From 1841ba44bb19cf992900bd53fa73d5e59d9459c0 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 18:05:04 +0530 Subject: [PATCH 01/19] remove primitives --- package-lock.json | 25191 ++++++++-------- package.json | 22 - packages/ai/.gitignore | 1 - packages/ai/CHANGELOG.md | 93 - packages/ai/package.json | 77 - packages/ai/src/bootstrap/main.ts | 160 - packages/ai/src/main.test.ts | 470 - packages/ai/src/main.ts | 1 - packages/ai/tsconfig.json | 20 - packages/ai/tsup.config.ts | 11 - packages/ai/vitest.config.ts | 11 - packages/aws-lambda-compat/.gitignore | 2 - packages/aws-lambda-compat/CHANGELOG.md | 27 - packages/aws-lambda-compat/README.md | 60 - packages/aws-lambda-compat/package.json | 64 - packages/aws-lambda-compat/src/lib/handler.ts | 14 - .../src/lib/handler_context.ts | 24 - .../src/lib/handler_event.ts | 21 - .../src/lib/handler_response.ts | 7 - .../src/lib/request_to_event.ts | 115 - .../src/lib/response_from_handler.ts | 41 - packages/aws-lambda-compat/src/main.test.ts | 246 - packages/aws-lambda-compat/src/main.ts | 25 - packages/aws-lambda-compat/tsconfig.json | 18 - packages/aws-lambda-compat/tsup.config.ts | 15 - packages/blobs/.gitattributes | 1 - packages/blobs/.gitignore | 12 - packages/blobs/CHANGELOG.md | 856 - packages/blobs/CODE_OF_CONDUCT.md | 60 - packages/blobs/CONTRIBUTING.md | 44 - packages/blobs/LICENSE | 22 - packages/blobs/README.md | 448 - packages/blobs/netlify.toml | 13 - packages/blobs/package.json | 87 - packages/blobs/server.d.ts | 1 - packages/blobs/src/backend/delete_store.ts | 4 - packages/blobs/src/backend/list.ts | 12 - packages/blobs/src/backend/list_stores.ts | 4 - packages/blobs/src/client.ts | 261 - packages/blobs/src/consistency.test.ts | 268 - packages/blobs/src/consistency.ts | 11 - packages/blobs/src/environment.ts | 57 - packages/blobs/src/headers.ts | 2 - packages/blobs/src/lambda_compat.test.ts | 77 - packages/blobs/src/lambda_compat.ts | 22 - packages/blobs/src/list.test.ts | 812 - packages/blobs/src/main.test.ts | 2421 -- packages/blobs/src/main.ts | 15 - packages/blobs/src/metadata.ts | 53 - packages/blobs/src/region.ts | 23 - packages/blobs/src/retry.ts | 52 - packages/blobs/src/server.test.ts | 606 - packages/blobs/src/server.ts | 648 - packages/blobs/src/store.ts | 685 - packages/blobs/src/store_factory.ts | 107 - packages/blobs/src/store_list.test.ts | 310 - packages/blobs/src/store_list.ts | 82 - packages/blobs/src/types.ts | 16 - packages/blobs/src/util.test.ts | 44 - packages/blobs/src/util.ts | 77 - packages/blobs/test/util.ts | 19 - packages/blobs/tsconfig.json | 20 - packages/blobs/tsup.config.ts | 16 - packages/blobs/vitest.config.ts | 11 - packages/cache/.gitattributes | 1 - packages/cache/.gitignore | 12 - packages/cache/CHANGELOG.md | 618 - packages/cache/CODE_OF_CONDUCT.md | 60 - packages/cache/CONTRIBUTING.md | 44 - packages/cache/LICENSE | 22 - packages/cache/README.md | 14 - packages/cache/netlify.toml | 13 - packages/cache/package.json | 84 - packages/cache/src/bootstrap/cache.test.ts | 313 - packages/cache/src/bootstrap/cache.ts | 232 - packages/cache/src/bootstrap/cachestorage.ts | 53 - packages/cache/src/bootstrap/environment.ts | 21 - packages/cache/src/bootstrap/errors.ts | 18 - packages/cache/src/bootstrap/main.ts | 3 - .../src/cache-headers/cache-headers.test.ts | 178 - .../cache/src/cache-headers/cache-headers.ts | 118 - packages/cache/src/cache-headers/options.ts | 84 - .../cache/src/cache-headers/validation.ts | 33 - .../src/cache-status/cache-status.test.ts | 205 - .../cache/src/cache-status/cache-status.ts | 167 - packages/cache/src/constants.test.ts | 11 - packages/cache/src/constants.ts | 24 - packages/cache/src/fetchwithcache.test.ts | 520 - packages/cache/src/fetchwithcache.ts | 196 - packages/cache/src/headers.ts | 11 - packages/cache/src/main.test.ts | 36 - packages/cache/src/main.ts | 5 - packages/cache/src/polyfill.ts | 68 - packages/cache/src/test/headers.ts | 18 - packages/cache/src/test/util.ts | 3 - packages/cache/tsconfig.json | 20 - packages/cache/tsup.config.ts | 17 - packages/cache/vitest.config.ts | 11 - packages/database/.gitignore | 2 - packages/database/dev/CHANGELOG.md | 72 - packages/database/dev/package.json | 60 - .../database/dev/src/lib/migrations.test.ts | 299 - packages/database/dev/src/lib/migrations.ts | 146 - .../database/dev/src/lib/notifications.ts | 72 - packages/database/dev/src/lib/sql-executor.ts | 6 - packages/database/dev/src/main.test.ts | 457 - packages/database/dev/src/main.ts | 222 - packages/database/dev/tsconfig.json | 18 - packages/database/dev/tsup.config.ts | 15 - packages/database/dev/vitest.config.ts | 14 - packages/database/prod/CHANGELOG.md | 66 - packages/database/prod/package.json | 71 - packages/database/prod/src/environment.ts | 9 - packages/database/prod/src/main.test.ts | 178 - packages/database/prod/src/main.ts | 91 - packages/database/prod/tsconfig.json | 18 - packages/database/prod/tsup.config.ts | 23 - packages/database/prod/vitest.config.ts | 14 - packages/database/proxy/CHANGELOG.md | 50 - packages/database/proxy/package.json | 58 - packages/database/proxy/src/lib/connection.ts | 180 - .../database/proxy/src/lib/pg-protocol.ts | 50 - packages/database/proxy/src/main.test.ts | 186 - packages/database/proxy/src/main.ts | 103 - packages/database/proxy/tsconfig.json | 18 - packages/database/proxy/tsup.config.ts | 15 - packages/database/proxy/vitest.config.ts | 14 - packages/dev-utils/.gitignore | 1 - packages/dev-utils/CHANGELOG.md | 262 - packages/dev-utils/package.json | 72 - packages/dev-utils/src/lib/api-token.ts | 9 - packages/dev-utils/src/lib/base64.test.ts | 9 - packages/dev-utils/src/lib/base64.ts | 34 - packages/dev-utils/src/lib/errors.ts | 21 - packages/dev-utils/src/lib/event.ts | 5 - .../src/lib/file-watcher/index.test.ts | 374 - .../dev-utils/src/lib/file-watcher/index.ts | 291 - .../dev-utils/src/lib/file-watcher/util.ts | 51 - .../dev-utils/src/lib/geo-location.test.ts | 181 - packages/dev-utils/src/lib/geo-location.ts | 85 - packages/dev-utils/src/lib/gitignore.ts | 45 - packages/dev-utils/src/lib/global-config.ts | 101 - packages/dev-utils/src/lib/handler.ts | 1 - packages/dev-utils/src/lib/headers.ts | 16 - packages/dev-utils/src/lib/local-state.ts | 125 - packages/dev-utils/src/lib/logger.ts | 17 - packages/dev-utils/src/lib/memoize.ts | 45 - packages/dev-utils/src/lib/paths.ts | 23 - packages/dev-utils/src/lib/process.ts | 39 - packages/dev-utils/src/lib/reactive.test.ts | 66 - packages/dev-utils/src/lib/reactive.ts | 45 - packages/dev-utils/src/lib/reqres.ts | 61 - packages/dev-utils/src/lib/watch-debounced.ts | 84 - packages/dev-utils/src/main.ts | 28 - .../dev-utils/src/server/http_server.test.ts | 25 - packages/dev-utils/src/server/http_server.ts | 62 - .../src/templates/function-error.html | 316 - .../dev-utils/src/test/event_inspector.ts | 45 - packages/dev-utils/src/test/fetch.ts | 154 - packages/dev-utils/src/test/fixture.ts | 142 - packages/dev-utils/src/test/image.ts | 55 - packages/dev-utils/src/test/logger.ts | 7 - packages/dev-utils/tsconfig.json | 16 - packages/dev-utils/tsup.config.ts | 17 - packages/dev/.gitignore | 1 - packages/dev/CHANGELOG.md | 1504 - packages/dev/README.md | 66 - packages/dev/package.json | 73 - packages/dev/src/lib/env.ts | 397 - packages/dev/src/lib/fs.ts | 25 - packages/dev/src/lib/reqres.ts | 68 - packages/dev/src/lib/request_id.ts | 3 - packages/dev/src/lib/runtime.ts | 81 - packages/dev/src/main.test.ts | 1109 - packages/dev/src/main.ts | 743 - packages/dev/test/mock-api.ts | 136 - packages/dev/tsconfig.json | 16 - packages/dev/tsup.config.ts | 18 - packages/dev/vitest.config.ts | 8 - packages/edge-functions/.gitignore | 2 - packages/edge-functions/dev/CHANGELOG.md | 207 - .../edge-functions/dev/bootstrap-bundle.mjs | 15 - packages/edge-functions/dev/package.json | 54 - .../edge-functions/dev/src/deno/config.mjs | 55 - .../edge-functions/dev/src/deno/errors.mjs | 28 - .../edge-functions/dev/src/deno/invoke.mjs | 109 - .../edge-functions/dev/src/deno/server.mjs | 73 - .../dev/src/deno/workers/config.mjs | 52 - .../dev/src/deno/workers/runner.mjs | 86 - .../dev/src/deno/workers/types.ts | 78 - .../edge-functions/dev/src/node/headers.ts | 24 - .../edge-functions/dev/src/node/main.test.ts | 338 - packages/edge-functions/dev/src/node/main.ts | 407 - .../edge-functions/dev/src/shared/types.ts | 10 - packages/edge-functions/dev/tsconfig.json | 18 - packages/edge-functions/dev/tsup.config.ts | 49 - packages/edge-functions/prod/CHANGELOG.md | 395 - packages/edge-functions/prod/package.json | 54 - .../edge-functions/prod/src/lib/config.ts | 72 - .../prod/src/lib/edge-function.ts | 6 - packages/edge-functions/prod/src/main.test.ts | 7 - packages/edge-functions/prod/src/main.ts | 11 - packages/edge-functions/prod/tsconfig.json | 16 - packages/edge-functions/prod/tsup.config.ts | 17 - packages/functions/.gitignore | 2 - packages/functions/dev/CHANGELOG.md | 340 - packages/functions/dev/package.json | 69 - packages/functions/dev/src/builder.ts | 23 - packages/functions/dev/src/events.ts | 36 - packages/functions/dev/src/function.ts | 446 - packages/functions/dev/src/main.test.ts | 302 - packages/functions/dev/src/main.ts | 151 - packages/functions/dev/src/registry.test.ts | 153 - packages/functions/dev/src/registry.ts | 524 - packages/functions/dev/src/runtimes/index.ts | 30 - .../dev/src/runtimes/nodejs/builder.ts | 225 - .../dev/src/runtimes/nodejs/config.ts | 42 - .../dev/src/runtimes/nodejs/index.ts | 117 - .../dev/src/runtimes/nodejs/lambda.ts | 70 - .../dev/src/runtimes/nodejs/worker.js | 106 - .../dev/src/server/client-context.ts | 44 - packages/functions/dev/tsconfig.json | 18 - packages/functions/dev/tsup.config.ts | 16 - packages/functions/dev/vitest.config.ts | 23 - packages/functions/prod/CHANGELOG.md | 902 - packages/functions/prod/CODE_OF_CONDUCT.md | 60 - packages/functions/prod/CONTRIBUTING.md | 48 - packages/functions/prod/LICENSE | 22 - packages/functions/prod/README.md | 104 - packages/functions/prod/functions.png | Bin 32204 -> 0 bytes packages/functions/prod/internal.d.ts | 1 - packages/functions/prod/package.json | 87 - .../functions/prod/src/function/handler.ts | 25 - .../prod/src/function/handler_context.ts | 24 - .../prod/src/function/handler_event.ts | 21 - .../prod/src/function/handler_response.ts | 16 - packages/functions/prod/src/function/index.ts | 36 - .../prod/src/function/netlify_function.ts | 45 - packages/functions/prod/src/function/v2.ts | 131 - .../functions/prod/src/global-types.test.ts | 13 - packages/functions/prod/src/internal.ts | 5 - .../functions/prod/src/lib/builder.test.ts | 184 - packages/functions/prod/src/lib/builder.ts | 47 - .../functions/prod/src/lib/consts.test.ts | 10 - packages/functions/prod/src/lib/consts.ts | 23 - .../functions/prod/src/lib/context_store.ts | 29 - .../prod/src/lib/get_context.test.ts | 30 - .../functions/prod/src/lib/get_context.ts | 15 - .../prod/src/lib/purge_cache.test.ts | 152 - .../functions/prod/src/lib/purge_cache.ts | 95 - packages/functions/prod/src/lib/schedule.ts | 20 - packages/functions/prod/src/lib/stream.ts | 68 - .../prod/src/lib/system_logger.test.ts | 59 - .../functions/prod/src/lib/system_logger.ts | 85 - packages/functions/prod/src/main.ts | 15 - packages/functions/prod/test/helpers/main.mjs | 18 - .../prod/test/helpers/mock_fetch.mjs | 73 - .../test/types/BackgroundHandler.test-d.ts | 10 - .../prod/test/types/Config.test-d.ts | 23 - .../prod/test/types/Handler.test-d.ts | 10 - .../prod/test/types/NetlifyFunction.test-d.ts | 57 - .../prod/test/types/Netlify_Global.test-d.ts | 5 - packages/functions/prod/tsconfig.json | 18 - packages/functions/prod/tsup.config.ts | 15 - packages/functions/prod/vitest.config.ts | 14 - packages/headers/.gitignore | 1 - packages/headers/CHANGELOG.md | 254 - packages/headers/package.json | 47 - .../headers/src/lib/headersForPath.test.ts | 84 - packages/headers/src/lib/headersForPath.ts | 10 - packages/headers/src/lib/parseHeaders.test.ts | 124 - packages/headers/src/lib/parseHeaders.ts | 35 - packages/headers/src/main.test.ts | 175 - packages/headers/src/main.ts | 67 - packages/headers/tsconfig.json | 16 - packages/headers/tsup.config.ts | 17 - packages/identity/.gitignore | 2 - packages/identity/prod/.gitignore | 12 - packages/identity/prod/CHANGELOG.md | 13 - packages/identity/prod/README.md | 1261 - packages/identity/prod/package.json | 72 - packages/identity/prod/src/account.ts | 165 - packages/identity/prod/src/admin.ts | 261 - packages/identity/prod/src/auth.ts | 486 - packages/identity/prod/src/config.ts | 46 - packages/identity/prod/src/cookies.ts | 70 - packages/identity/prod/src/csrf.ts | 69 - packages/identity/prod/src/environment.ts | 102 - packages/identity/prod/src/errors.ts | 54 - packages/identity/prod/src/events.ts | 89 - packages/identity/prod/src/fetch.ts | 35 - packages/identity/prod/src/globals.d.ts | 15 - packages/identity/prod/src/main.ts | 32 - packages/identity/prod/src/nextjs.ts | 49 - packages/identity/prod/src/refresh.ts | 194 - packages/identity/prod/src/types.ts | 167 - packages/identity/prod/src/user.ts | 274 - .../prod/test/account.browser.test.ts | 263 - .../identity/prod/test/admin.browser.test.ts | 72 - .../identity/prod/test/admin.server.test.ts | 448 - .../identity/prod/test/auth.browser.test.ts | 594 - .../identity/prod/test/auth.server.test.ts | 400 - .../identity/prod/test/config.browser.test.ts | 20 - packages/identity/prod/test/config.test.ts | 129 - packages/identity/prod/test/csrf.test.ts | 170 - packages/identity/prod/test/errors.test.ts | 25 - packages/identity/prod/test/fetch.test.ts | 108 - packages/identity/prod/test/fixtures.ts | 20 - packages/identity/prod/test/nextjs.test.ts | 96 - .../prod/test/refresh.browser.test.ts | 235 - .../identity/prod/test/refresh.server.test.ts | 244 - .../prod/test/stale-session.browser.test.ts | 76 - .../identity/prod/test/user.browser.test.ts | 111 - packages/identity/prod/test/user.test.ts | 311 - packages/identity/prod/tsconfig.json | 20 - packages/identity/prod/tsup.config.ts | 16 - packages/identity/prod/vitest.config.ts | 11 - packages/images/.gitignore | 1 - packages/images/CHANGELOG.md | 223 - packages/images/package.json | 46 - packages/images/src/main.test.ts | 369 - packages/images/src/main.ts | 133 - packages/images/tsconfig.json | 16 - packages/images/tsup.config.ts | 17 - packages/nuxt-module/.nuxtrc | 1 + packages/otel/.gitattributes | 1 - packages/otel/.gitignore | 12 - packages/otel/CHANGELOG.md | 251 - packages/otel/CODE_OF_CONDUCT.md | 60 - packages/otel/CONTRIBUTING.md | 44 - packages/otel/LICENSE | 22 - packages/otel/README.md | 14 - packages/otel/package.json | 141 - packages/otel/src/bootstrap/main.ts | 86 - packages/otel/src/constants.ts | 3 - packages/otel/src/exporters/netlify.test.ts | 133 - packages/otel/src/exporters/netlify.ts | 147 - .../otel/src/instrumentations/fetch.test.ts | 156 - packages/otel/src/instrumentations/fetch.ts | 255 - .../otel/src/instrumentations/http.test.ts | 174 - packages/otel/src/instrumentations/http.ts | 222 - packages/otel/src/main.test.ts | 39 - packages/otel/src/main.ts | 52 - packages/otel/src/opentelemetry.test.ts | 14 - packages/otel/src/opentelemetry.ts | 11 - packages/otel/tsconfig.json | 21 - packages/otel/tsup.config.ts | 24 - packages/otel/vitest.config.ts | 11 - packages/redirects/.gitignore | 1 - packages/redirects/CHANGELOG.md | 336 - packages/redirects/package.json | 50 - packages/redirects/src/lib/parser.ts | 64 - packages/redirects/src/lib/redirect.ts | 12 - packages/redirects/src/lib/rewriter.ts | 107 - packages/redirects/src/lib/signer.ts | 23 - packages/redirects/src/main.test.ts | 234 - packages/redirects/src/main.ts | 158 - packages/redirects/tsconfig.json | 17 - packages/redirects/tsup.config.ts | 17 - .../redirects/types/netlify-redirector.d.ts | 39 - packages/runtime-utils/.gitignore | 1 - packages/runtime-utils/CHANGELOG.md | 75 - packages/runtime-utils/package.json | 56 - packages/runtime-utils/src/lib/base64.ts | 9 - packages/runtime-utils/src/lib/environment.ts | 43 - packages/runtime-utils/src/main.test.ts | 9 - packages/runtime-utils/src/main.ts | 2 - packages/runtime-utils/tsconfig.json | 16 - packages/runtime-utils/tsup.config.ts | 20 - packages/runtime/.gitignore | 1 - packages/runtime/CHANGELOG.md | 608 - packages/runtime/package.json | 47 - packages/runtime/src/lib/environment/blobs.ts | 46 - .../runtime/src/lib/environment/branch.ts | 10 - packages/runtime/src/lib/environment/purge.ts | 10 - packages/runtime/src/lib/globals.ts | 39 - packages/runtime/src/lib/util.ts | 3 - packages/runtime/src/main.test.ts | 106 - packages/runtime/src/main.ts | 67 - packages/runtime/tsconfig.json | 16 - packages/runtime/tsup.config.ts | 17 - packages/static/.gitignore | 1 - packages/static/CHANGELOG.md | 307 - packages/static/package.json | 47 - packages/static/src/lib/fs.ts | 22 - packages/static/src/lib/paths.ts | 37 - packages/static/src/main.test.ts | 125 - packages/static/src/main.ts | 53 - packages/static/tsconfig.json | 16 - packages/static/tsup.config.ts | 17 - packages/types/.gitignore | 1 - packages/types/CHANGELOG.md | 110 - packages/types/README.md | 37 - packages/types/package.json | 41 - packages/types/src/lib/context/context.ts | 47 - packages/types/src/lib/context/cookies.ts | 39 - packages/types/src/lib/context/geo.ts | 15 - packages/types/src/lib/context/server.ts | 3 - packages/types/src/lib/context/site.ts | 5 - .../types/src/lib/environment-variables.ts | 7 - packages/types/src/lib/events/deploy.ts | 49 - packages/types/src/lib/events/identity.ts | 56 - packages/types/src/lib/events/index.ts | 31 - packages/types/src/lib/events/submission.ts | 5 - packages/types/src/lib/function-regions.ts | 13 - packages/types/src/lib/globals.ts | 7 - packages/types/src/main.test.ts | 25 - packages/types/src/main.ts | 37 - packages/types/tsconfig.json | 16 - packages/types/tsup.config.ts | 17 - packages/types/vitest.config.ts | 9 - .../vite-plugin-tanstack-start/tsconfig.json | 2 +- packages/vite-plugin/.gitignore | 3 + 413 files changed, 13058 insertions(+), 56255 deletions(-) delete mode 100644 packages/ai/.gitignore delete mode 100644 packages/ai/CHANGELOG.md delete mode 100644 packages/ai/package.json delete mode 100644 packages/ai/src/bootstrap/main.ts delete mode 100644 packages/ai/src/main.test.ts delete mode 100644 packages/ai/src/main.ts delete mode 100644 packages/ai/tsconfig.json delete mode 100644 packages/ai/tsup.config.ts delete mode 100644 packages/ai/vitest.config.ts delete mode 100644 packages/aws-lambda-compat/.gitignore delete mode 100644 packages/aws-lambda-compat/CHANGELOG.md delete mode 100644 packages/aws-lambda-compat/README.md delete mode 100644 packages/aws-lambda-compat/package.json delete mode 100644 packages/aws-lambda-compat/src/lib/handler.ts delete mode 100644 packages/aws-lambda-compat/src/lib/handler_context.ts delete mode 100644 packages/aws-lambda-compat/src/lib/handler_event.ts delete mode 100644 packages/aws-lambda-compat/src/lib/handler_response.ts delete mode 100644 packages/aws-lambda-compat/src/lib/request_to_event.ts delete mode 100644 packages/aws-lambda-compat/src/lib/response_from_handler.ts delete mode 100644 packages/aws-lambda-compat/src/main.test.ts delete mode 100644 packages/aws-lambda-compat/src/main.ts delete mode 100644 packages/aws-lambda-compat/tsconfig.json delete mode 100644 packages/aws-lambda-compat/tsup.config.ts delete mode 100644 packages/blobs/.gitattributes delete mode 100644 packages/blobs/.gitignore delete mode 100644 packages/blobs/CHANGELOG.md delete mode 100644 packages/blobs/CODE_OF_CONDUCT.md delete mode 100644 packages/blobs/CONTRIBUTING.md delete mode 100644 packages/blobs/LICENSE delete mode 100644 packages/blobs/README.md delete mode 100644 packages/blobs/netlify.toml delete mode 100644 packages/blobs/package.json delete mode 100644 packages/blobs/server.d.ts delete mode 100644 packages/blobs/src/backend/delete_store.ts delete mode 100644 packages/blobs/src/backend/list.ts delete mode 100644 packages/blobs/src/backend/list_stores.ts delete mode 100644 packages/blobs/src/client.ts delete mode 100644 packages/blobs/src/consistency.test.ts delete mode 100644 packages/blobs/src/consistency.ts delete mode 100644 packages/blobs/src/environment.ts delete mode 100644 packages/blobs/src/headers.ts delete mode 100644 packages/blobs/src/lambda_compat.test.ts delete mode 100644 packages/blobs/src/lambda_compat.ts delete mode 100644 packages/blobs/src/list.test.ts delete mode 100644 packages/blobs/src/main.test.ts delete mode 100644 packages/blobs/src/main.ts delete mode 100644 packages/blobs/src/metadata.ts delete mode 100644 packages/blobs/src/region.ts delete mode 100644 packages/blobs/src/retry.ts delete mode 100644 packages/blobs/src/server.test.ts delete mode 100644 packages/blobs/src/server.ts delete mode 100644 packages/blobs/src/store.ts delete mode 100644 packages/blobs/src/store_factory.ts delete mode 100644 packages/blobs/src/store_list.test.ts delete mode 100644 packages/blobs/src/store_list.ts delete mode 100644 packages/blobs/src/types.ts delete mode 100644 packages/blobs/src/util.test.ts delete mode 100644 packages/blobs/src/util.ts delete mode 100644 packages/blobs/test/util.ts delete mode 100644 packages/blobs/tsconfig.json delete mode 100644 packages/blobs/tsup.config.ts delete mode 100644 packages/blobs/vitest.config.ts delete mode 100644 packages/cache/.gitattributes delete mode 100644 packages/cache/.gitignore delete mode 100644 packages/cache/CHANGELOG.md delete mode 100644 packages/cache/CODE_OF_CONDUCT.md delete mode 100644 packages/cache/CONTRIBUTING.md delete mode 100644 packages/cache/LICENSE delete mode 100644 packages/cache/README.md delete mode 100644 packages/cache/netlify.toml delete mode 100644 packages/cache/package.json delete mode 100644 packages/cache/src/bootstrap/cache.test.ts delete mode 100644 packages/cache/src/bootstrap/cache.ts delete mode 100644 packages/cache/src/bootstrap/cachestorage.ts delete mode 100644 packages/cache/src/bootstrap/environment.ts delete mode 100644 packages/cache/src/bootstrap/errors.ts delete mode 100644 packages/cache/src/bootstrap/main.ts delete mode 100644 packages/cache/src/cache-headers/cache-headers.test.ts delete mode 100644 packages/cache/src/cache-headers/cache-headers.ts delete mode 100644 packages/cache/src/cache-headers/options.ts delete mode 100644 packages/cache/src/cache-headers/validation.ts delete mode 100644 packages/cache/src/cache-status/cache-status.test.ts delete mode 100644 packages/cache/src/cache-status/cache-status.ts delete mode 100644 packages/cache/src/constants.test.ts delete mode 100644 packages/cache/src/constants.ts delete mode 100644 packages/cache/src/fetchwithcache.test.ts delete mode 100644 packages/cache/src/fetchwithcache.ts delete mode 100644 packages/cache/src/headers.ts delete mode 100644 packages/cache/src/main.test.ts delete mode 100644 packages/cache/src/main.ts delete mode 100644 packages/cache/src/polyfill.ts delete mode 100644 packages/cache/src/test/headers.ts delete mode 100644 packages/cache/src/test/util.ts delete mode 100644 packages/cache/tsconfig.json delete mode 100644 packages/cache/tsup.config.ts delete mode 100644 packages/cache/vitest.config.ts delete mode 100644 packages/database/.gitignore delete mode 100644 packages/database/dev/CHANGELOG.md delete mode 100644 packages/database/dev/package.json delete mode 100644 packages/database/dev/src/lib/migrations.test.ts delete mode 100644 packages/database/dev/src/lib/migrations.ts delete mode 100644 packages/database/dev/src/lib/notifications.ts delete mode 100644 packages/database/dev/src/lib/sql-executor.ts delete mode 100644 packages/database/dev/src/main.test.ts delete mode 100644 packages/database/dev/src/main.ts delete mode 100644 packages/database/dev/tsconfig.json delete mode 100644 packages/database/dev/tsup.config.ts delete mode 100644 packages/database/dev/vitest.config.ts delete mode 100644 packages/database/prod/CHANGELOG.md delete mode 100644 packages/database/prod/package.json delete mode 100644 packages/database/prod/src/environment.ts delete mode 100644 packages/database/prod/src/main.test.ts delete mode 100644 packages/database/prod/src/main.ts delete mode 100644 packages/database/prod/tsconfig.json delete mode 100644 packages/database/prod/tsup.config.ts delete mode 100644 packages/database/prod/vitest.config.ts delete mode 100644 packages/database/proxy/CHANGELOG.md delete mode 100644 packages/database/proxy/package.json delete mode 100644 packages/database/proxy/src/lib/connection.ts delete mode 100644 packages/database/proxy/src/lib/pg-protocol.ts delete mode 100644 packages/database/proxy/src/main.test.ts delete mode 100644 packages/database/proxy/src/main.ts delete mode 100644 packages/database/proxy/tsconfig.json delete mode 100644 packages/database/proxy/tsup.config.ts delete mode 100644 packages/database/proxy/vitest.config.ts delete mode 100644 packages/dev-utils/.gitignore delete mode 100644 packages/dev-utils/CHANGELOG.md delete mode 100644 packages/dev-utils/package.json delete mode 100644 packages/dev-utils/src/lib/api-token.ts delete mode 100644 packages/dev-utils/src/lib/base64.test.ts delete mode 100644 packages/dev-utils/src/lib/base64.ts delete mode 100644 packages/dev-utils/src/lib/errors.ts delete mode 100644 packages/dev-utils/src/lib/event.ts delete mode 100644 packages/dev-utils/src/lib/file-watcher/index.test.ts delete mode 100644 packages/dev-utils/src/lib/file-watcher/index.ts delete mode 100644 packages/dev-utils/src/lib/file-watcher/util.ts delete mode 100644 packages/dev-utils/src/lib/geo-location.test.ts delete mode 100644 packages/dev-utils/src/lib/geo-location.ts delete mode 100644 packages/dev-utils/src/lib/gitignore.ts delete mode 100644 packages/dev-utils/src/lib/global-config.ts delete mode 100644 packages/dev-utils/src/lib/handler.ts delete mode 100644 packages/dev-utils/src/lib/headers.ts delete mode 100644 packages/dev-utils/src/lib/local-state.ts delete mode 100644 packages/dev-utils/src/lib/logger.ts delete mode 100644 packages/dev-utils/src/lib/memoize.ts delete mode 100644 packages/dev-utils/src/lib/paths.ts delete mode 100644 packages/dev-utils/src/lib/process.ts delete mode 100644 packages/dev-utils/src/lib/reactive.test.ts delete mode 100644 packages/dev-utils/src/lib/reactive.ts delete mode 100644 packages/dev-utils/src/lib/reqres.ts delete mode 100644 packages/dev-utils/src/lib/watch-debounced.ts delete mode 100644 packages/dev-utils/src/main.ts delete mode 100644 packages/dev-utils/src/server/http_server.test.ts delete mode 100644 packages/dev-utils/src/server/http_server.ts delete mode 100644 packages/dev-utils/src/templates/function-error.html delete mode 100644 packages/dev-utils/src/test/event_inspector.ts delete mode 100644 packages/dev-utils/src/test/fetch.ts delete mode 100644 packages/dev-utils/src/test/fixture.ts delete mode 100644 packages/dev-utils/src/test/image.ts delete mode 100644 packages/dev-utils/src/test/logger.ts delete mode 100644 packages/dev-utils/tsconfig.json delete mode 100644 packages/dev-utils/tsup.config.ts delete mode 100644 packages/dev/.gitignore delete mode 100644 packages/dev/CHANGELOG.md delete mode 100644 packages/dev/README.md delete mode 100644 packages/dev/package.json delete mode 100644 packages/dev/src/lib/env.ts delete mode 100644 packages/dev/src/lib/fs.ts delete mode 100644 packages/dev/src/lib/reqres.ts delete mode 100644 packages/dev/src/lib/request_id.ts delete mode 100644 packages/dev/src/lib/runtime.ts delete mode 100644 packages/dev/src/main.test.ts delete mode 100644 packages/dev/src/main.ts delete mode 100644 packages/dev/test/mock-api.ts delete mode 100644 packages/dev/tsconfig.json delete mode 100644 packages/dev/tsup.config.ts delete mode 100644 packages/dev/vitest.config.ts delete mode 100644 packages/edge-functions/.gitignore delete mode 100644 packages/edge-functions/dev/CHANGELOG.md delete mode 100644 packages/edge-functions/dev/bootstrap-bundle.mjs delete mode 100644 packages/edge-functions/dev/package.json delete mode 100644 packages/edge-functions/dev/src/deno/config.mjs delete mode 100644 packages/edge-functions/dev/src/deno/errors.mjs delete mode 100644 packages/edge-functions/dev/src/deno/invoke.mjs delete mode 100644 packages/edge-functions/dev/src/deno/server.mjs delete mode 100644 packages/edge-functions/dev/src/deno/workers/config.mjs delete mode 100644 packages/edge-functions/dev/src/deno/workers/runner.mjs delete mode 100644 packages/edge-functions/dev/src/deno/workers/types.ts delete mode 100644 packages/edge-functions/dev/src/node/headers.ts delete mode 100644 packages/edge-functions/dev/src/node/main.test.ts delete mode 100644 packages/edge-functions/dev/src/node/main.ts delete mode 100644 packages/edge-functions/dev/src/shared/types.ts delete mode 100644 packages/edge-functions/dev/tsconfig.json delete mode 100644 packages/edge-functions/dev/tsup.config.ts delete mode 100644 packages/edge-functions/prod/CHANGELOG.md delete mode 100644 packages/edge-functions/prod/package.json delete mode 100644 packages/edge-functions/prod/src/lib/config.ts delete mode 100644 packages/edge-functions/prod/src/lib/edge-function.ts delete mode 100644 packages/edge-functions/prod/src/main.test.ts delete mode 100644 packages/edge-functions/prod/src/main.ts delete mode 100644 packages/edge-functions/prod/tsconfig.json delete mode 100644 packages/edge-functions/prod/tsup.config.ts delete mode 100644 packages/functions/.gitignore delete mode 100644 packages/functions/dev/CHANGELOG.md delete mode 100644 packages/functions/dev/package.json delete mode 100644 packages/functions/dev/src/builder.ts delete mode 100644 packages/functions/dev/src/events.ts delete mode 100644 packages/functions/dev/src/function.ts delete mode 100644 packages/functions/dev/src/main.test.ts delete mode 100644 packages/functions/dev/src/main.ts delete mode 100644 packages/functions/dev/src/registry.test.ts delete mode 100644 packages/functions/dev/src/registry.ts delete mode 100644 packages/functions/dev/src/runtimes/index.ts delete mode 100644 packages/functions/dev/src/runtimes/nodejs/builder.ts delete mode 100644 packages/functions/dev/src/runtimes/nodejs/config.ts delete mode 100644 packages/functions/dev/src/runtimes/nodejs/index.ts delete mode 100644 packages/functions/dev/src/runtimes/nodejs/lambda.ts delete mode 100644 packages/functions/dev/src/runtimes/nodejs/worker.js delete mode 100644 packages/functions/dev/src/server/client-context.ts delete mode 100644 packages/functions/dev/tsconfig.json delete mode 100644 packages/functions/dev/tsup.config.ts delete mode 100644 packages/functions/dev/vitest.config.ts delete mode 100644 packages/functions/prod/CHANGELOG.md delete mode 100644 packages/functions/prod/CODE_OF_CONDUCT.md delete mode 100644 packages/functions/prod/CONTRIBUTING.md delete mode 100644 packages/functions/prod/LICENSE delete mode 100644 packages/functions/prod/README.md delete mode 100644 packages/functions/prod/functions.png delete mode 100644 packages/functions/prod/internal.d.ts delete mode 100644 packages/functions/prod/package.json delete mode 100644 packages/functions/prod/src/function/handler.ts delete mode 100644 packages/functions/prod/src/function/handler_context.ts delete mode 100644 packages/functions/prod/src/function/handler_event.ts delete mode 100644 packages/functions/prod/src/function/handler_response.ts delete mode 100644 packages/functions/prod/src/function/index.ts delete mode 100644 packages/functions/prod/src/function/netlify_function.ts delete mode 100644 packages/functions/prod/src/function/v2.ts delete mode 100644 packages/functions/prod/src/global-types.test.ts delete mode 100644 packages/functions/prod/src/internal.ts delete mode 100644 packages/functions/prod/src/lib/builder.test.ts delete mode 100644 packages/functions/prod/src/lib/builder.ts delete mode 100644 packages/functions/prod/src/lib/consts.test.ts delete mode 100644 packages/functions/prod/src/lib/consts.ts delete mode 100644 packages/functions/prod/src/lib/context_store.ts delete mode 100644 packages/functions/prod/src/lib/get_context.test.ts delete mode 100644 packages/functions/prod/src/lib/get_context.ts delete mode 100644 packages/functions/prod/src/lib/purge_cache.test.ts delete mode 100644 packages/functions/prod/src/lib/purge_cache.ts delete mode 100644 packages/functions/prod/src/lib/schedule.ts delete mode 100644 packages/functions/prod/src/lib/stream.ts delete mode 100644 packages/functions/prod/src/lib/system_logger.test.ts delete mode 100644 packages/functions/prod/src/lib/system_logger.ts delete mode 100644 packages/functions/prod/src/main.ts delete mode 100644 packages/functions/prod/test/helpers/main.mjs delete mode 100644 packages/functions/prod/test/helpers/mock_fetch.mjs delete mode 100644 packages/functions/prod/test/types/BackgroundHandler.test-d.ts delete mode 100644 packages/functions/prod/test/types/Config.test-d.ts delete mode 100644 packages/functions/prod/test/types/Handler.test-d.ts delete mode 100644 packages/functions/prod/test/types/NetlifyFunction.test-d.ts delete mode 100644 packages/functions/prod/test/types/Netlify_Global.test-d.ts delete mode 100644 packages/functions/prod/tsconfig.json delete mode 100644 packages/functions/prod/tsup.config.ts delete mode 100644 packages/functions/prod/vitest.config.ts delete mode 100644 packages/headers/.gitignore delete mode 100644 packages/headers/CHANGELOG.md delete mode 100644 packages/headers/package.json delete mode 100644 packages/headers/src/lib/headersForPath.test.ts delete mode 100644 packages/headers/src/lib/headersForPath.ts delete mode 100644 packages/headers/src/lib/parseHeaders.test.ts delete mode 100644 packages/headers/src/lib/parseHeaders.ts delete mode 100644 packages/headers/src/main.test.ts delete mode 100644 packages/headers/src/main.ts delete mode 100644 packages/headers/tsconfig.json delete mode 100644 packages/headers/tsup.config.ts delete mode 100644 packages/identity/.gitignore delete mode 100644 packages/identity/prod/.gitignore delete mode 100644 packages/identity/prod/CHANGELOG.md delete mode 100644 packages/identity/prod/README.md delete mode 100644 packages/identity/prod/package.json delete mode 100644 packages/identity/prod/src/account.ts delete mode 100644 packages/identity/prod/src/admin.ts delete mode 100644 packages/identity/prod/src/auth.ts delete mode 100644 packages/identity/prod/src/config.ts delete mode 100644 packages/identity/prod/src/cookies.ts delete mode 100644 packages/identity/prod/src/csrf.ts delete mode 100644 packages/identity/prod/src/environment.ts delete mode 100644 packages/identity/prod/src/errors.ts delete mode 100644 packages/identity/prod/src/events.ts delete mode 100644 packages/identity/prod/src/fetch.ts delete mode 100644 packages/identity/prod/src/globals.d.ts delete mode 100644 packages/identity/prod/src/main.ts delete mode 100644 packages/identity/prod/src/nextjs.ts delete mode 100644 packages/identity/prod/src/refresh.ts delete mode 100644 packages/identity/prod/src/types.ts delete mode 100644 packages/identity/prod/src/user.ts delete mode 100644 packages/identity/prod/test/account.browser.test.ts delete mode 100644 packages/identity/prod/test/admin.browser.test.ts delete mode 100644 packages/identity/prod/test/admin.server.test.ts delete mode 100644 packages/identity/prod/test/auth.browser.test.ts delete mode 100644 packages/identity/prod/test/auth.server.test.ts delete mode 100644 packages/identity/prod/test/config.browser.test.ts delete mode 100644 packages/identity/prod/test/config.test.ts delete mode 100644 packages/identity/prod/test/csrf.test.ts delete mode 100644 packages/identity/prod/test/errors.test.ts delete mode 100644 packages/identity/prod/test/fetch.test.ts delete mode 100644 packages/identity/prod/test/fixtures.ts delete mode 100644 packages/identity/prod/test/nextjs.test.ts delete mode 100644 packages/identity/prod/test/refresh.browser.test.ts delete mode 100644 packages/identity/prod/test/refresh.server.test.ts delete mode 100644 packages/identity/prod/test/stale-session.browser.test.ts delete mode 100644 packages/identity/prod/test/user.browser.test.ts delete mode 100644 packages/identity/prod/test/user.test.ts delete mode 100644 packages/identity/prod/tsconfig.json delete mode 100644 packages/identity/prod/tsup.config.ts delete mode 100644 packages/identity/prod/vitest.config.ts delete mode 100644 packages/images/.gitignore delete mode 100644 packages/images/CHANGELOG.md delete mode 100644 packages/images/package.json delete mode 100644 packages/images/src/main.test.ts delete mode 100644 packages/images/src/main.ts delete mode 100644 packages/images/tsconfig.json delete mode 100644 packages/images/tsup.config.ts create mode 100644 packages/nuxt-module/.nuxtrc delete mode 100644 packages/otel/.gitattributes delete mode 100644 packages/otel/.gitignore delete mode 100644 packages/otel/CHANGELOG.md delete mode 100644 packages/otel/CODE_OF_CONDUCT.md delete mode 100644 packages/otel/CONTRIBUTING.md delete mode 100644 packages/otel/LICENSE delete mode 100644 packages/otel/README.md delete mode 100644 packages/otel/package.json delete mode 100644 packages/otel/src/bootstrap/main.ts delete mode 100644 packages/otel/src/constants.ts delete mode 100644 packages/otel/src/exporters/netlify.test.ts delete mode 100644 packages/otel/src/exporters/netlify.ts delete mode 100644 packages/otel/src/instrumentations/fetch.test.ts delete mode 100644 packages/otel/src/instrumentations/fetch.ts delete mode 100644 packages/otel/src/instrumentations/http.test.ts delete mode 100644 packages/otel/src/instrumentations/http.ts delete mode 100644 packages/otel/src/main.test.ts delete mode 100644 packages/otel/src/main.ts delete mode 100644 packages/otel/src/opentelemetry.test.ts delete mode 100644 packages/otel/src/opentelemetry.ts delete mode 100644 packages/otel/tsconfig.json delete mode 100644 packages/otel/tsup.config.ts delete mode 100644 packages/otel/vitest.config.ts delete mode 100644 packages/redirects/.gitignore delete mode 100644 packages/redirects/CHANGELOG.md delete mode 100644 packages/redirects/package.json delete mode 100644 packages/redirects/src/lib/parser.ts delete mode 100644 packages/redirects/src/lib/redirect.ts delete mode 100644 packages/redirects/src/lib/rewriter.ts delete mode 100644 packages/redirects/src/lib/signer.ts delete mode 100644 packages/redirects/src/main.test.ts delete mode 100644 packages/redirects/src/main.ts delete mode 100644 packages/redirects/tsconfig.json delete mode 100644 packages/redirects/tsup.config.ts delete mode 100644 packages/redirects/types/netlify-redirector.d.ts delete mode 100644 packages/runtime-utils/.gitignore delete mode 100644 packages/runtime-utils/CHANGELOG.md delete mode 100644 packages/runtime-utils/package.json delete mode 100644 packages/runtime-utils/src/lib/base64.ts delete mode 100644 packages/runtime-utils/src/lib/environment.ts delete mode 100644 packages/runtime-utils/src/main.test.ts delete mode 100644 packages/runtime-utils/src/main.ts delete mode 100644 packages/runtime-utils/tsconfig.json delete mode 100644 packages/runtime-utils/tsup.config.ts delete mode 100644 packages/runtime/.gitignore delete mode 100644 packages/runtime/CHANGELOG.md delete mode 100644 packages/runtime/package.json delete mode 100644 packages/runtime/src/lib/environment/blobs.ts delete mode 100644 packages/runtime/src/lib/environment/branch.ts delete mode 100644 packages/runtime/src/lib/environment/purge.ts delete mode 100644 packages/runtime/src/lib/globals.ts delete mode 100644 packages/runtime/src/lib/util.ts delete mode 100644 packages/runtime/src/main.test.ts delete mode 100644 packages/runtime/src/main.ts delete mode 100644 packages/runtime/tsconfig.json delete mode 100644 packages/runtime/tsup.config.ts delete mode 100644 packages/static/.gitignore delete mode 100644 packages/static/CHANGELOG.md delete mode 100644 packages/static/package.json delete mode 100644 packages/static/src/lib/fs.ts delete mode 100644 packages/static/src/lib/paths.ts delete mode 100644 packages/static/src/main.test.ts delete mode 100644 packages/static/src/main.ts delete mode 100644 packages/static/tsconfig.json delete mode 100644 packages/static/tsup.config.ts delete mode 100644 packages/types/.gitignore delete mode 100644 packages/types/CHANGELOG.md delete mode 100644 packages/types/README.md delete mode 100644 packages/types/package.json delete mode 100644 packages/types/src/lib/context/context.ts delete mode 100644 packages/types/src/lib/context/cookies.ts delete mode 100644 packages/types/src/lib/context/geo.ts delete mode 100644 packages/types/src/lib/context/server.ts delete mode 100644 packages/types/src/lib/context/site.ts delete mode 100644 packages/types/src/lib/environment-variables.ts delete mode 100644 packages/types/src/lib/events/deploy.ts delete mode 100644 packages/types/src/lib/events/identity.ts delete mode 100644 packages/types/src/lib/events/index.ts delete mode 100644 packages/types/src/lib/events/submission.ts delete mode 100644 packages/types/src/lib/function-regions.ts delete mode 100644 packages/types/src/lib/globals.ts delete mode 100644 packages/types/src/main.test.ts delete mode 100644 packages/types/src/main.ts delete mode 100644 packages/types/tsconfig.json delete mode 100644 packages/types/tsup.config.ts delete mode 100644 packages/types/vitest.config.ts diff --git a/package-lock.json b/package-lock.json index fc73a11..3c2505d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,29 +9,7 @@ "version": "0.0.0", "license": "MIT", "workspaces": [ - "packages/types", - "packages/dev-utils", - "packages/runtime-utils", - "packages/otel", - "packages/blobs", - "packages/cache", - "packages/database/dev", - "packages/database/proxy", - "packages/database/prod", - "packages/edge-functions/prod", - "packages/edge-functions/dev", - "packages/functions/prod", - "packages/functions/dev", - "packages/headers", - "packages/images", - "packages/redirects", - "packages/runtime", - "packages/static", - "packages/ai", - "packages/dev", "packages/nuxt-module", - "packages/aws-lambda-compat", - "packages/identity/prod", "packages/vite-plugin", "packages/vite-plugin-tanstack-start" ], @@ -48,13 +26,6 @@ "typescript-eslint": "^8.33.0" } }, - "node_modules/@acemir/cssom": { - "version": "0.9.31", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", - "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", - "dev": true, - "license": "MIT" - }, "node_modules/@antfu/install-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", @@ -69,67 +40,13 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@antfu/install-pkg/node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - } - }, - "node_modules/@asamuzakjp/dom-selector": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", - "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/nwsapi": "^2.3.9", - "bidi-js": "^1.0.3", - "css-tree": "^3.1.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.6" - } - }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@asamuzakjp/nwsapi": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", - "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -138,9 +55,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -148,21 +65,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -189,14 +106,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -206,27 +123,27 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -235,16 +152,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -255,26 +162,19 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", - "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", "semver": "^6.3.1" }, "engines": { @@ -295,9 +195,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -305,43 +205,43 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -351,22 +251,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -374,15 +274,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -392,41 +292,41 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -434,26 +334,26 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -463,13 +363,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -479,13 +379,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -495,17 +395,17 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", - "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -515,33 +415,33 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -549,109 +449,90 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@bramus/specificity": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", - "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "node_modules/@bomb.sh/tab": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@bomb.sh/tab/-/tab-0.0.15.tgz", + "integrity": "sha512-Y90ub44TAvbdO9P8mcD/XPyQjFhiR5xmd4Fk7JErmWmEWEUimNnjWiBrVZ16Tj3GA1rLZ+uvCN2V/pzLawv31g==", "dev": true, "license": "MIT", - "dependencies": { - "css-tree": "^3.0.0" - }, "bin": { - "specificity": "bin/cli.js" - } - }, - "node_modules/@bundled-es-modules/cookie": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", - "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cookie": "^0.7.2" - } - }, - "node_modules/@bundled-es-modules/cookie/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@bundled-es-modules/statuses": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", - "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "statuses": "^2.0.1" + "tab": "dist/bin/cli.mjs" + }, + "peerDependencies": { + "cac": "^6.7.14", + "citty": "^0.1.6 || ^0.2.0", + "commander": "^13.1.0" + }, + "peerDependenciesMeta": { + "cac": { + "optional": true + }, + "citty": { + "optional": true + }, + "commander": { + "optional": true + } } }, "node_modules/@clack/core": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", - "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.1.tgz", + "integrity": "sha512-FILJa1gGKEFTGZAJE9RpVhrjKz3c3h4ar60dSv6cGuDqufQ84YEIS3GAGvZiN+H6yaLbbvTFNejjCC4tXpZEuw==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^1.0.0", + "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" } }, "node_modules/@clack/prompts": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", - "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.5.1.tgz", + "integrity": "sha512-zccHj2z2oCCO4yrDiRSlFOxWerGqRiysP7a5jPK6uoI9URKAquwY42Dd/iUP8JWHxEzdRe4TlbvZCo8z1/mhrw==", "dev": true, "license": "MIT", "dependencies": { - "@clack/core": "0.5.0", - "picocolors": "^1.0.0", + "@clack/core": "1.4.1", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz", - "integrity": "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", + "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", "dev": true, "license": "MIT OR Apache-2.0", - "dependencies": { - "mime": "^3.0.0" - }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@cloudflare/kv-asset-handler/node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "node_modules/@colordx/core": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@colordx/core/-/core-5.4.3.tgz", + "integrity": "sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ==", "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } + "license": "MIT" }, "node_modules/@colors/colors": { "version": "1.6.0", @@ -662,202 +543,111 @@ "node": ">=0.1.90" } }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@dabh/diagnostics": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", + "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "dependencies": { + "@so-ric/colorspace": "^1.1.6", + "enabled": "2.0.x", + "kuler": "^2.0.0" } }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@dependents/detective-less": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@dependents/detective-less/-/detective-less-5.0.3.tgz", + "integrity": "sha512-v6oD9Ukp+N7V4n6p5I/+mM5fIohSfkrDSGlFm5w/pYmchvbk+sMIHsLxrFJ5Lnujewj1BzWL0K84d88lwZAMQA==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "gonzales-pe": "^4.3.0", + "node-source-walk": "^7.0.1" }, "engines": { "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "node_modules/@dxup/nuxt": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@dxup/nuxt/-/nuxt-0.4.1.tgz", + "integrity": "sha512-gtYffW6OfWNvoLW+XD3Mx/K8uUq08PMGLYJoDxc92EzZAWqR0FhcR5iaLm5r/OxyGTKz+P5f5Y7Aoir9+SjYaw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" + "dependencies": { + "@dxup/unimport": "^0.1.2", + "@nuxt/kit": "^4.4.2", + "chokidar": "^5.0.0", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.16" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.2.tgz", - "integrity": "sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "peerDependencies": { - "css-tree": "^3.2.1" + "typescript": "*" }, "peerDependenciesMeta": { - "css-tree": { + "typescript": { "optional": true } } }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "node_modules/@dxup/nuxt/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", "license": "MIT", "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@dependents/detective-less": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@dependents/detective-less/-/detective-less-5.0.1.tgz", - "integrity": "sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ==", + "node_modules/@dxup/nuxt/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, "license": "MIT", - "dependencies": { - "gonzales-pe": "^4.3.0", - "node-source-walk": "^7.0.1" - }, "engines": { - "node": ">=18" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, + "node_modules/@dxup/unimport": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@dxup/unimport/-/unimport-0.1.2.tgz", + "integrity": "sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@electric-sql/pglite": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz", - "integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==", + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.16.tgz", + "integrity": "sha512-mZkZfOd9OqTMHsK+1cje8OSzfAQcpD7JmILXTl5ahdempjUDdmg4euf1biDex5/LfQIDJ3gvCu6qDgdnDxfJmA==", "license": "Apache-2.0" }, "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, "dependencies": { @@ -865,9 +655,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -889,486 +679,454 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.56.0.tgz", - "integrity": "sha512-c6EW+aA1w2rjqOMjbL93nZlwxp6c1Ln06vTYs5FjRRhmJXK8V/OrSXdT+pUr4aRYgjCgu8/OkiZr0tzeVrRSbw==", + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz", + "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", - "@typescript-eslint/types": "^8.42.0", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~5.1.0" + "@typescript-eslint/types": "^8.58.0", + "comment-parser": "1.4.6", + "esquery": "^1.7.0", + "jsdoc-type-pratt-parser": "~7.2.0" }, "engines": { - "node": ">=20.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@es-joy/jsdoccomment/node_modules/comment-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", + "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/@es-joy/resolve.exports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", + "integrity": "sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", - "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", - "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", - "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", - "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", - "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", - "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", - "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", - "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", - "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", - "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", - "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", - "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", - "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", - "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", - "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", - "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", - "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", - "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", - "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", - "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", - "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", - "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", - "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", - "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1392,10 +1150,23 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -1403,11 +1174,14 @@ } }, "node_modules/@eslint/compat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.3.2.tgz", - "integrity": "sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.1.tgz", + "integrity": "sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1421,24 +1195,31 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1447,9 +1228,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1460,19 +1241,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1483,20 +1267,20 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -1506,10 +1290,34 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1517,10 +1325,40 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1531,9 +1369,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { @@ -1544,9 +1382,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1554,37 +1392,19 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.2", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@exodus/bytes": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", - "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@noble/hashes": "^1.8.0 || ^2.0.0" - }, - "peerDependenciesMeta": { - "@noble/hashes": { - "optional": true - } - } - }, "node_modules/@fastify/accept-negotiator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-2.0.1.tgz", @@ -1608,29 +1428,43 @@ "license": "MIT" }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1674,10 +1508,19 @@ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", "license": "ISC" }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", - "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], @@ -1693,13 +1536,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", - "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", "cpu": [ "x64" ], @@ -1715,13 +1558,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", - "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], @@ -1735,9 +1578,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", - "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", "cpu": [ "x64" ], @@ -1751,12 +1594,15 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", - "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1767,12 +1613,15 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", - "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1783,12 +1632,34 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", - "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1799,12 +1670,15 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", - "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1815,12 +1689,15 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", - "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1831,12 +1708,15 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", - "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1847,12 +1727,15 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", - "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1863,12 +1746,15 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", - "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1881,16 +1767,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0" + "@img/sharp-libvips-linux-arm": "1.2.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", - "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1903,16 +1792,44 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0" + "@img/sharp-libvips-linux-arm64": "1.2.4" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", - "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1925,16 +1842,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0" + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", - "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1947,16 +1867,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0" + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", - "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1969,16 +1892,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0" + "@img/sharp-libvips-linux-x64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", - "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1991,16 +1917,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", - "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2013,20 +1942,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", - "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", "cpu": [ "wasm32" ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.4.4" + "@emnapi/runtime": "^1.7.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -2036,9 +1965,9 @@ } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", - "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", "cpu": [ "arm64" ], @@ -2055,9 +1984,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", - "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", "cpu": [ "ia32" ], @@ -2074,9 +2003,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", - "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], @@ -2098,201 +2027,50 @@ "integrity": "sha512-RwzRTpmrrS6Q1ZhQExwuxJGK1Wqhv4stt+OF2JzS+uawewpwNyU7EJL1WpBex7aDiiGLs4FsXGkfUBdYuX7xiQ==", "license": "MIT" }, - "node_modules/@inquirer/confirm": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz", - "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==", - "dev": true, - "license": "MIT", + "node_modules/@ioredis/commands": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.10.0.tgz", + "integrity": "sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=12" } }, - "node_modules/@inquirer/core": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", - "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", - "dev": true, - "license": "MIT", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", "dependencies": { - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "minipass": "^7.0.4" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18.0.0" } }, - "node_modules/@inquirer/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@inquirer/core/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@ioredis/commands": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.1.tgz", - "integrity": "sha512-bYtU8avhGIcje3IhvF9aSjsa5URMZBHnwKtOvXsT4sfYy9gppW11gLPT/9oNqlJZD47yPKveQFTAFWpHjKvUoQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/remapping": { @@ -2359,9 +2137,9 @@ "license": "MIT" }, "node_modules/@mapbox/node-pre-gyp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.0.tgz", - "integrity": "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz", + "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==", "license": "BSD-3-Clause", "dependencies": { "consola": "^3.2.3", @@ -2379,61 +2157,63 @@ "node": ">=18" } }, - "node_modules/@mswjs/interceptors": { - "version": "0.39.6", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.6.tgz", - "integrity": "sha512-bndDP83naYYkfayr/qhBHMhk0YGwS1iv6vaEGcr0SQbO0IZtbOPqjKjds/WcG+bJA+1T5vCx6kprKOzn5Bg+Vw==", - "dev": true, + "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" + "whatwg-url": "^5.0.0" }, "engines": { - "node": ">=18" + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@neondatabase/serverless": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-1.1.0.tgz", - "integrity": "sha512-r3ZZhRjEcfEdKIZnoB1RusNgvHuaBRqfCzV4Gi+5A9yUX0S4HTws/ASWqt13wL4y4I+0rqsWGdA2w7EQXHi3+Q==", - "license": "MIT", + "node_modules/@netlify/ai": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@netlify/ai/-/ai-0.4.1.tgz", + "integrity": "sha512-ETLtV/9taYrcGhszwO+BLFgFJJ2MCnJp8BwxfwV6Z/+z3SsaUG4ExC8x4xzNCdB2GPWxXrXkvR2LFNsPFSLcRA==", + "dependencies": { + "@netlify/api": "^14.0.18" + }, "engines": { - "node": ">=19.0.0" + "node": ">=20.6.1" } }, - "node_modules/@netlify/ai": { - "resolved": "packages/ai", - "link": true - }, "node_modules/@netlify/api": { - "version": "14.0.18", - "resolved": "https://registry.npmjs.org/@netlify/api/-/api-14.0.18.tgz", - "integrity": "sha512-4STtNybPXALobjTHEIU48Huv9Si1sNxgHbtYslNBPvQu9/aTpxhRHDZuUOkE/QuhHSbaCNCWJSYFGIRxpCdXxg==", + "version": "14.0.19", + "resolved": "https://registry.npmjs.org/@netlify/api/-/api-14.0.19.tgz", + "integrity": "sha512-oJ+7K+ioZ8sNoNzJbx+uIDmRynf5A+0ler2t9nHhhfwrrhx7mWgFaX5vGiEjvkpIxBAwfW8XyedhEdsm2OCK+w==", "license": "MIT", "dependencies": { - "@netlify/open-api": "^2.51.0", + "@netlify/open-api": "^2.52.0", "node-fetch": "^3.0.0", "p-wait-for": "^5.0.0", "picoquery": "^2.5.0" @@ -2442,28 +2222,6 @@ "node": ">=18.14.0" } }, - "node_modules/@netlify/api/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/@netlify/aws-lambda-compat": { - "resolved": "packages/aws-lambda-compat", - "link": true - }, "node_modules/@netlify/binary-info": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@netlify/binary-info/-/binary-info-1.0.0.tgz", @@ -2471,21 +2229,39 @@ "license": "Apache 2" }, "node_modules/@netlify/blobs": { - "resolved": "packages/blobs", - "link": true + "version": "10.7.9", + "resolved": "https://registry.npmjs.org/@netlify/blobs/-/blobs-10.7.9.tgz", + "integrity": "sha512-NEM8aNAMZCCWBWymomMM/fn5wmPGyGE8pendgsSu5mL7UNz+aXqGcHS0MiHWU/osyg+geiZuS+Rx956SVrMM/w==", + "license": "MIT", + "dependencies": { + "@netlify/dev-utils": "4.4.6", + "@netlify/otel": "^6.0.3", + "@netlify/runtime-utils": "2.3.0" + }, + "engines": { + "node": "^14.16.0 || >=16.0.0" + } }, "node_modules/@netlify/cache": { - "resolved": "packages/cache", - "link": true + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/@netlify/cache/-/cache-3.4.8.tgz", + "integrity": "sha512-20zPmLS8x2VXSNQHwxj1+jJgKAec/EoeKJahIgPmTolXq2X6nEdyulHTTHHA4KzxqGTkrzTcfNzZjEkjvRyj9Q==", + "license": "MIT", + "dependencies": { + "@netlify/runtime-utils": "2.3.0" + }, + "engines": { + "node": ">=20.6.1" + } }, "node_modules/@netlify/config": { - "version": "24.5.0", - "resolved": "https://registry.npmjs.org/@netlify/config/-/config-24.5.0.tgz", - "integrity": "sha512-d9M/H9ouQUlu6OnEYa9z4Sa+RZUn7OioS6bw6kKRtalllkQiSAtbgzjXz/2umgABsJGmxYXyjSOk7P8QcKluJg==", + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/@netlify/config/-/config-24.6.0.tgz", + "integrity": "sha512-bR2FhZiWFz+EIQBl/T9p9lRNBuInYqWtqtGQywwM1dkvNI2ViSQBmeEDY/qXh9EECB8g2f7ZBC2sF4KeNGtX0w==", "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.5", - "@netlify/api": "^14.0.18", + "@netlify/api": "^14.0.19", "@netlify/headers-parser": "^9.0.3", "@netlify/redirect-parser": "^15.0.4", "chalk": "^5.0.0", @@ -2517,116 +2293,72 @@ "node": ">=18.14.0" } }, - "node_modules/@netlify/config/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "node_modules/@netlify/database-dev": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@netlify/database-dev/-/database-dev-0.10.1.tgz", + "integrity": "sha512-kHLdS6r45TsDiS5aBrHUmzqPvoaWQEUZnaZeMwnIrLMwX8f2bIa6YAMOJJYJhyKm2drVo3C/T92/lJ5iGV/VBQ==", "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "dependencies": { + "@electric-sql/pglite": "^0.3.15", + "pg-gateway": "0.3.0-beta.4" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=20.6.1" } }, - "node_modules/@netlify/config/node_modules/find-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "node_modules/@netlify/dev": { + "version": "4.18.7", + "resolved": "https://registry.npmjs.org/@netlify/dev/-/dev-4.18.7.tgz", + "integrity": "sha512-BeXz9dis2Iid5EcOItVj2srdC30R4RwDhsk/N/h+T2WYrJbyhOj6b1IS+6fVGe5JbKe9fDiGANH1cujplX1+rw==", "license": "MIT", "dependencies": { - "locate-path": "^7.2.0", - "path-exists": "^5.0.0", - "unicorn-magic": "^0.1.0" + "@netlify/ai": "^0.4.1", + "@netlify/blobs": "10.7.9", + "@netlify/config": "^24.5.0", + "@netlify/database-dev": "0.10.1", + "@netlify/dev-utils": "4.4.6", + "@netlify/edge-functions-dev": "1.0.20", + "@netlify/functions-dev": "1.3.0", + "@netlify/headers": "2.1.11", + "@netlify/images": "1.3.10", + "@netlify/redirects": "3.1.13", + "@netlify/runtime": "4.1.25", + "@netlify/static": "3.1.10", + "ulid": "^3.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=20.6.1" } }, - "node_modules/@netlify/config/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "node_modules/@netlify/dev-utils": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@netlify/dev-utils/-/dev-utils-4.4.6.tgz", + "integrity": "sha512-P6X+xS3glvhiTX6AAocYvnZtqXtWhvxMX4AdPgv2iw6cXjGL2criUveX7bSjp6DiyHfvQpNdG0ZRpeBEVAFf1g==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "@whatwg-node/server": "^0.10.0", + "ansis": "^4.1.0", + "atomically": "^2.0.3", + "chokidar": "^4.0.1", + "decache": "^4.6.2", + "dettle": "^1.0.5", + "dot-prop": "9.0.0", + "empathic": "^2.0.0", + "env-paths": "^3.0.0", + "image-size": "^2.0.2", + "js-image-generator": "^1.0.4", + "parse-gitignore": "^2.0.0", + "semver": "^7.7.2", + "tmp-promise": "^3.0.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^18.14.0 || >=20" } }, - "node_modules/@netlify/config/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@netlify/config/node_modules/map-obj": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", - "integrity": "sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@netlify/config/node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@netlify/config/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@netlify/database": { - "resolved": "packages/database/prod", - "link": true - }, - "node_modules/@netlify/database-dev": { - "resolved": "packages/database/dev", - "link": true - }, - "node_modules/@netlify/database-proxy": { - "resolved": "packages/database/proxy", - "link": true - }, - "node_modules/@netlify/dev": { - "resolved": "packages/dev", - "link": true - }, - "node_modules/@netlify/dev-utils": { - "resolved": "packages/dev-utils", - "link": true - }, - "node_modules/@netlify/edge-bundler": { - "version": "14.10.1", - "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-14.10.1.tgz", - "integrity": "sha512-Kg/LHnLZnv18qzAQonnFMYcGbair/z5DI40le1L9PJlz+S7lR2xOVg0gBzTRccG1VylXozwp4GVYhVT4v7n2GA==", + "node_modules/@netlify/edge-bundler": { + "version": "14.10.3", + "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-14.10.3.tgz", + "integrity": "sha512-o+ww3ZUsdkdDEdeIhX6yT4wCNt99ar3JUreQowgXPCAyQeiXWf2i3xkoVwm5bQb77BhFmTTMp0kIeRMiGEqU4g==", "license": "MIT", "dependencies": { "@import-maps/resolve": "^2.0.0", @@ -2637,7 +2369,7 @@ "better-ajv-errors": "^1.2.0", "common-path-prefix": "^3.0.0", "env-paths": "^3.0.0", - "esbuild": "0.27.3", + "esbuild": "0.28.0", "execa": "^8.0.0", "find-up": "^7.0.0", "get-port": "^7.0.0", @@ -2649,767 +2381,999 @@ "semver": "^7.3.8", "tar": "^7.5.12", "tmp-promise": "^3.0.3", - "urlpattern-polyfill": "8.0.2", - "uuid": "^11.0.0" + "urlpattern-polyfill": "8.0.2" }, "engines": { "node": ">=18.14.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], + "node_modules/@netlify/edge-functions": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@netlify/edge-functions/-/edge-functions-3.0.8.tgz", + "integrity": "sha512-ml1oCDsRTTRmZS2nUj8XRD1b6+foEiZT3lPk7qQ4nv/jnxylHJ20ooPzPDH+cJmGjXFrMeR14/91W1o6D2ftBg==", "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "@netlify/types": "2.8.0" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } + "node_modules/@netlify/edge-functions-bootstrap": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@netlify/edge-functions-bootstrap/-/edge-functions-bootstrap-2.16.0.tgz", + "integrity": "sha512-v8QQihSbBHj3JxtJsHoepXALpNumD9M7egHoc8z62FYl5it34dWczkaJoFFopEyhiBVKi4K/n0ZYpdzwfujd6g==", + "license": "MIT" }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], + "node_modules/@netlify/edge-functions-dev": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/@netlify/edge-functions-dev/-/edge-functions-dev-1.0.20.tgz", + "integrity": "sha512-bk05M+nuafsc4JjYEhwTKI8kpnK7EPOf6sreUbdNCi+17JUNvl6D959Hxheq0Ke2nT5UPqIcJRuNvjvI+ocT+Q==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@netlify/dev-utils": "4.4.6", + "@netlify/edge-bundler": "^14.10.1", + "@netlify/edge-functions": "3.0.8", + "@netlify/edge-functions-bootstrap": "2.16.0", + "@netlify/runtime-utils": "2.3.0", + "get-port": "^7.1.0" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], + "node_modules/@netlify/functions": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-5.3.0.tgz", + "integrity": "sha512-FP+xCoZMkMOUsKa4UdG/oiK/2md1/TxuXvqqieaMVMgDbFFMaHI8h0oHCViUY73kPbKV6HyzayaSXGYXKpBSoQ==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@netlify/types": "2.8.0" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], + "node_modules/@netlify/functions-dev": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@netlify/functions-dev/-/functions-dev-1.3.0.tgz", + "integrity": "sha512-3CMb4GDuh8vzc2F7bUFw73QtCA+TEfcS9RQ6Z8Zkz4oAdTLN8W/73QeY50eWslWqkA2cUj87OLEYaTnC4Rj8EA==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@netlify/blobs": "10.7.9", + "@netlify/dev-utils": "4.4.6", + "@netlify/functions": "5.3.0", + "@netlify/zip-it-and-ship-it": "^14.5.5", + "cron-parser": "^4.9.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", + "semver": "^7.6.3", + "source-map-support": "^0.5.21" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], + "node_modules/@netlify/headers": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@netlify/headers/-/headers-2.1.11.tgz", + "integrity": "sha512-pWqoovsTBKlSfM7HKT0KnZ3x5ael2P+smiAogH5zuGU+ncQA7zBRHwLDi3nBy4iBM1MQAZ9BEjAXE42/yn/GQg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@netlify/headers-parser": "^9.0.3" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], + "node_modules/@netlify/headers-parser": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@netlify/headers-parser/-/headers-parser-9.0.3.tgz", + "integrity": "sha512-KNzC9RaKDwJVS44iTK6JxNA6LeXH0PUw0pLktWpmMVI/0FR98bvxaHcAisjHqbThAjxL9QjL1UZh0KzHCkxpNQ==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@iarna/toml": "^2.2.5", + "escape-string-regexp": "^5.0.0", + "fast-safe-stringify": "^2.0.7", + "is-plain-obj": "^4.0.0", + "map-obj": "^5.0.0", + "path-exists": "^5.0.0" + }, "engines": { - "node": ">=18" + "node": ">=18.14.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], + "node_modules/@netlify/images": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@netlify/images/-/images-1.3.10.tgz", + "integrity": "sha512-3ZlN8PNBaZFNr+uERzOtb9rQkb23xxS4k4iW188mgvSrMhxdVXPS5pkpOxAHPEunatSlT/a6oCuy3fsltrtr6A==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "ipx": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], + "node_modules/@netlify/nuxt": { + "resolved": "packages/nuxt-module", + "link": true + }, + "node_modules/@netlify/open-api": { + "version": "2.55.0", + "resolved": "https://registry.npmjs.org/@netlify/open-api/-/open-api-2.55.0.tgz", + "integrity": "sha512-kdjE3leurHQOye6R9iKjFubB69lMNqIpoAtlxELPjex0Lnokd9XctjB0fkSVXyd+hh2xHPa1On/dS0UKGDTkEw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=14.8.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], + "node_modules/@netlify/otel": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@netlify/otel/-/otel-6.0.3.tgz", + "integrity": "sha512-NIjIjB/aItiXKB6+wzSwfSyYqbNsVSzzlEPryxxTC5ZJiYSYSm82wAOcQ+9VdiufQyZO5t8jzHVPULo7a9L9sQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@opentelemetry/api": "1.9.0", + "@opentelemetry/core": "2.7.1", + "@opentelemetry/instrumentation": "^0.217.0", + "@opentelemetry/resources": "2.7.1", + "@opentelemetry/sdk-trace-node": "2.7.1" + }, "engines": { - "node": ">=18" + "node": "^18.14.0 || >=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], + "node_modules/@netlify/redirect-parser": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@netlify/redirect-parser/-/redirect-parser-15.0.4.tgz", + "integrity": "sha512-UYHRCO4HZI6WMpf8RheaCWnGafeJeFTsp/5yK887fyGqohDmFbc26NuFUvRl7J6sNu+di/1lLmRXP+yJ1X9TDA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@iarna/toml": "^2.2.5", + "fast-safe-stringify": "^2.1.1", + "is-plain-obj": "^4.0.0", + "path-exists": "^5.0.0" + }, "engines": { - "node": ">=18" + "node": ">=18.14.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], + "node_modules/@netlify/redirects": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@netlify/redirects/-/redirects-3.1.13.tgz", + "integrity": "sha512-28M4pyahGHf5kIqhdA6Y687g/QBmW0clPHmh/xGvxmwHIW+fN5aMzCO4JrM2v9bA/yDFoGjSQynckAG1MGr0/g==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@netlify/dev-utils": "4.4.6", + "@netlify/redirect-parser": "^15.0.4", + "cookie": "^1.0.2", + "jsonwebtoken": "9.0.3", + "netlify-redirector": "^0.5.0" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], + "node_modules/@netlify/runtime": { + "version": "4.1.25", + "resolved": "https://registry.npmjs.org/@netlify/runtime/-/runtime-4.1.25.tgz", + "integrity": "sha512-+RKE+oaygMDyp1ybcseQRT/OMVkiNOgUDfM0Q4+Nwl+vMGCZavmHKIAkGWRWlduw8UUcA094xSoHNcLQWCFgjg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@netlify/blobs": "^10.7.9", + "@netlify/cache": "3.4.8", + "@netlify/runtime-utils": "2.3.0", + "@netlify/types": "2.8.0" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], + "node_modules/@netlify/runtime-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@netlify/runtime-utils/-/runtime-utils-2.3.0.tgz", + "integrity": "sha512-cW8weDvsKV7zfia2m5EcBy6KILGoPD+eYZ3qWNGnIo05DGF28goPES0xKSDkNYgAF/2rRSIhie2qcBhbGVgSRg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.14.0 || >=20" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], + "node_modules/@netlify/serverless-functions-api": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-2.16.0.tgz", + "integrity": "sha512-yomP0pYRWPREiAuQbLghz9YbMb2+Mkmk1DMjyXVbIyrJ8QZhEtGcYQWAyl6cgki5CVqnOXvfIrRdLSf8bvxJCA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@netlify/types": "^2.6.0" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], + "node_modules/@netlify/static": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@netlify/static/-/static-3.1.10.tgz", + "integrity": "sha512-DOEVJ8SawvQ/ddWCSzfjqsQOE4GfF+LvxhWuB1OHSFvWnDEyBpobrLO6YWUG3lKq+0OhPBu50XFtKfdQNpUiFA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "mime-types": "^3.0.0" + }, "engines": { - "node": ">=18" + "node": ">=20.6.1" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], + "node_modules/@netlify/types": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@netlify/types/-/types-2.8.0.tgz", + "integrity": "sha512-8/g0Pt6y6wXj5Ia5eeYLiXhRfWeqZXGXpGFeCiiQdUOem+FPtXdA4+YdGxqzWc7D0AvptKSO01KGeeVWHSu8Kg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.14.0 || >=20" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } + "node_modules/@netlify/vite-plugin": { + "resolved": "packages/vite-plugin", + "link": true }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } + "node_modules/@netlify/vite-plugin-tanstack-start": { + "resolved": "packages/vite-plugin-tanstack-start", + "link": true }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], + "node_modules/@netlify/zip-it-and-ship-it": { + "version": "14.7.0", + "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-14.7.0.tgz", + "integrity": "sha512-SgqHGUTuPkarP5vpnjVKihsQAt7zQPfp+RjgpE+vJdW4tjJUEC3i6h954mE+3Mm7UZTF5xVRMMUJPi+d7oIiug==", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "dependencies": { + "@babel/parser": "^7.22.5", + "@babel/types": "^7.28.5", + "@netlify/binary-info": "^1.0.0", + "@netlify/serverless-functions-api": "2.16.0", + "@vercel/nft": "0.29.4", + "archiver": "^7.0.0", + "common-path-prefix": "^3.0.0", + "copy-file": "^11.0.0", + "es-module-lexer": "^1.0.0", + "esbuild": "0.28.0", + "execa": "^8.0.0", + "fast-glob": "^3.3.3", + "filter-obj": "^6.0.0", + "find-up": "^7.0.0", + "is-path-inside": "^4.0.0", + "junk": "^4.0.0", + "locate-path": "^7.0.0", + "merge-options": "^3.0.4", + "minimatch": "^10.2.4", + "normalize-path": "^3.0.0", + "p-map": "^7.0.0", + "path-exists": "^5.0.0", + "precinct": "^12.0.0", + "require-package-name": "^2.0.1", + "resolve": "^2.0.0-next.1", + "semver": "^7.3.8", + "tmp-promise": "^3.0.2", + "toml": "^3.0.0", + "unixify": "^1.0.0", + "urlpattern-polyfill": "8.0.2", + "yargs": "^17.0.0", + "zod": "^3.23.8" + }, + "bin": { + "zip-it-and-ship-it": "bin.js" + }, "engines": { - "node": ">=18" + "node": ">=18.14.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], + "node_modules/@netlify/zip-it-and-ship-it/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], + "node_modules/@nuxt/cli": { + "version": "3.35.2", + "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.35.2.tgz", + "integrity": "sha512-sCxNnFuYamqippdj+Cj4Nue55yaUvasaneyf2mnowK5/F1TKln/WVqTH18McxQ4baLlIlVapIFovKjJx1L8XMQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@bomb.sh/tab": "^0.0.15", + "@clack/prompts": "^1.3.0", + "c12": "^3.3.4", + "citty": "^0.2.2", + "confbox": "^0.2.4", + "consola": "^3.4.2", + "debug": "^4.4.3", + "defu": "^6.1.7", + "exsolve": "^1.0.8", + "fuse.js": "^7.3.0", + "fzf": "^0.5.2", + "giget": "^3.2.0", + "jiti": "^2.7.0", + "listhen": "^1.10.0", + "nypm": "^0.6.6", + "ofetch": "^1.5.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.1", + "scule": "^1.3.0", + "semver": "^7.8.0", + "srvx": "^0.11.15", + "std-env": "^4.1.0", + "tinyclip": "^0.1.12", + "tinyexec": "^1.1.2", + "ufo": "^1.6.4", + "youch": "^4.1.1" + }, + "bin": { + "nuxi": "bin/nuxi.mjs", + "nuxi-ng": "bin/nuxi.mjs", + "nuxt": "bin/nuxi.mjs", + "nuxt-cli": "bin/nuxi.mjs" + }, "engines": { - "node": ">=18" + "node": "^16.14.0 || >=18.0.0" + }, + "peerDependencies": { + "@nuxt/schema": "^4.4.5" + }, + "peerDependenciesMeta": { + "@nuxt/schema": { + "optional": true + } } }, - "node_modules/@netlify/edge-bundler/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "node_modules/@nuxt/devalue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nuxt/devalue/-/devalue-2.0.2.tgz", + "integrity": "sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==", + "dev": true, + "license": "MIT" }, - "node_modules/@netlify/edge-bundler/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "node_modules/@nuxt/devtools": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-2.7.0.tgz", + "integrity": "sha512-BtIklVYny14Ykek4SHeexAHoa28MEV9kz223ZzvoNYqE0f+YVV+cJP69ovZHf+HUVpxaAMJfWKLHXinWXiCZ4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nuxt/devtools-kit": "2.7.0", + "@nuxt/devtools-wizard": "2.7.0", + "@nuxt/kit": "^3.19.3", + "@vue/devtools-core": "^7.7.7", + "@vue/devtools-kit": "^7.7.7", + "birpc": "^2.6.1", + "consola": "^3.4.2", + "destr": "^2.0.5", + "error-stack-parser-es": "^1.0.5", + "execa": "^8.0.1", + "fast-npm-meta": "^0.4.7", + "get-port-please": "^3.2.0", + "hookable": "^5.5.3", + "image-meta": "^0.2.2", + "is-installed-globally": "^1.0.0", + "launch-editor": "^2.11.1", + "local-pkg": "^1.1.2", + "magicast": "^0.3.5", + "nypm": "^0.6.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.3.0", + "semver": "^7.7.3", + "simple-git": "^3.28.0", + "sirv": "^3.0.2", + "structured-clone-es": "^1.0.0", + "tinyglobby": "^0.2.15", + "vite-plugin-inspect": "^11.3.3", + "vite-plugin-vue-tracer": "^1.0.1", + "which": "^5.0.0", + "ws": "^8.18.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "bin": { + "devtools": "cli.mjs" + }, + "peerDependencies": { + "vite": ">=6.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/ajv-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", - "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "node_modules/@nuxt/devtools-kit": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.7.0.tgz", + "integrity": "sha512-MIJdah6CF6YOW2GhfKnb8Sivu6HpcQheqdjOlZqShBr+1DyjtKQbAKSCAyKPaoIzZP4QOo2SmTFV6aN8jBeEIQ==", + "dev": true, "license": "MIT", + "dependencies": { + "@nuxt/kit": "^3.19.3", + "execa": "^8.0.1" + }, "peerDependencies": { - "ajv": "^8.0.1" + "vite": ">=6.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "hasInstallScript": true, + "node_modules/@nuxt/devtools-kit/node_modules/@nuxt/kit": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.7.tgz", + "integrity": "sha512-kc7bEGcw3IHmSebr5PoO8B38MQ4N1CEcgEtrEpm+Dfmc0hE1j9KGygmHjk/eBwaYEATpSbgTzNUxjl2/cUU8ww==", + "dev": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "c12": "^3.3.4", + "consola": "^3.4.2", + "defu": "^6.1.7", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.8", + "ignore": "^7.0.5", + "jiti": "^2.7.0", + "klona": "^2.0.6", + "knitwork": "^1.3.0", + "mlly": "^1.8.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "rc9": "^3.0.1", + "scule": "^1.3.0", + "semver": "^7.8.0", + "tinyglobby": "^0.2.16", + "ufo": "^1.6.4", + "unctx": "^2.5.0", + "untyped": "^2.0.0" }, "engines": { - "node": ">=18" + "node": ">=18.12.0" + } + }, + "node_modules/@nuxt/devtools-wizard": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-2.7.0.tgz", + "integrity": "sha512-iWuWR0U6BRpF7D6xrgq9ZkQ6ajsw2EA/gVmbU9V5JPKRUtV6DVpCPi+h34VFNeQ104Sf531XgvT0sl3h93AjXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "consola": "^3.4.2", + "diff": "^8.0.2", + "execa": "^8.0.1", + "magicast": "^0.3.5", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "prompts": "^2.4.2", + "semver": "^7.7.3" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/@netlify/edge-bundler/node_modules/find-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "bin": { + "devtools-wizard": "cli.mjs" + } + }, + "node_modules/@nuxt/devtools/node_modules/@nuxt/kit": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.7.tgz", + "integrity": "sha512-kc7bEGcw3IHmSebr5PoO8B38MQ4N1CEcgEtrEpm+Dfmc0hE1j9KGygmHjk/eBwaYEATpSbgTzNUxjl2/cUU8ww==", + "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^7.2.0", - "path-exists": "^5.0.0", - "unicorn-magic": "^0.1.0" + "c12": "^3.3.4", + "consola": "^3.4.2", + "defu": "^6.1.7", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.8", + "ignore": "^7.0.5", + "jiti": "^2.7.0", + "klona": "^2.0.6", + "knitwork": "^1.3.0", + "mlly": "^1.8.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "rc9": "^3.0.1", + "scule": "^1.3.0", + "semver": "^7.8.0", + "tinyglobby": "^0.2.16", + "ufo": "^1.6.4", + "unctx": "^2.5.0", + "untyped": "^2.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18.12.0" } }, - "node_modules/@netlify/edge-bundler/node_modules/json-schema-traverse": { + "node_modules/@nuxt/devtools/node_modules/perfect-debounce": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, "license": "MIT" }, - "node_modules/@netlify/edge-bundler/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/@nuxt/eslint-config": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.15.2.tgz", + "integrity": "sha512-vS6mWB87tYjB8h3TxG/QziaZ6CGJpEOBd7N/j+64/tjNipUJzNgKwDzyGoOifNqyDDnlvgi6T3m9XpeYm4qRaA==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@clack/prompts": "^1.0.1", + "@eslint/js": "^9.39.3", + "@nuxt/eslint-plugin": "1.15.2", + "@stylistic/eslint-plugin": "^5.9.0", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", + "eslint-config-flat-gitignore": "^2.2.1", + "eslint-flat-config-utils": "^3.0.1", + "eslint-merge-processors": "^2.0.0", + "eslint-plugin-import-lite": "^0.5.2", + "eslint-plugin-import-x": "^4.16.1", + "eslint-plugin-jsdoc": "^62.7.1", + "eslint-plugin-regexp": "^3.0.0", + "eslint-plugin-unicorn": "^63.0.0", + "eslint-plugin-vue": "^10.8.0", + "eslint-processor-vue-blocks": "^2.0.0", + "globals": "^17.3.0", + "local-pkg": "^1.1.2", + "pathe": "^2.0.3", + "vue-eslint-parser": "^10.4.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0", + "eslint-plugin-format": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-format": { + "optional": true + } } }, - "node_modules/@netlify/edge-bundler/node_modules/uuid": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", - "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], + "node_modules/@nuxt/eslint-plugin": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.15.2.tgz", + "integrity": "sha512-LZ4gEcPP5GjzAkb6Kk04a4v0vvkTLOpmnEvdDatnkSlxtQLUSwX8v11vcDGXL92ZQ98dFoC1Q1IA6Tz3jdFIig==", + "dev": true, "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" + "dependencies": { + "@typescript-eslint/types": "^8.56.1", + "@typescript-eslint/utils": "^8.56.1" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" } }, - "node_modules/@netlify/edge-functions": { - "resolved": "packages/edge-functions/prod", - "link": true - }, - "node_modules/@netlify/edge-functions-bootstrap": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@netlify/edge-functions-bootstrap/-/edge-functions-bootstrap-2.16.0.tgz", - "integrity": "sha512-v8QQihSbBHj3JxtJsHoepXALpNumD9M7egHoc8z62FYl5it34dWczkaJoFFopEyhiBVKi4K/n0ZYpdzwfujd6g==", - "license": "MIT" - }, - "node_modules/@netlify/edge-functions-dev": { - "resolved": "packages/edge-functions/dev", - "link": true - }, - "node_modules/@netlify/functions": { - "resolved": "packages/functions/prod", - "link": true - }, - "node_modules/@netlify/functions-dev": { - "resolved": "packages/functions/dev", - "link": true - }, - "node_modules/@netlify/headers": { - "resolved": "packages/headers", - "link": true - }, - "node_modules/@netlify/headers-parser": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@netlify/headers-parser/-/headers-parser-9.0.3.tgz", - "integrity": "sha512-KNzC9RaKDwJVS44iTK6JxNA6LeXH0PUw0pLktWpmMVI/0FR98bvxaHcAisjHqbThAjxL9QjL1UZh0KzHCkxpNQ==", + "node_modules/@nuxt/kit": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.7.tgz", + "integrity": "sha512-QwtpqNxSOLyJH1UoDpcgsfzVEw95J0893hn1A+CvgeOxoTos1BGvD15D1v/OVQ2MK1EpfnFZJby51t1yudOvBA==", "license": "MIT", "dependencies": { - "@iarna/toml": "^2.2.5", - "escape-string-regexp": "^5.0.0", - "fast-safe-stringify": "^2.0.7", - "is-plain-obj": "^4.0.0", - "map-obj": "^5.0.0", - "path-exists": "^5.0.0" + "c12": "^3.3.4", + "consola": "^3.4.2", + "defu": "^6.1.7", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.8", + "ignore": "^7.0.5", + "jiti": "^2.7.0", + "klona": "^2.0.6", + "mlly": "^1.8.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "rc9": "^3.0.1", + "scule": "^1.3.0", + "semver": "^7.8.1", + "tinyglobby": "^0.2.17", + "ufo": "^1.6.4", + "unctx": "^2.5.0", + "untyped": "^2.0.0" }, "engines": { - "node": ">=18.14.0" + "node": ">=18.12.0" } }, - "node_modules/@netlify/headers-parser/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "node_modules/@nuxt/module-builder": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@nuxt/module-builder/-/module-builder-1.0.2.tgz", + "integrity": "sha512-9M+0oZimbwom1J+HrfDuR5NDPED6C+DlM+2xfXju9wqB6VpVfYkS6WNEmS0URw8kpJcKBuogAc7ADO7vRS4s4A==", + "dev": true, "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "defu": "^6.1.4", + "jiti": "^2.5.1", + "magic-regexp": "^0.10.0", + "mkdist": "^2.3.0", + "mlly": "^1.7.4", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tsconfck": "^3.1.6", + "unbuild": "^3.6.0", + "vue-sfc-transformer": "^0.1.16" + }, + "bin": { + "nuxt-build-module": "dist/cli.mjs", + "nuxt-module-build": "dist/cli.mjs" + }, "engines": { - "node": ">=12" + "node": "^18.0.0 || >=20.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@nuxt/cli": "^3.26.4", + "typescript": "^5.8.3" } }, - "node_modules/@netlify/headers-parser/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/@nuxt/module-builder/node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "consola": "^3.2.3" } }, - "node_modules/@netlify/headers-parser/node_modules/map-obj": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", - "integrity": "sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==", + "node_modules/@nuxt/nitro-server": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@nuxt/nitro-server/-/nitro-server-4.4.7.tgz", + "integrity": "sha512-mlu/DQ2P0CUb62uKlWr/uiWEG//gxEzGoTHtqREb1iso15zMmRMpFajILOdCknSGNoOyDOhqdAe7w6Yod9o50g==", + "dev": true, "license": "MIT", + "dependencies": { + "@nuxt/devalue": "^2.0.2", + "@nuxt/kit": "4.4.7", + "@unhead/vue": "^2.1.15", + "@vue/shared": "^3.5.35", + "consola": "^3.4.2", + "defu": "^6.1.7", + "destr": "^2.0.5", + "devalue": "^5.8.1", + "errx": "^0.1.0", + "escape-string-regexp": "^5.0.0", + "exsolve": "^1.0.8", + "h3": "^1.15.11", + "impound": "^1.1.5", + "klona": "^2.0.6", + "mocked-exports": "^0.1.1", + "nitropack": "^2.13.4", + "nypm": "^0.6.6", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "rou3": "^0.8.1", + "std-env": "^4.1.0", + "ufo": "^1.6.4", + "unctx": "^2.5.0", + "unstorage": "^1.17.5", + "vue": "^3.5.35", + "vue-bundle-renderer": "^2.2.0", + "vue-devtools-stub": "^0.1.0" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^22.12.0 || ^24.11.0 || >=26.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/plugin-proposal-decorators": "^7.25.0", + "@babel/plugin-syntax-typescript": "^7.25.0", + "@rollup/plugin-babel": "^6.0.0 || ^7.0.0", + "nuxt": "^4.4.7" + }, + "peerDependenciesMeta": { + "@babel/plugin-proposal-decorators": { + "optional": true + }, + "@babel/plugin-syntax-typescript": { + "optional": true + }, + "@rollup/plugin-babel": { + "optional": true + } } }, - "node_modules/@netlify/identity": { - "resolved": "packages/identity/prod", - "link": true - }, - "node_modules/@netlify/images": { - "resolved": "packages/images", - "link": true - }, - "node_modules/@netlify/nuxt": { - "resolved": "packages/nuxt-module", - "link": true - }, - "node_modules/@netlify/open-api": { - "version": "2.51.0", - "resolved": "https://registry.npmjs.org/@netlify/open-api/-/open-api-2.51.0.tgz", - "integrity": "sha512-pnGsLklHMfx8BKbWsiK8ZZ7h+vfE8Xh5ox0Lq2n0UMJUZL+iLMqXDw4tc3Udp9JxmyC06xBE6yYkOTI82VV0aA==", + "node_modules/@nuxt/schema": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.4.7.tgz", + "integrity": "sha512-jcyXJlOR/GmxDQHrIEdEevUCUuBv7B6GCQXIBt4oKTCasIwWgGuqo48IM35RsxdQVTb4tBohnqJbS2lKJlCBWg==", + "dev": true, "license": "MIT", + "dependencies": { + "@vue/shared": "^3.5.35", + "defu": "^6.1.7", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "std-env": "^4.1.0" + }, "engines": { - "node": ">=14.8.0" + "node": "^14.18.0 || >=16.10.0" } }, - "node_modules/@netlify/otel": { - "resolved": "packages/otel", - "link": true - }, - "node_modules/@netlify/redirect-parser": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@netlify/redirect-parser/-/redirect-parser-15.0.4.tgz", - "integrity": "sha512-UYHRCO4HZI6WMpf8RheaCWnGafeJeFTsp/5yK887fyGqohDmFbc26NuFUvRl7J6sNu+di/1lLmRXP+yJ1X9TDA==", + "node_modules/@nuxt/telemetry": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.8.0.tgz", + "integrity": "sha512-zAwXY24KYvpLTmiV+osagd2EHkfs5IF+7oDZYTQoit5r0kPlwaCNlzHp5I/wUAWT4LBw6lG8gZ6bWidAdv/erQ==", + "dev": true, "license": "MIT", "dependencies": { - "@iarna/toml": "^2.2.5", - "fast-safe-stringify": "^2.1.1", - "is-plain-obj": "^4.0.0", - "path-exists": "^5.0.0" + "citty": "^0.2.1", + "consola": "^3.4.2", + "ofetch": "^2.0.0-alpha.3", + "rc9": "^3.0.0", + "std-env": "^4.0.0" + }, + "bin": { + "nuxt-telemetry": "bin/nuxt-telemetry.mjs" }, "engines": { - "node": ">=18.14.0" + "node": ">=18.12.0" + }, + "peerDependencies": { + "@nuxt/kit": ">=3.0.0" } }, - "node_modules/@netlify/redirect-parser/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/@nuxt/telemetry/node_modules/ofetch": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-2.0.0-alpha.3.tgz", + "integrity": "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nuxt/test-utils": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@nuxt/test-utils/-/test-utils-3.23.0.tgz", + "integrity": "sha512-NZKWSwvfIiTO2qhMoJHVbUQLgJMe96J9ccLhPPqN5+a/XzISZ027LG9wWVp1tC5oB0qQ3eUDhrxmq6Lj8EQLMQ==", + "dev": true, "license": "MIT", + "dependencies": { + "@clack/prompts": "1.0.0-alpha.9", + "@nuxt/kit": "^3.20.2", + "c12": "^3.3.3", + "consola": "^3.4.2", + "defu": "^6.1.4", + "destr": "^2.0.5", + "estree-walker": "^3.0.3", + "exsolve": "^1.0.8", + "fake-indexeddb": "^6.2.5", + "get-port-please": "^3.2.0", + "h3": "^1.15.4", + "h3-next": "npm:h3@^2.0.1-rc.7", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "node-fetch-native": "^1.6.7", + "node-mock-http": "^1.0.4", + "nypm": "^0.6.2", + "ofetch": "^1.5.1", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "radix3": "^1.1.2", + "scule": "^1.3.0", + "std-env": "^3.10.0", + "tinyexec": "^1.0.2", + "ufo": "^1.6.1", + "unplugin": "^2.3.11", + "vitest-environment-nuxt": "^1.0.1", + "vue": "^3.5.26" + }, "engines": { - "node": ">=12" + "node": "^20.11.1 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@cucumber/cucumber": "^10.3.1 || >=11.0.0", + "@jest/globals": "^29.5.0 || >=30.0.0", + "@playwright/test": "^1.43.1", + "@testing-library/vue": "^7.0.0 || ^8.0.1", + "@vue/test-utils": "^2.4.2", + "happy-dom": "*", + "jsdom": "*", + "playwright-core": "^1.43.1", + "vitest": "^3.2.0" + }, + "peerDependenciesMeta": { + "@cucumber/cucumber": { + "optional": true + }, + "@jest/globals": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "@testing-library/vue": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "@vue/test-utils": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "playwright-core": { + "optional": true + }, + "vitest": { + "optional": true + } } }, - "node_modules/@netlify/redirects": { - "resolved": "packages/redirects", - "link": true - }, - "node_modules/@netlify/runtime": { - "resolved": "packages/runtime", - "link": true + "node_modules/@nuxt/test-utils/node_modules/@clack/core": { + "version": "1.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.0.0-alpha.7.tgz", + "integrity": "sha512-3vdh6Ar09D14rVxJZIm3VQJkU+ZOKKT5I5cC0cOVazy70CNyYYjiwRj9unwalhESndgxx6bGc/m6Hhs4EKF5XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } }, - "node_modules/@netlify/runtime-utils": { - "resolved": "packages/runtime-utils", - "link": true + "node_modules/@nuxt/test-utils/node_modules/@clack/prompts": { + "version": "1.0.0-alpha.9", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.0.0-alpha.9.tgz", + "integrity": "sha512-sKs0UjiHFWvry4SiRfBi5Qnj0C/6AYx8aKkFPZQSuUZXgAram25ZDmhQmP7vj1aFyLpfHWtLQjWvOvcat0TOLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "1.0.0-alpha.7", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } }, - "node_modules/@netlify/serverless-functions-api": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-2.15.1.tgz", - "integrity": "sha512-mgX6Nvidvy6h++Zk6vDlTuVEeeQVokuSCu0wuLyDfS5cdxowmdBNDA7ZWwLVS8ux2ozVUwRMkhPHSZUohkYTMw==", + "node_modules/@nuxt/test-utils/node_modules/@nuxt/kit": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.7.tgz", + "integrity": "sha512-kc7bEGcw3IHmSebr5PoO8B38MQ4N1CEcgEtrEpm+Dfmc0hE1j9KGygmHjk/eBwaYEATpSbgTzNUxjl2/cUU8ww==", + "dev": true, "license": "MIT", "dependencies": { - "@netlify/types": "^2.6.0" + "c12": "^3.3.4", + "consola": "^3.4.2", + "defu": "^6.1.7", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.8", + "ignore": "^7.0.5", + "jiti": "^2.7.0", + "klona": "^2.0.6", + "knitwork": "^1.3.0", + "mlly": "^1.8.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "rc9": "^3.0.1", + "scule": "^1.3.0", + "semver": "^7.8.0", + "tinyglobby": "^0.2.16", + "ufo": "^1.6.4", + "unctx": "^2.5.0", + "untyped": "^2.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.12.0" } }, - "node_modules/@netlify/static": { - "resolved": "packages/static", - "link": true - }, - "node_modules/@netlify/types": { - "resolved": "packages/types", - "link": true - }, - "node_modules/@netlify/vite-plugin": { - "resolved": "packages/vite-plugin", - "link": true - }, - "node_modules/@netlify/vite-plugin-tanstack-start": { - "resolved": "packages/vite-plugin-tanstack-start", - "link": true + "node_modules/@nuxt/test-utils/node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" }, - "node_modules/@netlify/zip-it-and-ship-it": { - "version": "14.5.5", - "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-14.5.5.tgz", - "integrity": "sha512-sWj48CDL8DjuwSu6+bQp1pvxXvBAU4P1BbkmJB+H+q3/YH7Yv9jRUNO+4nC/PJl4M/OVk8fXwHqW4+pTFstW6g==", + "node_modules/@nuxt/vite-builder": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-4.4.7.tgz", + "integrity": "sha512-EnMofNWpZF/dg4948PXk1kqrdR5uUR301sSudVbYj4DCjCa4NnBISwRbd4qe04F5Yw5OMHcR3svd8phZm1Yc7Q==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.22.5", - "@babel/types": "^7.28.5", - "@netlify/binary-info": "^1.0.0", - "@netlify/serverless-functions-api": "2.15.1", - "@vercel/nft": "0.29.4", - "archiver": "^7.0.0", - "common-path-prefix": "^3.0.0", - "copy-file": "^11.0.0", - "es-module-lexer": "^1.0.0", - "esbuild": "0.27.3", - "execa": "^8.0.0", - "fast-glob": "^3.3.3", - "filter-obj": "^6.0.0", - "find-up": "^7.0.0", - "is-path-inside": "^4.0.0", - "junk": "^4.0.0", - "locate-path": "^7.0.0", - "merge-options": "^3.0.4", - "minimatch": "^10.2.4", - "normalize-path": "^3.0.0", - "p-map": "^7.0.0", - "path-exists": "^5.0.0", - "precinct": "^12.0.0", - "require-package-name": "^2.0.1", - "resolve": "^2.0.0-next.1", - "semver": "^7.3.8", - "tmp-promise": "^3.0.2", - "toml": "^3.0.0", - "unixify": "^1.0.0", - "urlpattern-polyfill": "8.0.2", - "yargs": "^17.0.0", - "zod": "^3.23.8" - }, - "bin": { - "zip-it-and-ship-it": "bin.js" + "@nuxt/kit": "4.4.7", + "@rollup/plugin-replace": "^6.0.3", + "@vitejs/plugin-vue": "^6.0.7", + "@vitejs/plugin-vue-jsx": "^5.1.5", + "autoprefixer": "^10.5.0", + "consola": "^3.4.2", + "cssnano": "^8.0.1", + "defu": "^6.1.7", + "escape-string-regexp": "^5.0.0", + "exsolve": "^1.0.8", + "get-port-please": "^3.2.0", + "jiti": "^2.7.0", + "knitwork": "^1.3.0", + "magic-string": "^0.30.21", + "mlly": "^1.8.2", + "mocked-exports": "^0.1.1", + "nypm": "^0.6.6", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "postcss": "^8.5.15", + "seroval": "^1.5.4", + "std-env": "^4.1.0", + "ufo": "^1.6.4", + "unenv": "^2.0.0-rc.24", + "vite": "^7.3.3", + "vite-node": "^5.3.0", + "vite-plugin-checker": "^0.14.1", + "vue-bundle-renderer": "^2.2.0" }, "engines": { - "node": ">=18.14.0" + "node": "^22.12.0 || ^24.11.0 || >=26.0.0" + }, + "peerDependencies": { + "@babel/plugin-proposal-decorators": "^7.25.0", + "@babel/plugin-syntax-jsx": "^7.25.0", + "nuxt": "4.4.7", + "rolldown": "^1.0.0-beta.38", + "rollup-plugin-visualizer": "^6.0.0 || ^7.0.1", + "vue": "^3.3.4" + }, + "peerDependenciesMeta": { + "@babel/plugin-proposal-decorators": { + "optional": true + }, + "@babel/plugin-syntax-jsx": { + "optional": true + }, + "rolldown": { + "optional": true + }, + "rollup-plugin-visualizer": { + "optional": true + } } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3419,13 +3383,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3435,13 +3400,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3451,13 +3417,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3467,13 +3434,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3483,13 +3451,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3499,13 +3468,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3515,13 +3485,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3531,13 +3502,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3547,13 +3519,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3563,13 +3536,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3579,13 +3553,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3595,13 +3570,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3611,13 +3587,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3627,13 +3604,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3643,13 +3621,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3659,13 +3638,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3675,13 +3655,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3691,13 +3672,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3707,13 +3689,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3723,13 +3706,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3739,13 +3723,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3755,13 +3740,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3771,13 +3757,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3787,13 +3774,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3803,13 +3791,14 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3819,31 +3808,89 @@ "node": ">=18" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/@nuxt/vite-builder/node_modules/cssnano": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.1.tgz", + "integrity": "sha512-oSiOnPQNNYjusTUlYJiE6xvFQG4don3N0QavaoV1BxIsC1zjvxOwikXlR7lG1EVmZNDDaJkHbQx1VRB8kaoMHA==", + "dev": true, "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^8.0.1", + "lilconfig": "^3.1.3" + }, "engines": { - "node": "18 || 20 || >=22" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "node_modules/@nuxt/vite-builder/node_modules/cssnano-preset-default": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.1.tgz", + "integrity": "sha512-OTdKeYMlvQ8KBgyej5ysktnWJoeyo7rGrVnm+bdpIHGvxhbTGPsOkB+7T1EdTuX00dGlQQb2UEbSPB1OpMXULw==", + "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" + "browserslist": "^4.28.2", + "cssnano-utils": "^6.0.0", + "postcss-calc": "^10.1.1", + "postcss-colormin": "^8.0.0", + "postcss-convert-values": "^8.0.0", + "postcss-discard-comments": "^8.0.0", + "postcss-discard-duplicates": "^8.0.0", + "postcss-discard-empty": "^8.0.0", + "postcss-discard-overridden": "^8.0.0", + "postcss-merge-longhand": "^8.0.0", + "postcss-merge-rules": "^8.0.0", + "postcss-minify-font-values": "^8.0.0", + "postcss-minify-gradients": "^8.0.0", + "postcss-minify-params": "^8.0.0", + "postcss-minify-selectors": "^8.0.1", + "postcss-normalize-charset": "^8.0.0", + "postcss-normalize-display-values": "^8.0.0", + "postcss-normalize-positions": "^8.0.0", + "postcss-normalize-repeat-style": "^8.0.0", + "postcss-normalize-string": "^8.0.0", + "postcss-normalize-timing-functions": "^8.0.0", + "postcss-normalize-unicode": "^8.0.0", + "postcss-normalize-url": "^8.0.0", + "postcss-normalize-whitespace": "^8.0.0", + "postcss-ordered-values": "^8.0.0", + "postcss-reduce-initial": "^8.0.0", + "postcss-reduce-transforms": "^8.0.0", + "postcss-svgo": "^8.0.0", + "postcss-unique-selectors": "^8.0.0" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, + "peerDependencies": { + "postcss": "^8.5.14" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/cssnano-utils": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.0.tgz", + "integrity": "sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "18 || 20 || >=22" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "node_modules/@nuxt/vite-builder/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -3853,1191 +3900,617 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/find-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/postcss-colormin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.0.tgz", + "integrity": "sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==", + "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^7.2.0", - "path-exists": "^5.0.0", - "unicorn-magic": "^0.1.0" + "@colordx/core": "^5.4.3", + "browserslist": "^4.28.2", + "caniuse-api": "^3.0.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18" + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "license": "BlueOak-1.0.0", + "node_modules/@nuxt/vite-builder/node_modules/postcss-convert-values": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.0.tgz", + "integrity": "sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.5" + "browserslist": "^4.28.2", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "18 || 20 || >=22" + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-comments": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.0.tgz", + "integrity": "sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==", + "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": ">= 8" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-duplicates": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.0.tgz", + "integrity": "sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 8" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-empty": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.0.tgz", + "integrity": "sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==", + "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, + "peerDependencies": { + "postcss": "^8.5.14" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-overridden": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.0.tgz", + "integrity": "sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 8" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/cli": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.28.0.tgz", - "integrity": "sha512-WQ751WxWLBIeH3TDFt/LWQ2znyAKxpR5+gpv80oerwnVQs4GKajAfR6dIgExXZkjaPUHEFv2lVD9vM+frbprzw==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-merge-longhand": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.0.tgz", + "integrity": "sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==", "dev": true, "license": "MIT", "dependencies": { - "c12": "^3.2.0", - "citty": "^0.1.6", - "clipboardy": "^4.0.0", - "confbox": "^0.2.2", - "consola": "^3.4.2", - "defu": "^6.1.4", - "exsolve": "^1.0.7", - "fuse.js": "^7.1.0", - "get-port-please": "^3.2.0", - "giget": "^2.0.0", - "h3": "^1.15.4", - "httpxy": "^0.1.7", - "jiti": "^2.5.1", - "listhen": "^1.9.0", - "nypm": "^0.6.1", - "ofetch": "^1.4.1", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "pkg-types": "^2.2.0", - "scule": "^1.3.0", - "semver": "^7.7.2", - "std-env": "^3.9.0", - "tinyexec": "^1.0.1", - "ufo": "^1.6.1", - "youch": "^4.1.0-beta.11" - }, - "bin": { - "nuxi": "bin/nuxi.mjs", - "nuxi-ng": "bin/nuxi.mjs", - "nuxt": "bin/nuxi.mjs", - "nuxt-cli": "bin/nuxi.mjs" + "postcss-value-parser": "^4.2.0", + "stylehacks": "^8.0.0" }, "engines": { - "node": "^16.10.0 || >=18.0.0" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/cli/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/cli/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-merge-rules": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.0.tgz", + "integrity": "sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==", "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "browserslist": "^4.28.2", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^6.0.0", + "postcss-selector-parser": "^7.1.1" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/cli/node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/devalue": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nuxt/devalue/-/devalue-2.0.2.tgz", - "integrity": "sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/devtools": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-2.7.0.tgz", - "integrity": "sha512-BtIklVYny14Ykek4SHeexAHoa28MEV9kz223ZzvoNYqE0f+YVV+cJP69ovZHf+HUVpxaAMJfWKLHXinWXiCZ4Q==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-font-values": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.0.tgz", + "integrity": "sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==", "dev": true, "license": "MIT", "dependencies": { - "@nuxt/devtools-kit": "2.7.0", - "@nuxt/devtools-wizard": "2.7.0", - "@nuxt/kit": "^3.19.3", - "@vue/devtools-core": "^7.7.7", - "@vue/devtools-kit": "^7.7.7", - "birpc": "^2.6.1", - "consola": "^3.4.2", - "destr": "^2.0.5", - "error-stack-parser-es": "^1.0.5", - "execa": "^8.0.1", - "fast-npm-meta": "^0.4.7", - "get-port-please": "^3.2.0", - "hookable": "^5.5.3", - "image-meta": "^0.2.2", - "is-installed-globally": "^1.0.0", - "launch-editor": "^2.11.1", - "local-pkg": "^1.1.2", - "magicast": "^0.3.5", - "nypm": "^0.6.2", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "pkg-types": "^2.3.0", - "semver": "^7.7.3", - "simple-git": "^3.28.0", - "sirv": "^3.0.2", - "structured-clone-es": "^1.0.0", - "tinyglobby": "^0.2.15", - "vite-plugin-inspect": "^11.3.3", - "vite-plugin-vue-tracer": "^1.0.1", - "which": "^5.0.0", - "ws": "^8.18.3" + "postcss-value-parser": "^4.2.0" }, - "bin": { - "devtools": "cli.mjs" + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "vite": ">=6.0" + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools-kit": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.7.0.tgz", - "integrity": "sha512-MIJdah6CF6YOW2GhfKnb8Sivu6HpcQheqdjOlZqShBr+1DyjtKQbAKSCAyKPaoIzZP4QOo2SmTFV6aN8jBeEIQ==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-gradients": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.0.tgz", + "integrity": "sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==", "dev": true, "license": "MIT", "dependencies": { - "@nuxt/kit": "^3.19.3", - "execa": "^8.0.1" + "@colordx/core": "^5.4.3", + "cssnano-utils": "^6.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "vite": ">=6.0" + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools-kit/node_modules/@nuxt/kit": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.20.1.tgz", - "integrity": "sha512-TIslaylfI5kd3AxX5qts0qyrIQ9Uq3HAA1bgIIJ+c+zpDfK338YS+YrCWxBBzDMECRCbAS58mqAd2MtJfG1ENA==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-params": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.0.tgz", + "integrity": "sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==", "dev": true, "license": "MIT", "dependencies": { - "c12": "^3.3.1", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.7", - "ignore": "^7.0.5", - "jiti": "^2.6.1", - "klona": "^2.0.6", - "knitwork": "^1.2.0", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^2.1.2", - "scule": "^1.3.0", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "untyped": "^2.0.0" + "browserslist": "^4.28.2", + "cssnano-utils": "^6.0.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18.12.0" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools-kit/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/devtools-kit/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-selectors": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.1.tgz", + "integrity": "sha512-c31D46811kTkQDxV1KTTow79axX6gj/01AY5G7cGZg3s31KvAwP13jEFXGAzQbJ7NvOFV1pRqEia6nrAdHU7qg==", "dev": true, "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-api": "^3.0.0", + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.1" + }, "engines": { - "node": ">= 4" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools-kit/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-charset": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.0.tgz", + "integrity": "sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==", "dev": true, "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools-wizard": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-2.7.0.tgz", - "integrity": "sha512-iWuWR0U6BRpF7D6xrgq9ZkQ6ajsw2EA/gVmbU9V5JPKRUtV6DVpCPi+h34VFNeQ104Sf531XgvT0sl3h93AjXA==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-display-values": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.0.tgz", + "integrity": "sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==", "dev": true, "license": "MIT", "dependencies": { - "consola": "^3.4.2", - "diff": "^8.0.2", - "execa": "^8.0.1", - "magicast": "^0.3.5", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "prompts": "^2.4.2", - "semver": "^7.7.3" + "postcss-value-parser": "^4.2.0" }, - "bin": { - "devtools-wizard": "cli.mjs" + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools-wizard/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/devtools-wizard/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-positions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.0.tgz", + "integrity": "sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==", "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools/node_modules/@nuxt/kit": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.20.1.tgz", - "integrity": "sha512-TIslaylfI5kd3AxX5qts0qyrIQ9Uq3HAA1bgIIJ+c+zpDfK338YS+YrCWxBBzDMECRCbAS58mqAd2MtJfG1ENA==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-repeat-style": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.0.tgz", + "integrity": "sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==", "dev": true, "license": "MIT", "dependencies": { - "c12": "^3.3.1", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.7", - "ignore": "^7.0.5", - "jiti": "^2.6.1", - "klona": "^2.0.6", - "knitwork": "^1.2.0", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^2.1.2", - "scule": "^1.3.0", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "untyped": "^2.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18.12.0" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/devtools/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-string": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.0.tgz", + "integrity": "sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==", "dev": true, "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">= 4" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-timing-functions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.0.tgz", + "integrity": "sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=16" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-unicode": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.0.tgz", + "integrity": "sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==", "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "browserslist": "^4.28.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/devtools/node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.0.tgz", + "integrity": "sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/eslint-config": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.9.0.tgz", - "integrity": "sha512-KLiYlX/MmWR9dhC0u7GSZQl6wyVLGAHme5aAL5fAUT1PLYgcFiJIUg1Z+b296LmwHGTa+oGPRBIk3yoDmX9/9Q==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-whitespace": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.0.tgz", + "integrity": "sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==", "dev": true, "license": "MIT", "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@clack/prompts": "^0.11.0", - "@eslint/js": "^9.33.0", - "@nuxt/eslint-plugin": "1.9.0", - "@stylistic/eslint-plugin": "^5.2.3", - "@typescript-eslint/eslint-plugin": "^8.39.1", - "@typescript-eslint/parser": "^8.39.1", - "eslint-config-flat-gitignore": "^2.1.0", - "eslint-flat-config-utils": "^2.1.1", - "eslint-merge-processors": "^2.0.0", - "eslint-plugin-import-lite": "^0.3.0", - "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^54.1.0", - "eslint-plugin-regexp": "^2.10.0", - "eslint-plugin-unicorn": "^60.0.0", - "eslint-plugin-vue": "^10.4.0", - "eslint-processor-vue-blocks": "^2.0.0", - "globals": "^16.3.0", - "local-pkg": "^1.1.1", - "pathe": "^2.0.3", - "vue-eslint-parser": "^10.2.0" + "postcss-value-parser": "^4.2.0" }, - "peerDependencies": { - "eslint": "^9.0.0", - "eslint-plugin-format": "*" + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, - "peerDependenciesMeta": { - "eslint-plugin-format": { - "optional": true - } + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/eslint-config/node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-ordered-values": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.0.tgz", + "integrity": "sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==", "dev": true, "license": "MIT", + "dependencies": { + "cssnano-utils": "^6.0.0", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=18" + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/eslint-plugin": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.9.0.tgz", - "integrity": "sha512-DY4ZSavgFyKQxI/NCOpSCUHg3dpS2O4lAdic5UmvP2NWj1xwtvmA9UwEZQ2nW2/f/Km6N+Q53UsgFSIBjz8jDQ==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-reduce-initial": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.0.tgz", + "integrity": "sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.39.1", - "@typescript-eslint/utils": "^8.39.1" + "browserslist": "^4.28.2", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "eslint": "^9.0.0" + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/kit": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.1.1.tgz", - "integrity": "sha512-2MGfOXtbcxdkbUNZDjyEv4xmokicZhTrQBMrmNJQztrePfpKOVBe8AiGf/BfbHelXMKio5PgktiRoiEIyIsX4g==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-reduce-transforms": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.0.tgz", + "integrity": "sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==", + "dev": true, "license": "MIT", "dependencies": { - "c12": "^3.2.0", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.7", - "ignore": "^7.0.5", - "jiti": "^2.5.1", - "klona": "^2.0.6", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^2.1.2", - "scule": "^1.3.0", - "semver": "^7.7.2", - "std-env": "^3.9.0", - "tinyglobby": "^0.2.14", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "unimport": "^5.2.0", - "untyped": "^2.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18.12.0" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/kit/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "license": "MIT" - }, - "node_modules/@nuxt/kit/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-svgo": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.0.tgz", + "integrity": "sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==", + "dev": true, "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^4.0.1" + }, "engines": { - "node": ">= 4" + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/kit/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/@nuxt/vite-builder/node_modules/postcss-unique-selectors": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.0.tgz", + "integrity": "sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==", + "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "postcss-selector-parser": "^7.1.1" + }, + "engines": { + "node": "^22.11.0 || ^24.11.0 || >=26.0" + }, + "peerDependencies": { + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/module-builder": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@nuxt/module-builder/-/module-builder-1.0.2.tgz", - "integrity": "sha512-9M+0oZimbwom1J+HrfDuR5NDPED6C+DlM+2xfXju9wqB6VpVfYkS6WNEmS0URw8kpJcKBuogAc7ADO7vRS4s4A==", + "node_modules/@nuxt/vite-builder/node_modules/stylehacks": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.0.tgz", + "integrity": "sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==", "dev": true, "license": "MIT", "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.2", - "defu": "^6.1.4", - "jiti": "^2.5.1", - "magic-regexp": "^0.10.0", - "mkdist": "^2.3.0", - "mlly": "^1.7.4", - "pathe": "^2.0.3", - "pkg-types": "^2.2.0", - "tsconfck": "^3.1.6", - "unbuild": "^3.6.0", - "vue-sfc-transformer": "^0.1.16" - }, - "bin": { - "nuxt-build-module": "dist/cli.mjs", - "nuxt-module-build": "dist/cli.mjs" + "browserslist": "^4.28.2", + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "@nuxt/cli": "^3.26.4", - "typescript": "^5.8.3" + "postcss": "^8.5.14" } }, - "node_modules/@nuxt/module-builder/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/module-builder/node_modules/mkdist": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/mkdist/-/mkdist-2.3.0.tgz", - "integrity": "sha512-thkRk+pHdudjdZT3FJpPZ2+pncI6mGlH/B+KBVddlZj4MrFGW41sRIv1wZawZUHU8v7cttGaj+5nx8P+dG664A==", + "node_modules/@nuxt/vite-builder/node_modules/vite": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", "dev": true, "license": "MIT", "dependencies": { - "autoprefixer": "^10.4.21", - "citty": "^0.1.6", - "cssnano": "^7.0.6", - "defu": "^6.1.4", - "esbuild": "^0.25.2", - "jiti": "^1.21.7", - "mlly": "^1.7.4", - "pathe": "^2.0.3", - "pkg-types": "^2.1.0", - "postcss": "^8.5.3", - "postcss-nested": "^7.0.2", - "semver": "^7.7.1", - "tinyglobby": "^0.2.12" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { - "mkdist": "dist/cli.cjs" + "vite": "bin/vite.js" }, - "peerDependencies": { - "sass": "^1.85.0", - "typescript": ">=5.7.3", - "vue": "^3.5.13", - "vue-sfc-transformer": "^0.1.1", - "vue-tsc": "^1.8.27 || ^2.0.21" + "engines": { + "node": "^20.19.0 || >=22.12.0" }, - "peerDependenciesMeta": { - "sass": { - "optional": true - }, - "typescript": { - "optional": true - }, - "vue": { - "optional": true - }, - "vue-sfc-transformer": { - "optional": true - }, - "vue-tsc": { - "optional": true - } - } - }, - "node_modules/@nuxt/module-builder/node_modules/mkdist/node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/@nuxt/module-builder/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" - } - }, - "node_modules/@nuxt/schema": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.19.1.tgz", - "integrity": "sha512-87IfTFaJdHXIfOXrWH7lQDp5LcKPH3h7kc8UdXWBLrCy3lsxxTu42TWJV948fWKVYHCx0O/Er3bno5gMLD+IVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/shared": "^3.5.20", - "consola": "^3.4.2", - "defu": "^6.1.4", - "pathe": "^2.0.3", - "std-env": "^3.9.0", - "ufo": "1.6.1" - }, - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/@nuxt/telemetry": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.6.6.tgz", - "integrity": "sha512-Zh4HJLjzvm3Cq9w6sfzIFyH9ozK5ePYVfCUzzUQNiZojFsI2k1QkSBrVI9BGc6ArKXj/O6rkI6w7qQ+ouL8Cag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nuxt/kit": "^3.15.4", - "citty": "^0.1.6", - "consola": "^3.4.2", - "destr": "^2.0.3", - "dotenv": "^16.4.7", - "git-url-parse": "^16.0.1", - "is-docker": "^3.0.0", - "ofetch": "^1.4.1", - "package-manager-detector": "^1.1.0", - "pathe": "^2.0.3", - "rc9": "^2.1.2", - "std-env": "^3.8.1" - }, - "bin": { - "nuxt-telemetry": "bin/nuxt-telemetry.mjs" - }, - "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/@nuxt/telemetry/node_modules/@nuxt/kit": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.19.1.tgz", - "integrity": "sha512-cLKNdmfFk49o9Tt7g+vwD9rYN7cLg0D6K6CRB+4aaQYxveJXQbZGgZ4z7CGq5HxIG22Ki8G3XSXaiN1s6lVyZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "c12": "^3.2.0", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.7", - "ignore": "^7.0.5", - "jiti": "^2.5.1", - "klona": "^2.0.6", - "knitwork": "^1.2.0", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^2.1.2", - "scule": "^1.3.0", - "semver": "^7.7.2", - "std-env": "^3.9.0", - "tinyglobby": "^0.2.14", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "unimport": "^5.2.0", - "untyped": "^2.0.0" - }, - "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/@nuxt/telemetry/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/telemetry/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@nuxt/telemetry/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" - } - }, - "node_modules/@nuxt/test-utils": { - "version": "3.19.2", - "resolved": "https://registry.npmjs.org/@nuxt/test-utils/-/test-utils-3.19.2.tgz", - "integrity": "sha512-jvpCbTNd1e8t2vrGAMpVq8j7N25Jao0NpblRiIYwogXgNXOPrH1XBZxgufyLA701g64SeiplUe+pddtnJnQu/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nuxt/kit": "^3.17.5", - "c12": "^3.0.4", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "estree-walker": "^3.0.3", - "fake-indexeddb": "^6.0.1", - "get-port-please": "^3.1.2", - "h3": "^1.15.3", - "local-pkg": "^1.1.1", - "magic-string": "^0.30.17", - "node-fetch-native": "^1.6.5", - "node-mock-http": "^1.0.1", - "ofetch": "^1.4.1", - "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "radix3": "^1.1.2", - "scule": "^1.3.0", - "std-env": "^3.9.0", - "tinyexec": "^1.0.1", - "ufo": "^1.6.1", - "unplugin": "^2.3.5", - "vitest-environment-nuxt": "^1.0.1", - "vue": "^3.5.17" + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "@cucumber/cucumber": "^10.3.1 || ^11.0.0", - "@jest/globals": "^29.5.0 || ^30.0.0", - "@playwright/test": "^1.43.1", - "@testing-library/vue": "^7.0.0 || ^8.0.1", - "@vue/test-utils": "^2.4.2", - "happy-dom": "^9.10.9 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "jsdom": "^22.0.0 || ^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0", - "playwright-core": "^1.43.1", - "vitest": "^3.2.0" + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "@cucumber/cucumber": { + "@types/node": { "optional": true }, - "@jest/globals": { + "jiti": { "optional": true }, - "@playwright/test": { + "less": { "optional": true }, - "@testing-library/vue": { + "lightningcss": { "optional": true }, - "@vitest/ui": { + "sass": { "optional": true }, - "@vue/test-utils": { + "sass-embedded": { "optional": true }, - "happy-dom": { + "stylus": { "optional": true }, - "jsdom": { + "sugarss": { "optional": true }, - "playwright-core": { + "terser": { "optional": true }, - "vitest": { + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/@nuxt/test-utils/node_modules/@nuxt/kit": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.19.1.tgz", - "integrity": "sha512-cLKNdmfFk49o9Tt7g+vwD9rYN7cLg0D6K6CRB+4aaQYxveJXQbZGgZ4z7CGq5HxIG22Ki8G3XSXaiN1s6lVyZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "c12": "^3.2.0", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.7", - "ignore": "^7.0.5", - "jiti": "^2.5.1", - "klona": "^2.0.6", - "knitwork": "^1.2.0", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^2.1.2", - "scule": "^1.3.0", - "semver": "^7.7.2", - "std-env": "^3.9.0", - "tinyglobby": "^0.2.14", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "unimport": "^5.2.0", - "untyped": "^2.0.0" - }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", "engines": { - "node": ">=18.12.0" + "node": ">=8.0.0" } }, - "node_modules/@nuxt/test-utils/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/test-utils/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", + "node_modules/@opentelemetry/api-logs": { + "version": "0.217.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.217.0.tgz", + "integrity": "sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==", + "license": "Apache-2.0", "dependencies": { - "@types/estree": "^1.0.0" + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@nuxt/test-utils/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz", + "integrity": "sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==", + "license": "Apache-2.0", "engines": { - "node": ">= 4" + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@nuxt/test-utils/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", - "dev": true, - "license": "MIT", + "node_modules/@opentelemetry/core": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", + "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", + "license": "Apache-2.0", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@nuxt/test-utils/node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/vite-builder": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-4.1.1.tgz", - "integrity": "sha512-hRIHu9a1x2HFFSXQt3+eG4s8GP1QhuzjiCmd/sciC55NISc0oP69tTmOmFOp3L8G2BapSZ/O1CZEnO/XoAqZkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nuxt/kit": "4.1.1", - "@rollup/plugin-replace": "^6.0.2", - "@vitejs/plugin-vue": "^6.0.1", - "@vitejs/plugin-vue-jsx": "^5.1.1", - "autoprefixer": "^10.4.21", - "consola": "^3.4.2", - "cssnano": "^7.1.1", - "defu": "^6.1.4", - "esbuild": "^0.25.9", - "escape-string-regexp": "^5.0.0", - "exsolve": "^1.0.7", - "get-port-please": "^3.2.0", - "h3": "^1.15.4", - "jiti": "^2.5.1", - "knitwork": "^1.2.0", - "magic-string": "^0.30.18", - "mlly": "^1.8.0", - "mocked-exports": "^0.1.1", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "postcss": "^8.5.6", - "rollup-plugin-visualizer": "^6.0.3", - "std-env": "^3.9.0", - "ufo": "^1.6.1", - "unenv": "^2.0.0-rc.19", - "vite": "^7.1.4", - "vite-node": "^3.2.4", - "vite-plugin-checker": "^0.10.3", - "vue-bundle-renderer": "^2.1.2" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vue": "^3.3.4" - } - }, - "node_modules/@nuxt/vite-builder/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nuxt/vite-builder/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nuxt/vite-builder/node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nuxt/vite-builder/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nuxt/vite-builder/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" - } - }, - "node_modules/@nuxt/vite-builder/node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nuxt/vite-builder/node_modules/vite-plugin-checker": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.10.3.tgz", - "integrity": "sha512-f4sekUcDPF+T+GdbbE8idb1i2YplBAoH+SfRS0e/WRBWb2rYb1Jf5Pimll0Rj+3JgIYWwG2K5LtBPCXxoibkLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "chokidar": "^4.0.3", - "npm-run-path": "^6.0.0", - "picocolors": "^1.1.1", - "picomatch": "^4.0.3", - "strip-ansi": "^7.1.0", - "tiny-invariant": "^1.3.3", - "tinyglobby": "^0.2.14", - "vscode-uri": "^3.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "peerDependencies": { - "@biomejs/biome": ">=1.7", - "eslint": ">=7", - "meow": "^13.2.0", - "optionator": "^0.9.4", - "stylelint": ">=16", - "typescript": "*", - "vite": ">=2.0.0", - "vls": "*", - "vti": "*", - "vue-tsc": "~2.2.10 || ^3.0.0" - }, - "peerDependenciesMeta": { - "@biomejs/biome": { - "optional": true - }, - "eslint": { - "optional": true - }, - "meow": { - "optional": true - }, - "optionator": { - "optional": true - }, - "stylelint": { - "optional": true - }, - "typescript": { - "optional": true - }, - "vls": { - "optional": true - }, - "vti": { - "optional": true - }, - "vue-tsc": { - "optional": true - } - } - }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" - } - }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.217.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.217.0.tgz", - "integrity": "sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz", - "integrity": "sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", - "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.217.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.217.0.tgz", - "integrity": "sha512-24ucQMjz7Y34Kw3trbxL2ZrssbtgWnR+Clpaa+YdeWuuyH3Cvk23Q03PcQvqiZrDvt8AmQmjgg9v6Y9PHoxG7w==", - "license": "Apache-2.0", + "node_modules/@opentelemetry/instrumentation": { + "version": "0.217.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.217.0.tgz", + "integrity": "sha512-24ucQMjz7Y34Kw3trbxL2ZrssbtgWnR+Clpaa+YdeWuuyH3Cvk23Q03PcQvqiZrDvt8AmQmjgg9v6Y9PHoxG7w==", + "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.217.0", "import-in-the-middle": "^3.0.0", @@ -5101,18 +4574,35 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", - "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", "license": "Apache-2.0", "engines": { "node": ">=14" } }, + "node_modules/@oxc-minify/binding-android-arm-eabi": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.133.0.tgz", + "integrity": "sha512-D8M1+nqwLaACHZsld/t6f+cE4N97XOu5iQ88f1ZaYH4ptFzFrXo5N7wUKACTI4xmNUD+6W0Y4Apk5U2r8HLdBQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-minify/binding-android-arm64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.86.0.tgz", - "integrity": "sha512-jOgbDgp6A1ax9sxHPRHBxUpxIzp2VTgbZ/6HPKIVUJ7IQqKVsELKFXIOEbCDlb1rUhZZtGf53MFypXf72kR5eQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.133.0.tgz", + "integrity": "sha512-dnQUJdpOEh/nZfQtvGGN61VcCCcPJ2aCm+ndl8GIA2lk2GpmIBgZ9h+phLVhgUFGt2es+2AQc0xvtK7RFNsViw==", "cpu": [ "arm64" ], @@ -5123,13 +4613,13 @@ "android" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-darwin-arm64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.86.0.tgz", - "integrity": "sha512-LQkjIHhIzxVYnxfC2QV7MMe4hgqIbwK07j+zzEsNWWfdmWABw11Aa6FP0uIvERmoxstzsDT77F8c/+xhxswKiw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.133.0.tgz", + "integrity": "sha512-K6+aXlOlsCcibpTiTitQYNXWGGwea0fEKF/kGHCNB+MNqOLCkdC7wesycaABYcXcyr58DhDoJnVb8E4Hq95iVw==", "cpu": [ "arm64" ], @@ -5140,13 +4630,13 @@ "darwin" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-darwin-x64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.86.0.tgz", - "integrity": "sha512-AuLkeXIvJ535qOhFzZfHBkcEZA59SN1vKUblW2oN+6ClZfIMru0I2wr0cCHA9QDxIVDkI7swDu29qcn2AqKdrg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.133.0.tgz", + "integrity": "sha512-BFEXHxYNwThyaO63p1VE5MOOXNGkHsHfkmajOCKXH40TfllTHQenXhpJ9mHDoF7EhaQjArpPjlDY88BuPjhurw==", "cpu": [ "x64" ], @@ -5157,13 +4647,13 @@ "darwin" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-freebsd-x64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.86.0.tgz", - "integrity": "sha512-UcXLcM8+iHW1EL+peHHV1HDBFUVdoxFMJC7HBc2U83q9oiF/K73TnAEgW/xteR+IvbV/9HD+cQsH+DX6oBXoQg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.133.0.tgz", + "integrity": "sha512-oT5dbcXnS/cbpdXCpudAeVg/fqH1XnKhLUE/vkuRTuocjOd/GA2MoNMMhLWUvqNXO0xJnYmo2ISmDxShkItfOQ==", "cpu": [ "x64" ], @@ -5174,13 +4664,13 @@ "freebsd" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-linux-arm-gnueabihf": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.86.0.tgz", - "integrity": "sha512-UtSplQY10Idp//cLS5i2rFaunS71padZFavHLHygNAxJBt+37DPKDl/4kddpV6Kv2Mr6bhw2KpXGAVs0C3dIOw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.133.0.tgz", + "integrity": "sha512-tJ3B+b7DOuTsIMXSmu5xHHCakrBqqcrp4COYd/lelOdDvkbFoDRGnwH91POUOSUEOI/WLzIMkDqAH2SZ3N2jhQ==", "cpu": [ "arm" ], @@ -5191,13 +4681,13 @@ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-linux-arm-musleabihf": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.86.0.tgz", - "integrity": "sha512-P5efCOl9QiwqqJHrw1Q+4ssexvOz+MAmgTmBorbdEM3WJdIHR1CWGDj4GqcvKBlwpBqt4XilOuoN0QD8dfl85A==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.133.0.tgz", + "integrity": "sha512-XMUHfdilk1KTtOM2vA1bwDso07/wkLm/GgDOO9z/ioxrZoQyjXnJRW665VXa08z2BqEgwHRc1zH9p7s6sKPQbg==", "cpu": [ "arm" ], @@ -5208,115 +4698,190 @@ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-linux-arm64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.86.0.tgz", - "integrity": "sha512-hwHahfs//g9iZLQmKldjQPmnpzq76eyHvfkmdnXXmPtwTHnwXL1hPlNbTIqakUirAsroBeQwXqzHm3I040R+mg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.133.0.tgz", + "integrity": "sha512-UEff2jopbwJ4SndmxK06uqXrOpwWiJERJPdgDTBywwXP9QgW0p1YkQnBNt4+jK0I/hdLpbbyaCLLuUPKbaU70w==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-linux-arm64-musl": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.86.0.tgz", - "integrity": "sha512-S2dL24nxWqDCwrq48xlZBvhSIBcEWOu3aDOiaccP4q73PiTLrf6rm1M11J7vQNSRiH6ao9UKr7ZMsepCZcOyfA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.133.0.tgz", + "integrity": "sha512-yqskeIapQvx7Tu/OLsepLPcGsHGzfYy9PX6gIbhaOHfF+LA2zHBKnKb587FGx+lQjHLQR0llfmoSuXQ6q2EN+A==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-minify/binding-linux-riscv64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.86.0.tgz", - "integrity": "sha512-itZ24A1a5NOw0ibbt6EYOHdBojfV4vbiC209d06Dwv5WLXtntHCjc8P4yfrCsC22uDmMPNkVa+UL+OM4mkUrwg==", + "node_modules/@oxc-minify/binding-linux-ppc64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.133.0.tgz", + "integrity": "sha512-r7PnUNxRB9D/gQjCVeasoieJVUF48n43rvk/jYbGAw9sRfYGoEo/rOs0GyTZU9ttss8HzjBaerAbADbAL8K8vw==", "cpu": [ - "riscv64" + "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-minify/binding-linux-s390x-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.86.0.tgz", - "integrity": "sha512-/nJAwS/uit19qXNpaOybf7GYJI7modbXYVZ8q1pIFdxs6HkhZLxS1ZvcIzY3W75+37u+uKeZ4MbygawAN8kQpQ==", + "node_modules/@oxc-minify/binding-linux-riscv64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.133.0.tgz", + "integrity": "sha512-omXWC8I9lAMMjQIeadfItP5H4VDAiuU2BiVCtHMH3ktTbFq04sxscZhK4NFUUuw3fApDdXmfd7LW18q0JBHarg==", "cpu": [ - "s390x" + "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-minify/binding-linux-x64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.86.0.tgz", - "integrity": "sha512-3qnWZB2cOj5Em/uEJqJ1qP/8lxtoi/Rf1U8fmdLzPW5zIaiTRUr/LklB4aJ+Vc/GU5g3HX5nFPQG3ZnEV3Ktzg==", + "node_modules/@oxc-minify/binding-linux-riscv64-musl": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.133.0.tgz", + "integrity": "sha512-LtFA3Hi8LVD/zuiPLKy9Aiz7N1IOj8rRhdXiW38GKQ9mAhj+Ko6IHGcTk2A7yNDA1DZBl7r+Qd4PEGWgVelPPw==", "cpu": [ - "x64" + "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-s390x-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.133.0.tgz", + "integrity": "sha512-rFsPDsT1j3beSInbrFukAAlTg101PcqdVMXDioR9AgJ1180tZ8s8D+pNDpQTRmPd3956mnpAE+Cs77Xoo/QZAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-x64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.133.0.tgz", + "integrity": "sha512-xlrtAmDWZI8BEmsaXMYfblWuLIY5UnnRkit1VLkmVDb5ceZRZf4oEXK1QeYf5Z33dT0WK1Ek++P+TL/ZMCpyGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-linux-x64-musl": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.86.0.tgz", - "integrity": "sha512-+ZqYG8IQSRq9dR2djrnyzGHlmwGRKdueVjHYbEOwngb/4h/+FxAOaNUbsoUsCthAfXTrZHVXiQMTKJ32r7j2Bg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.133.0.tgz", + "integrity": "sha512-kd36CDkTkZDMNfVceNTSfpWnitE1+GjZmzJCeq8yaxsgvs/MXg8aauI2RgFjElYZIHSMyZku4pQ7Jtl3ZEYI6w==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-openharmony-arm64": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.133.0.tgz", + "integrity": "sha512-pI38dJBqfkNbFoL/GEarAzGDjKGVCZTdg0a8NKh1PP9GqWleXT6HLtXE4CZ+54e+2u68qVYVBwhbWAiRfwlUZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-wasm32-wasi": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.86.0.tgz", - "integrity": "sha512-ixeSZW7jzd3g9fh8MoR9AzGLQxMCo//Q2mVpO2S/4NmcPtMaJEog85KzHULgUvbs70RqxTHEUqtVgpnc/5lMWA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.133.0.tgz", + "integrity": "sha512-AkLr+d+LLY4/55J/TrE0srNBUpZPzyU+cygdse7yZ9AhCndryNqe2y6e8naVK0TV7n8lxBd2OGGJAkho6blAkw==", "cpu": [ "wasm32" ], @@ -5324,16 +4889,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.3" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-win32-arm64-msvc": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.86.0.tgz", - "integrity": "sha512-cN309CnFVG8jeSRd+lQGnoMpZAVmz4bzH4fgqJM0NsMXVnFPGFceG/XiToLoBA1FigGQvkV0PJ7MQKWxBHPoUA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.133.0.tgz", + "integrity": "sha512-V92v7397t2073g+mSfaLHnPeoz6hA/1U4JNLeUBP87eWGZgVxDZ2qz3t3wFyYqXGJ/0VoEwdP8yrHLQQ7QzAOQ==", "cpu": [ "arm64" ], @@ -5344,13 +4911,30 @@ "win32" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-win32-ia32-msvc": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.133.0.tgz", + "integrity": "sha512-2DP5RbG/SSaRVtmuwgTH6Ati4+uuOJjoI88dQnC5hD0zCC90EVDXZSXyJQ5i/OxLE1UAy58Wo2DJot/OrUspzA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-minify/binding-win32-x64-msvc": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.86.0.tgz", - "integrity": "sha512-YAqCKtZ9KKhSW73d/Oa9Uut0myYnCEUL2D0buMjJ4p0PuK1PQsMCJsmX4ku0PgK31snanZneRwtEjjNFYNdX2A==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.133.0.tgz", + "integrity": "sha512-PJ75c6PlBx87tau0W35J43eGCv4wrDmdZ+4ddTZAnGtZqEeCVsLdmDPOEMe2DepogqlSVUF2kGBWtnFUJ5c7Rw==", "cpu": [ "x64" ], @@ -5361,13 +4945,30 @@ "win32" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.133.0.tgz", + "integrity": "sha512-l/44caGse+VpnY9gx0yvvc5QnnG3yG1FO3KZgYvNL1GZrfK86zIwAOgGEVlxDyRymzrU/KHiblPFpevKOmJmUA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-android-arm64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.86.0.tgz", - "integrity": "sha512-BfNFEWpRo4gqLHKvRuQmhbPGeJqB1Ka/hsPhKf1imAojwUcf/Dr/yRkZBuEi2yc1LWBjApKYJEqpsBUmtqSY1Q==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.133.0.tgz", + "integrity": "sha512-KUHmPMziLBp4u+zbrLdB7iWS7KshuZe+RAp7ELnY9SI9nNXBZ+dp8fiBqWOxhXqn+FQg3a4UcQhwmsJOKV8Jjg==", "cpu": [ "arm64" ], @@ -5378,13 +4979,13 @@ "android" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-darwin-arm64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.86.0.tgz", - "integrity": "sha512-gRSnEHcyNEfLdNj6v8XKcuHUaZnRpH2lOZFztuGEi23ENydPOQVEtiZYexuHOTeaLGgzw+93TgB4n/YkjYodug==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.133.0.tgz", + "integrity": "sha512-q8dWmnU/8ea2tga9w2f1PinQ5rcMPDUGkF64T189b65YMjUomET4oy5oRldOr4AwOQkneOG/Zttnz1Dvrc62wg==", "cpu": [ "arm64" ], @@ -5395,13 +4996,13 @@ "darwin" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-darwin-x64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.86.0.tgz", - "integrity": "sha512-6mdymm8i+VpLTJP19D3PSFumMmAyfhhhIRWcRHsc0bL7CSZjCWbvRb00ActKrGKWtsol/A/KKgqglJwpvjlzOA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.133.0.tgz", + "integrity": "sha512-cOKeIELIB2bJnCKwqx4Rdj+1Lss/U6uCbLxRySZrhyOOQa1flKhwZFjEHRHxk8fU1NKmhK5OnTdPQ4CpjuFuVw==", "cpu": [ "x64" ], @@ -5412,13 +5013,13 @@ "darwin" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-freebsd-x64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.86.0.tgz", - "integrity": "sha512-mc2xYRPxhzFg4NX1iqfIWP+8ORtXiNpAkaomNDepegQFlIFUmrESa3IJrKJ/4vg77Tbti7omHbraOqwdTk849g==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.133.0.tgz", + "integrity": "sha512-OpaSv4pW3KgFrMYQxTaS0aOE4T1DQF3qZE/4B6uqqv1KgPWWd4UQhJALi8PJPX1RRV5K7ThKXRfF7qGg2+3l1A==", "cpu": [ "x64" ], @@ -5429,13 +5030,13 @@ "freebsd" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.86.0.tgz", - "integrity": "sha512-LZzapjFhwGQMKefcFsn3lJc/mTY37fBlm0jjEvETgNCyd5pH4gDwOcrp/wZHAz2qw5uLWOHaa69I6ci5lBjJgA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.133.0.tgz", + "integrity": "sha512-JGK1wlGrGwxBIlVSF7KWTX1/ru6BEtf28fRROztDRkLfiW+Kxa4onnriezMIiogfn9hVw2KzYcKiLjkLR2ns8A==", "cpu": [ "arm" ], @@ -5446,13 +5047,13 @@ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.86.0.tgz", - "integrity": "sha512-/rhJMpng7/Qgn8hE4sigxTRb04+zdO0K1kfAMZ3nONphk5r2Yk2RjyEpLLz17adysCyQw/KndaMHNv8GR8VMNg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.133.0.tgz", + "integrity": "sha512-yuZO533Ftonxn/iyoqQzURzLQHMspvsIyfiCSNi1t/ER4eIQaR0SsmUOUm5b/lmSig7IWIUa5/BrbEkAPwcilQ==", "cpu": [ "arm" ], @@ -5463,115 +5064,190 @@ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-arm64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.86.0.tgz", - "integrity": "sha512-IXEZnk6O0zJg5gDn1Zvt5Qx62Z3E+ewrKwPgMfExqnNCLq+Ix2g7hQypevm/S6qxVgyz5HbiW+a/5ziMFXTCJQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.133.0.tgz", + "integrity": "sha512-hvpbqT5pN2rR+3+xtWeizwfR/aZ0vGceg6TqYMl+ToxMpk9/tmnX7kSvQnfEUkoua8mhogzvIKsAkn0wxgblBA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-arm64-musl": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.86.0.tgz", - "integrity": "sha512-QG7DUVZ/AtBaUGMhgToB4glOdq0MGAEYU1MJQpNB5HqiEcOpteF9Pd+oPfscj2zrGPd47KNyljtJRBKJr6Ut0w==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.133.0.tgz", + "integrity": "sha512-wJQGamIosQBoJHW9+S5XxrtKRo3eyJxsnS1XCPrqN0LHi8uw1pTqqTfn3t/NVuvbBg7Pumn4ez9Eidgcn0xbEg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.133.0.tgz", + "integrity": "sha512-Koaz32/O5+abIfrNGdyndgRvdOZ9jEf5/z3Ep9h3h2QWpdDiUQpVwgH0OcMXCs+l9aXxPLtkupqyVig9W6FDKw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.86.0.tgz", - "integrity": "sha512-smz+J6riX2du2lp0IKeZSaOBIhhoE2N/L1IQdOLCpzB0ikjCDBoyNKdDM7te8ZDq3KDnRmJChmhQGd8P1/LGBQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.133.0.tgz", + "integrity": "sha512-R4vOjWzxhnNWHnVLeiB6jNuIifdy9vcMXZGPc7StXcxBovI+U2zg1QhZ9o8OjV80oGivs1lX5NfPLzk4IPqlRA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.133.0.tgz", + "integrity": "sha512-iwgBNUTHiMdxARLYuM0SBlnYeb19iw1Ea5M+4ERZupCsBMLArti6FyZ6UfFjJxIiTDr2oW2DGQFxlQVQ/dW9rA==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-s390x-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.86.0.tgz", - "integrity": "sha512-vas1BOMWVdicuimmi5Y+xPj3csaYQquVA45Im9a/DtVsypVeh8RWYXBMO1qJNM5Fg5HD0QvYNqxvftx3c+f5pg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.133.0.tgz", + "integrity": "sha512-ZwZNo8FZmB/gVfboQl+wXilBigGl+6nQQs+nITOeAP/HcAOjiHl6XZJL9F/KXNEspODQcbjAiyjUbeCJd9a0fA==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-x64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.86.0.tgz", - "integrity": "sha512-3Fsi+JA3NwdZdrpC6AieOP48cuBrq0q59JgnR0mfoWfr9wHrbn2lt8EEubrj6EXpBUmu1Zii7S9NNRC6fl/d+w==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.133.0.tgz", + "integrity": "sha512-govCvWx1dBlED3uu4qXctxpRcouu9I8Kn+DBktGCl760JtlGJzc9l/OmPJKlYWSbrRqKkMZehNeZ/4Wfma7uSA==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-linux-x64-musl": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.86.0.tgz", - "integrity": "sha512-89/d43EW76wJagz8u5zcKW8itB2rnS/uN7un5APb8Ebme8TePBwDyxo64J6oY5rcJYkfJ6lEszSF/ovicsNVPw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.133.0.tgz", + "integrity": "sha512-ssTlpXD5Mq9uCssDJPzlRWqBt4Y7Zzd9i+XZhWmK/9Y6KUIuAxVYTYiI8lxcGWi0+3/Cz4A8q9UrD4NK9Y2j7g==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.133.0.tgz", + "integrity": "sha512-51aByfXhPtLEdWG4a2Ihdw6cPWV1ei1AarALpFdDP8MLWDLE2NuUMgbo3DERR2Kt8fT/ok1GUvBiLxVGke9uUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-wasm32-wasi": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.86.0.tgz", - "integrity": "sha512-gRrGmE2L27stNMeiAucy/ffHF9VjYr84MizuJzSYnnKmd5WXf3HelNdd0UYSJnpb7APBuyFSN2Oato+Qb6yAFw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.133.0.tgz", + "integrity": "sha512-2e16tkKp+wDO2GTAmXfxbBcCmGEaFPIJEIRBBmVKNVXSc8/fJsSIaBGyFTPHM9ST5GNWgJcYIt94rDTks+PLwA==", "cpu": [ "wasm32" ], @@ -5579,16 +5255,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.3" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-parser/binding-win32-arm64-msvc": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.86.0.tgz", - "integrity": "sha512-parTnpNviJYR3JIFLseDGip1KkYbhWLeuZG9OMek62gr6Omflddoytvb17s+qODoZqFAVjvuOmVipDdjTl9q3Q==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.133.0.tgz", + "integrity": "sha512-KPTNDKbxH1cglrqTyVeXHb4Pk4oksz8EcE1/v8zqU7N4UXbiHfA/IwtXZ2U77fnRAWBbgVkl/lZbL7o3hRdejg==", "cpu": [ "arm64" ], @@ -5599,15 +5277,15 @@ "win32" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-parser/binding-win32-x64-msvc": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.86.0.tgz", - "integrity": "sha512-FTso24eQh3vPTe/SOTf0/RXfjJ13tsk5fw728fm+z5y6Rb+mmEBfyVT6XxyGhEwtdfnRSZawheX74/9caI1etw==", + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.133.0.tgz", + "integrity": "sha512-Una1bNYv9zCavQrfnDR9wuZVB3itLjCEH4Oz7i6CwAJN/Xq9b+zbbcxmvdkKvvJt4Ngc/MBmIYlbLo3zS4TQ0A==", "cpu": [ - "x64" + "ia32" ], "dev": true, "license": "MIT", @@ -5616,33 +5294,57 @@ "win32" ], "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-project/runtime": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", - "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.133.0.tgz", + "integrity": "sha512-kjBhCiOGSYTwDJQuuZa7a94JbP8htWu7J0X1KwH74kV2K5eYf6eyJRYmkpCDvr0XEL8tMxYI4WU1VekblFCLgg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-project/types": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.86.0.tgz", - "integrity": "sha512-bJ57vWNQnOnUe5ZxUkrWpLyExxqb0BoyQ+IRmI/V1uxHbBNBzFGMIjKIf5ECFsgS0KgUUl8TM3a4xpeAtAnvIA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@oxc-transform/binding-android-arm-eabi": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm-eabi/-/binding-android-arm-eabi-0.133.0.tgz", + "integrity": "sha512-2A79NBpyBKgHJ0FwgC8D1hzp3x2ujyvqq/kG+M76YyDMMkxLhX6A3vjnAnfEKycOoZxuKhwYu8BF9hKq67ykIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-transform/binding-android-arm64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.86.0.tgz", - "integrity": "sha512-025JJoCWi04alNef6WvLnGCbx2MH9Ld2xvr0168bpOcpBjxt8sOZawu0MPrZQhnNWWiX8rrwrhuUDasWCWHxFw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.133.0.tgz", + "integrity": "sha512-dynEph/hyoSgBzd2XbNlW37NK97nU6tZMs5jrhObUxSasBV/Gv9THZrWj9AlbWiMXR07WFYE82C9axjntYyBSw==", "cpu": [ "arm64" ], @@ -5653,13 +5355,13 @@ "android" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-darwin-arm64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.86.0.tgz", - "integrity": "sha512-dJls3eCO1Y2dc4zAdA+fiRbQwlvFFDmfRHRpGOllwS1FtvKQ7dMkRFKsHODEdxWakxISLvyabUmkGOhcJ47Dog==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.133.0.tgz", + "integrity": "sha512-4hGgKOG+dZSN3xjcgNWpcihekRG7/YbbAdjyz07yv0HjzA6kdqYAhGrn84374UPO2h6etYJwsCBoM9iJHHvJ8w==", "cpu": [ "arm64" ], @@ -5670,13 +5372,13 @@ "darwin" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-darwin-x64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.86.0.tgz", - "integrity": "sha512-udMZFZn6FEy36tVMs/yrczEqWyCJc+l/lqIMS4xYWsm/6qVafUWDSAZJLgcPilng16IdMnHINkc8NSz7Pp1EVw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.133.0.tgz", + "integrity": "sha512-7J11/9PFkznmKuANkCAjt3znV1BcDFXQSgDiBvDxXT3Wm6995/zxrJD5zmo+5XSgY4sm+2V8/ED6ZSD3mKOC5A==", "cpu": [ "x64" ], @@ -5687,13 +5389,13 @@ "darwin" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-freebsd-x64": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.86.0.tgz", - "integrity": "sha512-41J5qSlypbE0HCOd+4poFD96+ZKoR8sfDn5qdaU0Hc5bT5Drwat/wv06s9Y5Lu86uXYTwPPj6kbbxHHsiV2irw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.133.0.tgz", + "integrity": "sha512-5EMAO0vzCpUfhn6aSjIUeJeRI2ztevHwSVr/M8sZ2VBYc79UuOfjjMCQ67LtUbgpvQtpBWkzeAHCP3L7JFYmlg==", "cpu": [ "x64" ], @@ -5704,13 +5406,13 @@ "freebsd" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-linux-arm-gnueabihf": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.86.0.tgz", - "integrity": "sha512-mrI+nKgwRsr4FYjb0pECrNTVnNvHAflukS3SFqFHI8n+3LJgrCYDcnbrFD/4VWKp2EUrkIZ//RhwgGsTiSXbng==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.133.0.tgz", + "integrity": "sha512-z6XT8tmo9sPmCIYaFIxDelBU4wXLwwWMX2VNCMIY6bkQp5r+kRtVXYS3yLbJHMKEhRKvw/g+Z7fO9aadsGGEAw==", "cpu": [ "arm" ], @@ -5721,13 +5423,13 @@ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-linux-arm-musleabihf": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.86.0.tgz", - "integrity": "sha512-FXWyvpxiEXBewA3L6HGFtEribqFjGOiounD8ke/4C1F5134+rH5rNrgK6vY116P4MtWKfZolMRdvlzaD3TaX0A==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.133.0.tgz", + "integrity": "sha512-GQDpEV2VhHG8hT5BviDv+emi9oHYhfv+JJJWROYp+eGgWjiQMp4QZVb6Bu3kwVMzkwy0r200ToA1KThYTq53ug==", "cpu": [ "arm" ], @@ -5738,115 +5440,190 @@ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-linux-arm64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.86.0.tgz", - "integrity": "sha512-gktU/9WLAc0d2hAq8yRi3K92xwkWoDt1gJmokMOfb1FU4fyDbzbt13jdZEd6KVn2xLaiQeaFTTfFTghFsJUM3A==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.133.0.tgz", + "integrity": "sha512-VstR+NEQAJb80ysWk2vPjEvg0JzwEjKn2hDbC/joa5zGXkCnVVCWgAGG8c6o23S981a7XRpCMcClBgeD1q9H2A==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-linux-arm64-musl": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.86.0.tgz", - "integrity": "sha512-2w5e5qiTBYQ0xc1aSY1GNyAOP9BQFEjN43FI3OhrRWZXHOj3inqcVSlptO/hHGK3Q2bG26kWLfSNFOEylTX39A==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.133.0.tgz", + "integrity": "sha512-Ec7xJdDrnukgiz20E3iDNzAIgx1XXn8cVVsNNUpgEIAvNlXZaocqlQT8Zalk0Lv3fbkxcJ+9BuWB0ndBRHQtzg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-transform/binding-linux-riscv64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.86.0.tgz", - "integrity": "sha512-PfnTYm+vQ9X5VNXqs0Z3S67Xp2FoZj5RteYKUNwL+j/sxGi05eps+EWLVrcGsuN9x2GHFpTiqBz3lzERCn2USg==", + "node_modules/@oxc-transform/binding-linux-ppc64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.133.0.tgz", + "integrity": "sha512-6YX38grimcigz20eYpyz6e4c9rDKzwK3i+tcDpgwYj0bWreaAOwrABmSmKplPJOorkDVlbT69wPCN+d11irBQw==", "cpu": [ - "riscv64" + "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-transform/binding-linux-s390x-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.86.0.tgz", - "integrity": "sha512-uHgGN0rFfqDcdkLUITshqrpV34PRKAiRwsw6Jgkg7CRcRGIU8rOJc568EU0jfhTZ1zO5MJKt/S8D6cgIFJwe0A==", + "node_modules/@oxc-transform/binding-linux-riscv64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.133.0.tgz", + "integrity": "sha512-WxMIzItRJR66lgaAyyqj0FFwLMpcuCV9mTFcUMQpIz8+Hey1Enk8xuv+7QpSsqCR5zRlwNr092dsFkz5cbvtrw==", "cpu": [ - "s390x" + "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-transform/binding-linux-x64-gnu": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.86.0.tgz", - "integrity": "sha512-MtrvfU2RkSD+oTnzG4Xle3jK8FXJPQa1MhYQm0ivcAMf0tUQDojTaqBtM/9E0iFr/4l1xZODJOHCGjLktdpykg==", + "node_modules/@oxc-transform/binding-linux-riscv64-musl": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.133.0.tgz", + "integrity": "sha512-+x6dnO87986rjVNjcF0tg8wVS0e/SH8nzLa/X0Wsh7jtEniN7buvR8iqZm8pnsfaZ8DH5F4GCSZpoPRrd9jJ6w==", "cpu": [ - "x64" + "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-transform/binding-linux-x64-musl": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.86.0.tgz", - "integrity": "sha512-wTTTIPcnoS04SRJ7HuOL/VxIu1QzUtv2n6Mx0wPIEQobj2qPGum0qYGnFEMU0Njltp+8FAUg5EfX6u3udRQBbQ==", + "node_modules/@oxc-transform/binding-linux-s390x-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.133.0.tgz", + "integrity": "sha512-oEyQudXIwWM/+v0vZzPbAi25YMWyvjtQYYjuSrhMEQwe7ZEMDXscX7U1j6alrVdZq2DtCMeror3X/Dv7p/JUwg==", "cpu": [ - "x64" + "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-linux-x64-gnu": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.133.0.tgz", + "integrity": "sha512-G8P/OadKTbyUHz5TK63sDDtUHwn2SXG/o0oGo4GGTzBu70xmUSN5/ZUgpyl6ypAmbshoyw8nC7+msb3BjzHxaA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-linux-x64-musl": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.133.0.tgz", + "integrity": "sha512-Oi/fyOzZ+aytmmsRND5pGgvux4n++v9cG4qNFiXj7qFwSqBKWZHBq7cJLXqbH1I81pyI3kvU1Za+1qk3afXuwg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-openharmony-arm64": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-openharmony-arm64/-/binding-openharmony-arm64-0.133.0.tgz", + "integrity": "sha512-/ZElgq+/tcga27X2G2AUpxcYX0baX94Gz658w6Zz2P+6Kr06bfYSrdtC0P7oPrbu3Gy/6kpiSoJPgZy8R2IjYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-wasm32-wasi": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.86.0.tgz", - "integrity": "sha512-g+0bf+ZA2DvBHQ+0u8TvEY8ERo86Brqvdghfv06Wph2qGTlhzSmrE0c0Zurr7yhtqI5yZjMaBr2HbqwW1kHFng==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.133.0.tgz", + "integrity": "sha512-GANcoEa8Nzza7saxdb4qWO24U6jk4nK6G+g87lGp8TTU45CUvWf1Igdze2+NrebgiwOy6F1/h6Esag4DM3JTtQ==", "cpu": [ "wasm32" ], @@ -5854,16 +5631,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.3" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-win32-arm64-msvc": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.86.0.tgz", - "integrity": "sha512-dgBeU4qBEag0rhW3OT9YHgj4cvW51KZzrxhDQ1gAVX2fqgl+CeJnu0a9q+DMhefHrO3c8Yxwbt7NxUDmWGkEtg==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.133.0.tgz", + "integrity": "sha512-2+uDo/+ZvGQu10J8xryg/l5PdBt2vXPtf+0aIosVKJavqCaKcBDdo95OUaEulx0bqvoytAQ4yyz2gcPZ40mjcQ==", "cpu": [ "arm64" ], @@ -5874,13 +5653,30 @@ "win32" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-win32-ia32-msvc": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.133.0.tgz", + "integrity": "sha512-zpPIZ1S3JHmSEFyyGyPYCwhOiNLyfaPifYxK8BQY21JXyHglu/wUr3/ESFrXb+XegEy/iBlWbzr3FzPtcq1MUw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@oxc-transform/binding-win32-x64-msvc": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.86.0.tgz", - "integrity": "sha512-M1eCl8xz7MmEatuqWdr+VdvNCUJ+d4ECF+HND39PqRCVkaH+Vl1rcyP5pLILb2CB/wTb2DMvZmb9RCt5+8S5TQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.133.0.tgz", + "integrity": "sha512-cADrfLvc/VeyvpvQS+t5ktqfyqyyGANZC5NHp++JAElacfXqq/+k8bYkjqMWzNZ3HxkJtL1qDHfZZCA9+4hlSQ==", "cpu": [ "x64" ], @@ -5891,20 +5687,27 @@ "win32" ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@package-json/types": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@package-json/types/-/types-0.0.12.tgz", + "integrity": "sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==", + "dev": true, + "license": "MIT" + }, "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { - "detect-libc": "^1.0.3", + "detect-libc": "^2.0.3", "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">= 10.0.0" @@ -5914,25 +5717,25 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", "cpu": [ "arm64" ], @@ -5950,9 +5753,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", "cpu": [ "arm64" ], @@ -5970,9 +5773,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", "cpu": [ "x64" ], @@ -5990,9 +5793,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", "cpu": [ "x64" ], @@ -6010,12 +5813,15 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6030,12 +5836,15 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", "cpu": [ "arm" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6050,12 +5859,15 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6070,12 +5882,15 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6090,12 +5905,15 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6110,12 +5928,15 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6130,17 +5951,17 @@ } }, "node_modules/@parcel/watcher-wasm": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.1.tgz", - "integrity": "sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.6.tgz", + "integrity": "sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==", "bundleDependencies": [ "napi-wasm" ], "license": "MIT", "dependencies": { "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "napi-wasm": "^1.1.0" + "napi-wasm": "^1.1.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">= 10.0.0" @@ -6156,9 +5977,9 @@ "license": "MIT" }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", "cpu": [ "arm64" ], @@ -6176,9 +5997,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", "cpu": [ "ia32" ], @@ -6196,9 +6017,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", "cpu": [ "x64" ], @@ -6215,18 +6036,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -6245,9 +6054,9 @@ "license": "MIT" }, "node_modules/@poppinss/colors": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.5.tgz", - "integrity": "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", + "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", "dev": true, "license": "MIT", "dependencies": { @@ -6265,9 +6074,9 @@ } }, "node_modules/@poppinss/dumper": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.4.tgz", - "integrity": "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.7.0.tgz", + "integrity": "sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==", "dev": true, "license": "MIT", "dependencies": { @@ -6276,30 +6085,17 @@ "supports-color": "^10.0.0" } }, - "node_modules/@poppinss/dumper/node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/@poppinss/exception": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.2.tgz", - "integrity": "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", + "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", "dev": true, "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", "cpu": [ "arm64" ], @@ -6314,9 +6110,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", "cpu": [ "arm64" ], @@ -6331,9 +6127,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", - "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", "cpu": [ "x64" ], @@ -6348,9 +6144,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", - "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", "cpu": [ "x64" ], @@ -6365,9 +6161,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", - "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", "cpu": [ "arm" ], @@ -6382,13 +6178,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6399,13 +6198,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", - "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6416,13 +6218,16 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6433,13 +6238,16 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6450,13 +6258,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6467,13 +6278,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", - "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6484,9 +6298,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", "cpu": [ "arm64" ], @@ -6501,9 +6315,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", - "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", "cpu": [ "wasm32" ], @@ -6511,16 +6325,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", - "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", "cpu": [ "arm64" ], @@ -6535,9 +6351,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", - "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", "cpu": [ "x64" ], @@ -6552,23 +6368,23 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.29", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", - "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, "node_modules/@rollup/plugin-alias": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", - "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-6.0.0.tgz", + "integrity": "sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "rollup": ">=4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -6577,9 +6393,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "28.0.6", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz", - "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.3.tgz", + "integrity": "sha512-ZaOxZceP7SOUW7Lqw5IRVweSQYWaeIPnXIGLiB690EBA3FGJTO40EEr2L5yZplJWsgTCogILRSpcAe7+U0Otdg==", "dev": true, "license": "MIT", "dependencies": { @@ -6603,6 +6419,13 @@ } } }, + "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/plugin-inject": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", @@ -6626,6 +6449,13 @@ } } }, + "node_modules/@rollup/plugin-inject/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/plugin-json": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", @@ -6648,9 +6478,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", - "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", "dev": true, "license": "MIT", "dependencies": { @@ -6673,13 +6503,14 @@ } }, "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6694,9 +6525,9 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz", - "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", "dev": true, "license": "MIT", "dependencies": { @@ -6716,18 +6547,18 @@ } }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", "dev": true, "license": "MIT", "dependencies": { - "serialize-javascript": "^6.0.1", + "serialize-javascript": "^7.0.3", "smob": "^1.0.0", "terser": "^5.17.4" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" @@ -6739,9 +6570,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -6760,332 +6591,410 @@ } } }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", - "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", - "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", - "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", - "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", - "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", - "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", - "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", "cpu": [ "arm" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", - "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", "cpu": [ "arm" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", - "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", - "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", - "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", + "cpu": [ + "loong64" ], - "peer": true + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", - "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", + "cpu": [ + "ppc64" ], - "peer": true + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", - "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", - "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", - "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", "cpu": [ "s390x" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", - "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", "cpu": [ "x64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", - "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", "cpu": [ "x64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", - "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", - "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", - "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", + "cpu": [ + "x64" ], - "peer": true + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", - "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "node_modules/@simple-git/args-pathspec": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@simple-git/args-pathspec/-/args-pathspec-1.0.3.tgz", + "integrity": "sha512-ngJMaHlsWDTfjyq9F3VIQ8b7NXbBLq5j9i5bJ6XLYtD6qlDXT7fdKY2KscWWUF8t18xx052Y/PUO1K1TRc9yKA==", "dev": true, "license": "MIT" }, + "node_modules/@simple-git/argv-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@simple-git/argv-parser/-/argv-parser-1.1.1.tgz", + "integrity": "sha512-Q9lBcfQ+VQCpQqGJFHe5yooOS5hGdLFFbJ5R+R5aDsnkPCahtn1hSkMcORX65J2Z5lxSkD0lQorMsncuBQxYUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-git/args-pathspec": "^1.0.3" + } + }, + "node_modules/@sindresorhus/base62": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", + "integrity": "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@sindresorhus/is": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.2.tgz", - "integrity": "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", "dev": true, "license": "MIT", "engines": { @@ -7096,9 +7005,9 @@ } }, "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, "license": "MIT", "engines": { @@ -7108,22 +7017,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@so-ric/colorspace": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", + "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", + "license": "MIT", + "dependencies": { + "color": "^5.0.2", + "text-hex": "1.0.x" + } + }, "node_modules/@speed-highlight/core": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.7.tgz", - "integrity": "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.15.tgz", + "integrity": "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==", "dev": true, "license": "CC0-1.0" }, "node_modules/@stylistic/eslint-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.3.1.tgz", - "integrity": "sha512-Ykums1VYonM0TgkD0VteVq9mrlO2FhF48MDJnPyv3MktIB2ydtuhlO0AfWm7xnW1kyf5bjOqA6xc7JjviuVTxg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/types": "^8.41.0", + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "estraverse": "^5.3.0", @@ -7133,45 +7052,22 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=9.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "eslint": "^9.0.0 || ^10.0.0" } }, "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", - "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.10.tgz", + "integrity": "sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==", "license": "MIT", "peerDependencies": { "acorn": "^8.9.0" } }, - "node_modules/@tsd/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-oKarNCN1QUhG148M88mtZdOlBZWWGcInquef+U8QL7gwJkRuNo5WS45Fjsd+3hM9cDJWGpqSZ4Oo097KDx4IWA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.17" - } - }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -7180,22 +7076,16 @@ } }, "node_modules/@types/chai": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", - "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { - "@types/deep-eql": "*" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -7203,21 +7093,17 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", - "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==", + "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { @@ -7227,90 +7113,22 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", - "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*", - "@types/node": "*" - } - }, - "node_modules/@types/mime-types": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", - "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", - "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "devOptional": true, "license": "MIT", "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~6.21.0" } }, - "node_modules/@types/node/node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "devOptional": true, - "license": "MIT" - }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "license": "MIT" }, - "node_modules/@types/parse-gitignore": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-gitignore/-/parse-gitignore-1.0.2.tgz", - "integrity": "sha512-AQwj+lNTWI7y1kkMe8qLByiToXoXs/du70qGFIHJZaJUVrF5jB8QzvWmLyR1VWYqRagpY8ABrqAjs7uHsJnVBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/parse-path": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz", - "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/pg": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", - "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -7324,46 +7142,12 @@ "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "license": "MIT" }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "source-map": "^0.6.0" - } - }, - "node_modules/@types/statuses": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", - "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", "license": "MIT" }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -7375,21 +7159,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz", - "integrity": "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", + "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.43.0", - "@typescript-eslint/type-utils": "8.43.0", - "@typescript-eslint/utils": "8.43.0", - "@typescript-eslint/visitor-keys": "8.43.0", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/type-utils": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7399,33 +7182,23 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.43.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "@typescript-eslint/parser": "^8.60.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.43.0.tgz", - "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", + "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.43.0", - "@typescript-eslint/types": "8.43.0", - "@typescript-eslint/typescript-estree": "8.43.0", - "@typescript-eslint/visitor-keys": "8.43.0", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7435,19 +7208,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.43.0.tgz", - "integrity": "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.43.0", - "@typescript-eslint/types": "^8.43.0", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7457,18 +7230,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.43.0.tgz", - "integrity": "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.43.0", - "@typescript-eslint/visitor-keys": "8.43.0" + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7479,9 +7252,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.43.0.tgz", - "integrity": "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7491,21 +7264,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.43.0.tgz", - "integrity": "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", + "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.43.0", - "@typescript-eslint/typescript-estree": "8.43.0", - "@typescript-eslint/utils": "8.43.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7515,14 +7288,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz", - "integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7533,21 +7306,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.43.0.tgz", - "integrity": "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.43.0", - "@typescript-eslint/tsconfig-utils": "8.43.0", - "@typescript-eslint/types": "8.43.0", - "@typescript-eslint/visitor-keys": "8.43.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7557,20 +7329,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.43.0.tgz", - "integrity": "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.43.0", - "@typescript-eslint/types": "8.43.0", - "@typescript-eslint/typescript-estree": "8.43.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7580,18 +7352,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.43.0.tgz", - "integrity": "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.43.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7602,26 +7374,26 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@unhead/vue": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.0.14.tgz", - "integrity": "sha512-Ym9f+Kd2Afqek2FtUHvYvK+j2uZ2vbZ6Rr9NCnNGGBMdmafAuiZpT117YGyh0ARcueL6Znia0U8ySqPsnHOZIg==", + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.1.15.tgz", + "integrity": "sha512-SSByXfEjhzPn8gXdEdgpYqpLMPSkLUH2HVE0GxZfOtNsJ0GgOHQs0g9T67ZZ1z0kTELLKdtOtYrzrbv9+ffF7g==", "dev": true, "license": "MIT", "dependencies": { - "hookable": "^5.5.3", - "unhead": "2.0.14" + "hookable": "^6.0.1", + "unhead": "2.1.15" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" @@ -7630,10 +7402,30 @@ "vue": ">=3.5.18" } }, + "node_modules/@unhead/vue/node_modules/hookable": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.1.1.tgz", + "integrity": "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@unhead/vue/node_modules/unhead": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.15.tgz", + "integrity": "sha512-MCt5T90mCWyr3Z6pUCdM9lVRXoMoVBlL7z7U4CYVIiaDiuzad/UCfLuMqz5MeNmpZUgoBCQnrucJimU7EZR+XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookable": "^6.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/harlan-zw" + } + }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", "cpu": [ "arm" ], @@ -7645,9 +7437,9 @@ ] }, "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", "cpu": [ "arm64" ], @@ -7659,9 +7451,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", "cpu": [ "arm64" ], @@ -7673,9 +7465,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", "cpu": [ "x64" ], @@ -7687,9 +7479,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", "cpu": [ "x64" ], @@ -7701,9 +7493,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", "cpu": [ "arm" ], @@ -7715,9 +7507,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", "cpu": [ "arm" ], @@ -7729,13 +7521,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7743,13 +7538,50 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7757,13 +7589,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7771,13 +7606,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7785,13 +7623,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7799,13 +7640,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7813,13 +7657,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7827,23 +7674,40 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", "cpu": [ "wasm32" ], @@ -7851,29 +7715,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" - } - }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", "cpu": [ "arm64" ], @@ -7885,9 +7738,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", "cpu": [ "ia32" ], @@ -7899,9 +7752,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", "cpu": [ "x64" ], @@ -7938,70 +7791,73 @@ "node": ">=18" } }, - "node_modules/@vitejs/plugin-vue": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", - "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==", - "dev": true, - "license": "MIT", + "node_modules/@vercel/nft/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", + "dev": true, + "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.29" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "node_modules/@vitejs/plugin-vue-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.1.tgz", - "integrity": "sha512-uQkfxzlF8SGHJJVH966lFTdjM/lGcwJGzwAHpVqAPDD/QcsqoUGa+q31ox1BrUfi+FLP2ChVp7uLXE3DkHyDdQ==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.5.tgz", + "integrity": "sha512-jIAsvHOEtWpslLOI2MeElGFxH7M8pM83BU/Tor4RLyiwH0FM4nUW3xdvbw20EeU9wc5IspQwMq225K3CMnJEpA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.3", - "@babel/plugin-syntax-typescript": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.28.0", - "@rolldown/pluginutils": "^1.0.0-beta.34", - "@vue/babel-plugin-jsx": "^1.5.0" + "@babel/core": "^7.29.0", + "@babel/plugin-syntax-typescript": "^7.28.6", + "@babel/plugin-transform-typescript": "^7.28.6", + "@rolldown/pluginutils": "^1.0.0-rc.2", + "@vue/babel-plugin-jsx": "^2.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.0.0" } }, - "node_modules/@vitejs/plugin-vue-jsx/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.37", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.37.tgz", - "integrity": "sha512-0taU1HpxFzrukvWIhLRI4YssJX2wOW5q1MxPXWztltsQ13TE51/larZIwhFdpyk7+K43TH7x6GJ8oEqAo+vDbA==", - "dev": true, - "license": "MIT" - }, "node_modules/@vitest/eslint-plugin": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.7.tgz", - "integrity": "sha512-sd2QJirEscSQk3Pywtelbs7z8RQp1gyF5BfeZVtTHE8y3suyzbAA71NuT9z01uTRMHoCf5p6M2t2WYNJ7m5FlA==", + "version": "1.6.19", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.19.tgz", + "integrity": "sha512-zodmXRsVKFsuHxHJILuTFaaKsrsxm0YsiOX65clk+LpCW9JrVXaf6ERXr0caDs+NEk0S62Jyk0K7XYQ7gWXheA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "^8.55.0", - "@typescript-eslint/utils": "^8.55.0" + "@typescript-eslint/scope-manager": "^8.58.0", + "@typescript-eslint/utils": "^8.58.0" }, "engines": { "node": ">=18" }, "peerDependencies": { + "@typescript-eslint/eslint-plugin": "*", "eslint": ">=8.57.0", "typescript": ">=5.0.0", "vitest": "*" }, "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, "typescript": { "optional": true }, @@ -8010,170 +7866,16 @@ } } }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/project-service": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.55.0.tgz", - "integrity": "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.55.0", - "@typescript-eslint/types": "^8.55.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.55.0.tgz", - "integrity": "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.55.0.tgz", - "integrity": "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.55.0.tgz", - "integrity": "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.55.0.tgz", - "integrity": "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.55.0", - "@typescript-eslint/tsconfig-utils": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.55.0.tgz", - "integrity": "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.55.0.tgz", - "integrity": "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.55.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitest/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", "dev": true, "license": "MIT", "dependencies": { "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -8181,47 +7883,10 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/mocker": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", - "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "3.2.4", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/mocker/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", "dev": true, "license": "MIT", "dependencies": { @@ -8232,13 +7897,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", - "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.4", + "@vitest/utils": "3.2.6", "pathe": "^2.0.3", "strip-literal": "^3.0.0" }, @@ -8247,13 +7912,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", - "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", + "@vitest/pretty-format": "3.2.6", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -8262,9 +7927,9 @@ } }, "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", "dev": true, "license": "MIT", "dependencies": { @@ -8275,13 +7940,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", + "@vitest/pretty-format": "3.2.6", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, @@ -8290,49 +7955,49 @@ } }, "node_modules/@volar/language-core": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", - "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", "dev": true, "license": "MIT", "dependencies": { - "@volar/source-map": "2.4.23" + "@volar/source-map": "2.4.28" } }, "node_modules/@volar/source-map": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", - "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", "dev": true, "license": "MIT" }, "node_modules/@volar/typescript": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", - "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.23", + "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "node_modules/@vue-macros/common": { - "version": "3.0.0-beta.16", - "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.0.0-beta.16.tgz", - "integrity": "sha512-8O2gWxWFiaoNkk7PGi0+p7NPGe/f8xJ3/INUufvje/RZOs7sJvlI1jnR4lydtRFa/mU0ylMXUXXjSK0fHDEYTA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", + "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-sfc": "^3.5.17", - "ast-kit": "^2.1.1", - "local-pkg": "^1.1.1", - "magic-string-ast": "^1.0.0", - "unplugin-utils": "^0.2.4" + "@vue/compiler-sfc": "^3.5.22", + "ast-kit": "^2.1.2", + "local-pkg": "^1.1.2", + "magic-string-ast": "^1.0.2", + "unplugin-utils": "^0.3.0" }, "engines": { - "node": ">=20.18.0" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/sponsors/vue-macros" @@ -8346,34 +8011,17 @@ } } }, - "node_modules/@vue-macros/common/node_modules/unplugin-utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", - "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pathe": "^2.0.3", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" - } - }, "node_modules/@vue/babel-helper-vue-transform-on": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", - "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-2.0.1.tgz", + "integrity": "sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==", "dev": true, "license": "MIT" }, "node_modules/@vue/babel-plugin-jsx": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", - "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-2.0.1.tgz", + "integrity": "sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==", "dev": true, "license": "MIT", "dependencies": { @@ -8381,11 +8029,11 @@ "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.2", - "@vue/babel-helper-vue-transform-on": "1.5.0", - "@vue/babel-plugin-resolve-type": "1.5.0", - "@vue/shared": "^3.5.18" + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@vue/babel-helper-vue-transform-on": "2.0.1", + "@vue/babel-plugin-resolve-type": "2.0.1", + "@vue/shared": "^3.5.22" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -8397,17 +8045,17 @@ } }, "node_modules/@vue/babel-plugin-resolve-type": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", - "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-2.0.1.tgz", + "integrity": "sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/parser": "^7.28.0", - "@vue/compiler-sfc": "^3.5.18" + "@babel/parser": "^7.28.4", + "@vue/compiler-sfc": "^3.5.22" }, "funding": { "url": "https://github.com/sponsors/sxzz" @@ -8417,82 +8065,106 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz", - "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", + "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@vue/shared": "3.5.21", - "entities": "^4.5.0", + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.35", + "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@vue/compiler-dom": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz", - "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", + "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.21", - "@vue/shared": "3.5.21" + "@vue/compiler-core": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz", - "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz", + "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@vue/compiler-core": "3.5.21", - "@vue/compiler-dom": "3.5.21", - "@vue/compiler-ssr": "3.5.21", - "@vue/shared": "3.5.21", + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.35", + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35", "estree-walker": "^2.0.2", - "magic-string": "^0.30.18", - "postcss": "^8.5.6", + "magic-string": "^0.30.21", + "postcss": "^8.5.15", "source-map-js": "^1.2.1" } }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz", - "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz", + "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.21", - "@vue/shared": "3.5.21" + "@vue/compiler-dom": "3.5.35", + "@vue/shared": "3.5.35" } }, - "node_modules/@vue/compiler-vue2": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", - "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "node_modules/@vue/devtools-api": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.2.tgz", + "integrity": "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==", "dev": true, "license": "MIT", "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" + "@vue/devtools-kit": "^8.1.2" } }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "node_modules/@vue/devtools-api/node_modules/@vue/devtools-kit": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz", + "integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.1.2", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-api/node_modules/@vue/devtools-shared": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz", + "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==", "dev": true, "license": "MIT" }, "node_modules/@vue/devtools-core": { - "version": "7.7.7", - "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.7.tgz", - "integrity": "sha512-9z9TLbfC+AjAi1PQyWX+OErjIaJmdFlbDHcD+cAMYKY6Bh5VlsAtCeGyRMrXwIlMEQPukvnWt3gZBLwTAIMKzQ==", + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.9.tgz", + "integrity": "sha512-48jrBSwG4GVQRvVeeXn9p9+dlx+ISgasM7SxZZKczseohB0cBz+ITKr4YbLWjmJdy45UHL7UMPlR4Y0CWTRcSQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^7.7.7", - "@vue/devtools-shared": "^7.7.7", + "@vue/devtools-kit": "^7.7.9", + "@vue/devtools-shared": "^7.7.9", "mitt": "^3.0.1", "nanoid": "^5.1.0", "pathe": "^2.0.3", @@ -8502,33 +8174,14 @@ "vue": "^3.0.0" } }, - "node_modules/@vue/devtools-core/node_modules/nanoid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", - "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, "node_modules/@vue/devtools-kit": { - "version": "7.7.7", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", - "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^7.7.7", + "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", @@ -8537,10 +8190,17 @@ "superjson": "^2.2.2" } }, + "node_modules/@vue/devtools-kit/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, "node_modules/@vue/devtools-shared": { - "version": "7.7.7", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", - "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", "dev": true, "license": "MIT", "dependencies": { @@ -8548,82 +8208,73 @@ } }, "node_modules/@vue/language-core": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.0.6.tgz", - "integrity": "sha512-e2RRzYWm+qGm8apUHW1wA5RQxzNhkqbbKdbKhiDUcmMrNAZGyM8aTiL3UrTqkaFI5s7wJRGGrp4u3jgusuBp2A==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.3.tgz", + "integrity": "sha512-X6p+7nfY7vVT6dQwUJ+v0Jfq/lwIfhL2jMi91dQ3ln4hnlGXlxsDu/FNkeyHYgvYtyQy18ZX76IZy7X4diDbiQ==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.23", + "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", - "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", - "alien-signals": "^2.0.5", + "alien-signals": "^3.2.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", - "picomatch": "^4.0.2" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "picomatch": "^4.0.4" } }, "node_modules/@vue/reactivity": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", - "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz", + "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.21" + "@vue/shared": "3.5.35" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", - "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz", + "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.21", - "@vue/shared": "3.5.21" + "@vue/reactivity": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", - "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz", + "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.21", - "@vue/runtime-core": "3.5.21", - "@vue/shared": "3.5.21", - "csstype": "^3.1.3" + "@vue/reactivity": "3.5.35", + "@vue/runtime-core": "3.5.35", + "@vue/shared": "3.5.35", + "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", - "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz", + "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.21", - "@vue/shared": "3.5.21" + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35" }, "peerDependencies": { - "vue": "3.5.21" + "vue": "3.5.35" } }, "node_modules/@vue/shared": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz", - "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", + "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", "license": "MIT" }, "node_modules/@whatwg-node/disposablestack": { @@ -8640,12 +8291,12 @@ } }, "node_modules/@whatwg-node/fetch": { - "version": "0.10.10", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.10.tgz", - "integrity": "sha512-watz4i/Vv4HpoJ+GranJ7HH75Pf+OkPQ63NoVmru6Srgc8VezTArB00i/oQlnn0KWh14gM42F22Qcc9SU9mo/w==", + "version": "0.10.13", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.13.tgz", + "integrity": "sha512-b4PhJ+zYj4357zwk4TTuF2nEe0vVtOrwdsrNo5hL+u1ojXNhh1FgJ6pg1jzDlwlT4oBdzfSwaBwMCtFCsIWg8Q==", "license": "MIT", "dependencies": { - "@whatwg-node/node-fetch": "^0.7.25", + "@whatwg-node/node-fetch": "^0.8.3", "urlpattern-polyfill": "^10.0.0" }, "engines": { @@ -8659,9 +8310,9 @@ "license": "MIT" }, "node_modules/@whatwg-node/node-fetch": { - "version": "0.7.25", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.25.tgz", - "integrity": "sha512-szCTESNJV+Xd56zU6ShOi/JWROxE9IwCic8o5D9z5QECZloas6Ez5tUuKqXTAdu6fHFx1t6C+5gwj8smzOLjtg==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.8.6.tgz", + "integrity": "sha512-BDMdYFcerLQkwA2RTldxOqRCs6ZQD1S7UgP3pUdGUkcbgTrP/V5ko77ZkCww9DHmC4lpoYuwigGfQYj285gMvA==", "license": "MIT", "dependencies": { "@fastify/busboy": "^3.1.1", @@ -8686,14 +8337,14 @@ } }, "node_modules/@whatwg-node/server": { - "version": "0.10.12", - "resolved": "https://registry.npmjs.org/@whatwg-node/server/-/server-0.10.12.tgz", - "integrity": "sha512-MQIvvQyPvKGna586MzXhgwnEbGtbm7QtOgJ/KPd/tC70M/jbhd1xHdIQQbh3okBw+MrDF/EvaC2vB5oRC7QdlQ==", + "version": "0.10.18", + "resolved": "https://registry.npmjs.org/@whatwg-node/server/-/server-0.10.18.tgz", + "integrity": "sha512-kMwLlxUbduttIgaPdSkmEarFpP+mSY8FEm+QWMBRJwxOHWkri+cxd8KZHO9EMrB9vgUuz+5WEaCawaL5wGVoXg==", "license": "MIT", "dependencies": { "@envelop/instrumentation": "^1.0.0", "@whatwg-node/disposablestack": "^0.0.6", - "@whatwg-node/fetch": "^0.10.10", + "@whatwg-node/fetch": "^0.10.13", "@whatwg-node/promise-helpers": "^1.3.2", "tslib": "^2.6.3" }, @@ -8723,9 +8374,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -8763,56 +8414,36 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/alien-signals": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-2.0.7.tgz", - "integrity": "sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, + "node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "ajv": "^8.0.1" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/alien-signals": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/ansi-regex": { "version": "6.2.2", @@ -8827,24 +8458,21 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/ansis": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", - "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", + "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==", "license": "ISC", "engines": { "node": ">=14" @@ -8871,9 +8499,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -8947,24 +8575,59 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/assertion-error": { @@ -8978,43 +8641,44 @@ } }, "node_modules/ast-kit": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.1.2.tgz", - "integrity": "sha512-cl76xfBQM6pztbrFWRnxbrDm9EOqDr1BF6+qQnnDZG2Co2LjyUktkN9GTJfBAfdae+DbT2nJf2nCGAdDDN7W2g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", + "@babel/parser": "^7.28.5", "pathe": "^2.0.3" }, "engines": { - "node": ">=20.18.0" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/sponsors/sxzz" } }, "node_modules/ast-module-types": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-6.0.1.tgz", - "integrity": "sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-6.0.2.tgz", + "integrity": "sha512-6KuK/7nZ/2Qh7sGuVEiwxjCxzTY2Pdb5mTo5z1e6/J8BA0tvjR7G8vQJKrQMTqwmnA3UPEyKIFX4YUS1DO1Hvw==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/ast-walker-scope": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.2.tgz", - "integrity": "sha512-3pYeLyDZ6nJew9QeBhS4Nly02269Dkdk32+zdbbKmL6n4ZuaGorwwA+xx12xgOciA8BF1w9x+dlH7oUkFTW91w==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.9.0.tgz", + "integrity": "sha512-IJdzo2vLiElBxKzwS36VsCue/62d6IdWjnPB2v3nuPKeWGynp6FF/CYoLa5i/3jXH/z97ZDdsXz6abpgM6w07A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "ast-kit": "^2.1.2" + "@babel/parser": "^7.29.2", + "@babel/types": "^7.29.0", + "ast-kit": "^2.2.0" }, "engines": { - "node": ">=20.18.0" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/sponsors/sxzz" @@ -9026,6 +8690,15 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/async-sema": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", @@ -9043,9 +8716,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.21", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", - "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -9063,10 +8736,9 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, @@ -9080,10 +8752,25 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/b4a": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.1.tgz", - "integrity": "sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -9095,17 +8782,104 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/bare-events": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", - "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", + "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz", + "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz", + "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.4.tgz", + "integrity": "sha512-zbQJi2YQUe3SrX19TItQ8DoPj9E1i5rrdE9iHV4PhUif1GodNRSe85lavVGbmU7P4M8579EQi4akGFuhCATWaQ==", "license": "Apache-2.0", - "optional": true + "dependencies": { + "bare-path": "^3.0.0" + } }, "node_modules/base64-js": { "version": "1.5.1", @@ -9127,6 +8901,19 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/better-ajv-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-1.2.0.tgz", @@ -9146,14 +8933,59 @@ "ajv": "4.11.8 - 8" } }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "dev": true, + "node_modules/better-ajv-errors/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { - "require-from-string": "^2.0.2" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/better-ajv-errors/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/better-ajv-errors/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/better-ajv-errors/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/bindings": { @@ -9166,9 +8998,9 @@ } }, "node_modules/birpc": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.8.0.tgz", - "integrity": "sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", "dev": true, "license": "MIT", "funding": { @@ -9182,12 +9014,15 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -9203,9 +9038,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", - "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -9223,10 +9058,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001737", - "electron-to-chromium": "^1.5.211", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -9281,9 +9117,9 @@ "license": "MIT" }, "node_modules/builtin-modules": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", - "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.2.0.tgz", + "integrity": "sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==", "dev": true, "license": "MIT", "engines": { @@ -9326,23 +9162,23 @@ } }, "node_modules/c12": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.2.tgz", - "integrity": "sha512-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz", + "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==", "license": "MIT", "dependencies": { - "chokidar": "^4.0.3", - "confbox": "^0.2.2", - "defu": "^6.1.4", - "dotenv": "^17.2.3", + "chokidar": "^5.0.0", + "confbox": "^0.2.4", + "defu": "^6.1.6", + "dotenv": "^17.3.1", "exsolve": "^1.0.8", - "giget": "^2.0.0", + "giget": "^3.2.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", + "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", - "rc9": "^2.1.2" + "rc9": "^3.0.1" }, "peerDependencies": { "magicast": "*" @@ -9353,40 +9189,33 @@ } } }, - "node_modules/c12/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "license": "MIT" - }, - "node_modules/c12/node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", - "license": "BSD-2-Clause", + "node_modules/c12/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, "engines": { - "node": ">=12" + "node": ">= 20.19.0" }, "funding": { - "url": "https://dotenvx.com" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/c12/node_modules/perfect-debounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", - "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", - "license": "MIT" - }, - "node_modules/c12/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/c12/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" - } + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } }, "node_modules/cac": { "version": "6.7.14", @@ -9398,6 +9227,53 @@ "node": ">=8" } }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -9416,34 +9292,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -9458,9 +9306,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001741", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", - "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -9496,16 +9344,12 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -9519,9 +9363,9 @@ "license": "MIT" }, "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", "dev": true, "license": "MIT", "engines": { @@ -9553,9 +9397,9 @@ } }, "node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true, "funding": [ { @@ -9569,13 +9413,10 @@ } }, "node_modules/citty": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "license": "MIT", - "dependencies": { - "consola": "^3.2.3" - } + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", + "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", + "license": "MIT" }, "node_modules/cjs-module-lexer": { "version": "2.2.0", @@ -9606,33 +9447,6 @@ "node": ">=0.8.0" } }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/clipboardy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz", - "integrity": "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==", - "license": "MIT", - "dependencies": { - "execa": "^8.0.1", - "is-wsl": "^3.1.0", - "is64bit": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -9656,6 +9470,33 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -9706,9 +9547,9 @@ } }, "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", "devOptional": true, "license": "Apache-2.0", "engines": { @@ -9716,25 +9557,37 @@ } }, "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", "license": "MIT", "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" + "color-convert": "^3.1.3", + "color-string": "^2.1.3" + }, + "engines": { + "node": ">=18" } }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "color-name": "^2.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=14.6" + } + }, + "node_modules/color-convert/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" } }, "node_modules/color-name": { @@ -9744,60 +9597,40 @@ "license": "MIT" }, "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "license": "MIT", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" + "engines": { + "node": ">=12.20" } }, "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "extraneous": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", + "integrity": "sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==", "dev": true, "license": "MIT", "engines": { @@ -9860,9 +9693,9 @@ "license": "MIT" }, "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", "license": "MIT" }, "node_modules/consola": { @@ -9882,31 +9715,35 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cookie-es": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", - "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", "license": "MIT" }, "node_modules/copy-anything": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", - "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", "dev": true, "license": "MIT", "dependencies": { - "is-what": "^4.1.8" + "is-what": "^5.2.0" }, "engines": { - "node": ">=12.13" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/mesqueeb" @@ -9929,13 +9766,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", - "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.3" + "browserslist": "^4.28.1" }, "funding": { "type": "opencollective", @@ -9986,10 +9823,20 @@ } }, "node_modules/croner": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/croner/-/croner-9.1.0.tgz", - "integrity": "sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/croner/-/croner-10.0.1.tgz", + "integrity": "sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==", "dev": true, + "funding": [ + { + "type": "other", + "url": "https://paypal.me/hexagonpp" + }, + { + "type": "github", + "url": "https://github.com/sponsors/hexagon" + } + ], "license": "MIT", "engines": { "node": ">=18.0" @@ -10009,19 +9856,54 @@ "node": ">= 8" } }, - "node_modules/crossws": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", - "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { - "uncrypto": "^0.1.3" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.4.5.tgz", + "integrity": "sha512-wUR89x/Rw7/8t+vn0CmGDYM9TD6VtARGb0LD5jq2wjtMy1vCP4M+sm6N6TigWeTYvnA8MoW29NqqXD0ep0rfBA==", + "license": "MIT", + "peerDependencies": { + "srvx": ">=0.11.5" + }, + "peerDependenciesMeta": { + "srvx": { + "optional": true + } } }, "node_modules/css-declaration-sorter": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", - "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz", + "integrity": "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==", "dev": true, "license": "ISC", "engines": { @@ -10092,13 +9974,13 @@ "license": "MIT" }, "node_modules/cssnano": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.1.tgz", - "integrity": "sha512-fm4D8ti0dQmFPeF8DXSAA//btEmqCOgAc/9Oa3C1LW94h5usNrJEfrON7b4FkPZgnDEn6OUs5NdxiJZmAtGOpQ==", + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.9.tgz", + "integrity": "sha512-uPR75+5Dk/WJ/YSPR1/YDHdwMM9c5FsaARljfKWgeCKLKOtJ0we21xy/RcCjn53fZnD/f6yYEIZ8pu18+GnbNQ==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-preset-default": "^7.0.9", + "cssnano-preset-default": "^7.0.17", "lilconfig": "^3.1.3" }, "engines": { @@ -10109,65 +9991,65 @@ "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, "node_modules/cssnano-preset-default": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.9.tgz", - "integrity": "sha512-tCD6AAFgYBOVpMBX41KjbvRh9c2uUjLXRyV7KHSIrwHiq5Z9o0TFfUCoM3TwVrRsRteN3sVXGNvjVNxYzkpTsA==", + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.17.tgz", + "integrity": "sha512-11qO63A+czwguQFJCaTdICvbaxn0pJzz/XghLlv+OT7WyToDxAMR0Xb3/26/l0y0hQJywwNbj/SLSQlGBHE1OA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", + "browserslist": "^4.28.2", "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^5.0.1", + "cssnano-utils": "^5.0.3", "postcss-calc": "^10.1.1", - "postcss-colormin": "^7.0.4", - "postcss-convert-values": "^7.0.7", - "postcss-discard-comments": "^7.0.4", - "postcss-discard-duplicates": "^7.0.2", - "postcss-discard-empty": "^7.0.1", - "postcss-discard-overridden": "^7.0.1", - "postcss-merge-longhand": "^7.0.5", - "postcss-merge-rules": "^7.0.6", - "postcss-minify-font-values": "^7.0.1", - "postcss-minify-gradients": "^7.0.1", - "postcss-minify-params": "^7.0.4", - "postcss-minify-selectors": "^7.0.5", - "postcss-normalize-charset": "^7.0.1", - "postcss-normalize-display-values": "^7.0.1", - "postcss-normalize-positions": "^7.0.1", - "postcss-normalize-repeat-style": "^7.0.1", - "postcss-normalize-string": "^7.0.1", - "postcss-normalize-timing-functions": "^7.0.1", - "postcss-normalize-unicode": "^7.0.4", - "postcss-normalize-url": "^7.0.1", - "postcss-normalize-whitespace": "^7.0.1", - "postcss-ordered-values": "^7.0.2", - "postcss-reduce-initial": "^7.0.4", - "postcss-reduce-transforms": "^7.0.1", - "postcss-svgo": "^7.1.0", - "postcss-unique-selectors": "^7.0.4" + "postcss-colormin": "^7.0.10", + "postcss-convert-values": "^7.0.12", + "postcss-discard-comments": "^7.0.8", + "postcss-discard-duplicates": "^7.0.4", + "postcss-discard-empty": "^7.0.3", + "postcss-discard-overridden": "^7.0.3", + "postcss-merge-longhand": "^7.0.7", + "postcss-merge-rules": "^7.0.11", + "postcss-minify-font-values": "^7.0.3", + "postcss-minify-gradients": "^7.0.5", + "postcss-minify-params": "^7.0.9", + "postcss-minify-selectors": "^7.1.2", + "postcss-normalize-charset": "^7.0.3", + "postcss-normalize-display-values": "^7.0.3", + "postcss-normalize-positions": "^7.0.4", + "postcss-normalize-repeat-style": "^7.0.4", + "postcss-normalize-string": "^7.0.3", + "postcss-normalize-timing-functions": "^7.0.3", + "postcss-normalize-unicode": "^7.0.9", + "postcss-normalize-url": "^7.0.3", + "postcss-normalize-whitespace": "^7.0.3", + "postcss-ordered-values": "^7.0.4", + "postcss-reduce-initial": "^7.0.9", + "postcss-reduce-transforms": "^7.0.3", + "postcss-svgo": "^7.1.3", + "postcss-unique-selectors": "^7.0.7" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, "node_modules/cssnano-utils": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", - "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.3.tgz", + "integrity": "sha512-ynIREMICLxkxm7e9bCR9sh75s4Q5drICi0ua1yxo5jH2XPBqSKkl4dOh4EbFqtUmnTMhRffHgYL0EKKkMjtJTg==", "dev": true, "license": "MIT", "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, "node_modules/csso": { @@ -10203,26 +10085,10 @@ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", "license": "CC0-1.0" }, - "node_modules/cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, @@ -10235,69 +10101,61 @@ "node": ">= 12" } }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">=18" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/data-urls/node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dev": true, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "punycode": "^2.3.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" } }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": ">=18" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/db0": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.2.tgz", - "integrity": "sha512-xzWNQ6jk/+NtdfLyXEipbX55dmDSeteLFt/ayF+wZUU5bzKgmrDOxmInUTbyVRp46YwnJdkDA1KhB7WIXFofJw==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz", + "integrity": "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -10329,13 +10187,6 @@ } } }, - "node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true, - "license": "MIT" - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -10362,54 +10213,10 @@ "callsite": "^1.0.0" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -10447,9 +10254,9 @@ } }, "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", "dev": true, "license": "MIT", "dependencies": { @@ -10464,9 +10271,9 @@ } }, "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "dev": true, "license": "MIT", "engines": { @@ -10476,6 +10283,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", @@ -10489,10 +10313,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "license": "MIT" }, "node_modules/denque": { @@ -10522,23 +10363,23 @@ "license": "MIT" }, "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "engines": { "node": ">=8" } }, "node_modules/detective-amd": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-6.0.1.tgz", - "integrity": "sha512-TtyZ3OhwUoEEIhTFoc1C9IyJIud3y+xYkSRjmvCt65+ycQuc3VcBrPRTMWoO/AnuCyOB8T5gky+xf7Igxtjd3g==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-6.1.0.tgz", + "integrity": "sha512-fmI6LGMvotqd49QaA3ZYw+q0aGp2yXmMjzIuY6fH9j9YFIXY/73yDhMwhX9cPbhWd+AH06NH1Di/LKOuCH0Ubg==", "license": "MIT", "dependencies": { "ast-module-types": "^6.0.1", "escodegen": "^2.1.0", - "get-amd-module-type": "^6.0.1", + "get-amd-module-type": "^6.0.2", "node-source-walk": "^7.0.1" }, "bin": { @@ -10549,9 +10390,9 @@ } }, "node_modules/detective-cjs": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-6.0.1.tgz", - "integrity": "sha512-tLTQsWvd2WMcmn/60T2inEJNhJoi7a//PQ7DwRKEj1yEeiQs4mrONgsUtEJKnZmrGWBBmE0kJ1vqOG/NAxwaJw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-6.1.1.tgz", + "integrity": "sha512-pSh7mkCKEtLlmANqLu3KDFS3NV8Hx41jy/JF1/gAWOgU+Uo5QTkeI1tWNP4dWGo4L0E9j18Ez9EPsTleautKqA==", "license": "MIT", "dependencies": { "ast-module-types": "^6.0.1", @@ -10562,9 +10403,9 @@ } }, "node_modules/detective-es6": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-5.0.1.tgz", - "integrity": "sha512-XusTPuewnSUdoxRSx8OOI6xIA/uld/wMQwYsouvFN2LAg7HgP06NF1lHRV3x6BZxyL2Kkoih4ewcq8hcbGtwew==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-5.0.2.tgz", + "integrity": "sha512-+qHHGYhjupiVs4rnIpI9nZ5B130A4AmE35ZX1w33hb46vcZ7T3jfDbvmPw0FhWtMHn5BS5HHu7ZtnZ53bMcXZA==", "license": "MIT", "dependencies": { "node-source-walk": "^7.0.1" @@ -10574,25 +10415,25 @@ } }, "node_modules/detective-postcss": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-7.0.1.tgz", - "integrity": "sha512-bEOVpHU9picRZux5XnwGsmCN4+8oZo7vSW0O0/Enq/TO5R2pIAP2279NsszpJR7ocnQt4WXU0+nnh/0JuK4KHQ==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-8.0.4.tgz", + "integrity": "sha512-DZ7M/hWPZyr17ZUdoQ+TVXaPj70mYr4XXrAE+GeJbca44haCvZgb191L/jLJmFYewhxRJuBd4lUtNSu986TXag==", "license": "MIT", "dependencies": { - "is-url": "^1.2.4", + "is-url-superb": "^4.0.0", "postcss-values-parser": "^6.0.2" }, "engines": { - "node": "^14.0.0 || >=16.0.0" + "node": ">=18" }, "peerDependencies": { "postcss": "^8.4.47" } }, "node_modules/detective-sass": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-6.0.1.tgz", - "integrity": "sha512-jSGPO8QDy7K7pztUmGC6aiHkexBQT4GIH+mBAL9ZyBmnUIOFbkfZnO8wPRRJFP/QP83irObgsZHCoDHZ173tRw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-6.0.2.tgz", + "integrity": "sha512-i3xpXHDKS0qI2aFW4asQ7fqlPK00ndOVZELvQapFJCaF0VxYmsNWtd0AmvXbTLMk7bfO5VdIeorhY9KfmHVoVA==", "license": "MIT", "dependencies": { "gonzales-pe": "^4.3.0", @@ -10603,9 +10444,9 @@ } }, "node_modules/detective-scss": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-5.0.1.tgz", - "integrity": "sha512-MAyPYRgS6DCiS6n6AoSBJXLGVOydsr9huwXORUlJ37K3YLyiN0vYHpzs3AdJOgHobBfispokoqrEon9rbmKacg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-5.0.2.tgz", + "integrity": "sha512-9JOEMZ8pDh3ShXmftq7hoQqqJsClaGgxo1hghfCeFlmKf5TC/Twtwb0PAaK8dXwpg9Z0uCmEYSrCxO+kel2eEg==", "license": "MIT", "dependencies": { "gonzales-pe": "^4.3.0", @@ -10625,12 +10466,12 @@ } }, "node_modules/detective-typescript": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-14.0.0.tgz", - "integrity": "sha512-pgN43/80MmWVSEi5LUuiVvO/0a9ss5V7fwVfrJ4QzAQRd3cwqU1SfWGXJFcNKUqoD5cS+uIovhw5t/0rSeC5Mw==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-14.1.2.tgz", + "integrity": "sha512-bIeEn0eVi/JRsE1YizBR2ilnMlWRAIBJJ6kXCKNFxEEWhUcEY3R6I3KYIAy48ieURbD1hcb3Ebvl8AqeoPMSzg==", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "^8.23.0", + "@typescript-eslint/typescript-estree": "^8.58.2", "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" }, @@ -10638,28 +10479,28 @@ "node": ">=18" }, "peerDependencies": { - "typescript": "^5.4.4" + "typescript": "^5.4.4 || ^6.0.2" } }, "node_modules/detective-vue2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/detective-vue2/-/detective-vue2-2.2.0.tgz", - "integrity": "sha512-sVg/t6O2z1zna8a/UIV6xL5KUa2cMTQbdTIIvqNM0NIPswp52fe43Nwmbahzj3ww4D844u/vC2PYfiGLvD3zFA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/detective-vue2/-/detective-vue2-2.3.0.tgz", + "integrity": "sha512-3gwbZPqVTm9sL9XdZsgEJ7x4x99O853VVZHapQAiEkGuMJMpFPjHDrecSgfqnS5JW3FJfYXesLZGvUOibjn49g==", "license": "MIT", "dependencies": { "@dependents/detective-less": "^5.0.1", - "@vue/compiler-sfc": "^3.5.13", + "@vue/compiler-sfc": "^3.5.32", "detective-es6": "^5.0.1", "detective-sass": "^6.0.1", "detective-scss": "^5.0.1", "detective-stylus": "^5.0.1", - "detective-typescript": "^14.0.0" + "detective-typescript": "^14.1.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "typescript": "^5.4.4" + "typescript": "^5.4.4 || ^6.0.2" } }, "node_modules/dettle": { @@ -10669,45 +10510,22 @@ "license": "MIT" }, "node_modules/devalue": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.3.2.tgz", - "integrity": "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", + "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", "dev": true, "license": "MIT" }, "node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -10722,6 +10540,18 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -10779,9 +10609,9 @@ } }, "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -10790,6 +10620,20 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -10820,9 +10664,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.217", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.217.tgz", - "integrity": "sha512-Pludfu5iBxp9XzNl0qq2G87hdD17ZV7h5T4n6rQXDi3nCyloBV3jreE9+8GC6g4X/5yxqVgXEURpcLtM0WS4jA==", + "version": "1.5.367", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.367.tgz", + "integrity": "sha512-4Mk/mrynCNQ+atY40D3UpmhLWB6AHMbYMlIrPhHcMF6x0L7O0b052FCAsxw1LlaR++UFuNg3D/A6XCuGDa0guQ==", "dev": true, "license": "ISC" }, @@ -10833,9 +10677,9 @@ "license": "MIT" }, "node_modules/empathic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", - "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", "license": "MIT", "engines": { "node": ">=14" @@ -10867,23 +10711,23 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "version": "5.22.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.2.tgz", + "integrity": "sha512-0rxICaFZ7NQho/sHely2bvOPRP0Eu2B0NZ9zM54YvRvWMn7jfz3DmnOZDR9LlXDdDcqntAVc6Hfy4gr/tdH/Ag==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" } }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -10904,23 +10748,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/error-ex/node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, "node_modules/error-stack-parser-es": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", @@ -10937,11 +10764,87 @@ "integrity": "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==", "license": "MIT" }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10953,11 +10856,66 @@ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", - "dev": true, + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -10967,32 +10925,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.11", - "@esbuild/android-arm": "0.25.11", - "@esbuild/android-arm64": "0.25.11", - "@esbuild/android-x64": "0.25.11", - "@esbuild/darwin-arm64": "0.25.11", - "@esbuild/darwin-x64": "0.25.11", - "@esbuild/freebsd-arm64": "0.25.11", - "@esbuild/freebsd-x64": "0.25.11", - "@esbuild/linux-arm": "0.25.11", - "@esbuild/linux-arm64": "0.25.11", - "@esbuild/linux-ia32": "0.25.11", - "@esbuild/linux-loong64": "0.25.11", - "@esbuild/linux-mips64el": "0.25.11", - "@esbuild/linux-ppc64": "0.25.11", - "@esbuild/linux-riscv64": "0.25.11", - "@esbuild/linux-s390x": "0.25.11", - "@esbuild/linux-x64": "0.25.11", - "@esbuild/netbsd-arm64": "0.25.11", - "@esbuild/netbsd-x64": "0.25.11", - "@esbuild/openbsd-arm64": "0.25.11", - "@esbuild/openbsd-x64": "0.25.11", - "@esbuild/openharmony-arm64": "0.25.11", - "@esbuild/sunos-x64": "0.25.11", - "@esbuild/win32-arm64": "0.25.11", - "@esbuild/win32-ia32": "0.25.11", - "@esbuild/win32-x64": "0.25.11" + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" } }, "node_modules/escalade": { @@ -11012,13 +10970,12 @@ "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11045,27 +11002,36 @@ "source-map": "~0.6.1" } }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", - "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.35.0", - "@eslint/plugin-kit": "^0.3.5", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", @@ -11084,7 +11050,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -11123,116 +11089,109 @@ } }, "node_modules/eslint-config-flat-gitignore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.1.0.tgz", - "integrity": "sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.3.0.tgz", + "integrity": "sha512-bg4ZLGgoARg1naWfsINUUb/52Ksw/K22K+T16D38Y8v+/sGwwIYrGvH/JBjOin+RQtxxC9tzNNiy4shnGtGyyQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint/compat": "^1.2.5" + "@eslint/compat": "^2.0.3" }, "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "eslint": "^9.5.0" + "eslint": "^9.5.0 || ^10.0.0" } }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "node_modules/eslint-config-flat-gitignore/node_modules/@eslint/compat": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.1.0.tgz", + "integrity": "sha512-LgaSCymEpw7tF53xvDw9SNsraPb1IBHxpdABIOM0hW8UAlP8znrjYtuxfR58FSJ3L9BhwD+FaPRFQpZq84Nh6g==", "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": ">=7.0.0" + "eslint": "^8.40 || 9 || 10" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/eslint-flat-config-utils": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-flat-config-utils/-/eslint-flat-config-utils-2.1.1.tgz", - "integrity": "sha512-K8eaPkBemHkfbYsZH7z4lZ/tt6gNSsVh535Wh9W9gQBS2WjvfUbbVr2NZR3L1yiRCLuOEimYfPxCxODczD4Opg==", + "node_modules/eslint-config-flat-gitignore/node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "pathe": "^2.0.3" + "@types/json-schema": "^7.0.15" }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/eslint-formatter-pretty": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-4.1.0.tgz", - "integrity": "sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==", + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "dependencies": { - "@types/eslint": "^7.2.13", - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "eslint-rule-docs": "^1.1.5", - "log-symbols": "^4.0.0", - "plur": "^4.0.0", - "string-width": "^4.2.0", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=10" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/eslint-formatter-pretty/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/eslint-flat-config-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-flat-config-utils/-/eslint-flat-config-utils-3.2.0.tgz", + "integrity": "sha512-PHgo1X5uqIorJONLVD9BIaOSdoYFD3z/AeJljdqDPlWVRpeCYkDbK9k0AXoYVqqNJr6FEYIEr5Rm2TSktLQcHw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@eslint/config-helpers": "^0.5.5", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/eslint-formatter-pretty/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-formatter-pretty/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/eslint-flat-config-utils/node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@eslint/core": "^1.2.1" }, "engines": { - "node": ">=8" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/eslint-formatter-pretty/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/eslint-flat-config-utils/node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "ansi-regex": "^5.0.1" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=8" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/eslint-import-context": { @@ -11296,41 +11255,32 @@ } }, "node_modules/eslint-plugin-import-lite": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-lite/-/eslint-plugin-import-lite-0.3.0.tgz", - "integrity": "sha512-dkNBAL6jcoCsXZsQ/Tt2yXmMDoNt5NaBh/U7yvccjiK8cai6Ay+MK77bMykmqQA2bTF6lngaLCDij6MTO3KkvA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-lite/-/eslint-plugin-import-lite-0.5.2.tgz", + "integrity": "sha512-XvfdWOC5dSLEI9krIPRlNmKSI2ViIE9pVylzfV9fCq0ZpDaNeUk6o0wZv0OzN83QdadgXp1NsY0qjLINxwYCsw==", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/types": "^8.34.0" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=9.0.0", - "typescript": ">=4.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": ">=9.0.0" } }, "node_modules/eslint-plugin-import-x": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.1.tgz", - "integrity": "sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.2.tgz", + "integrity": "sha512-rM9K8UBHcWKpzQzStn1YRN2T5NvdeIfSVoKu/lKF41znQXHAUcBbYXe5wd6GNjZjTrP7viQ49n1D83x/2gYgIw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.35.0", + "@package-json/types": "^0.0.12", + "@typescript-eslint/types": "^8.56.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.9", "is-glob": "^4.0.3", - "minimatch": "^9.0.3 || ^10.0.1", + "minimatch": "^9.0.3 || ^10.1.2", "semver": "^7.7.2", "stable-hash-x": "^0.2.0", "unrs-resolver": "^1.9.2" @@ -11342,8 +11292,8 @@ "url": "https://opencollective.com/eslint-plugin-import-x" }, "peerDependencies": { - "@typescript-eslint/utils": "^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", + "@typescript-eslint/utils": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "eslint-import-resolver-node": "*" }, "peerDependenciesMeta": { @@ -11356,39 +11306,86 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "54.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-54.7.0.tgz", - "integrity": "sha512-u5Na4he2+6kY1rWqxzbQaAwJL3/tDCuT5ElDRc5UJ9stOeQeQ5L1JJ1kRRu7ldYMlOHMCJLsY8Mg/Tu3ExdZiQ==", + "version": "62.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz", + "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.56.0", + "@es-joy/jsdoccomment": "~0.86.0", + "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.4.1", + "comment-parser": "1.4.6", + "debug": "^4.4.3", "escape-string-regexp": "^4.0.0", - "espree": "^10.4.0", - "esquery": "^1.6.0", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "html-entities": "^2.6.0", + "object-deep-merge": "^2.0.0", "parse-imports-exports": "^0.2.4", - "semver": "^7.7.2", - "spdx-expression-parse": "^4.0.0" + "semver": "^7.7.4", + "spdx-expression-parse": "^4.0.0", + "to-valid-identifier": "^1.0.0" }, "engines": { - "node": ">=20.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/comment-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", + "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-plugin-n": { @@ -11431,63 +11428,61 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-plugin-n/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/eslint-plugin-regexp": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.10.0.tgz", - "integrity": "sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-3.1.0.tgz", + "integrity": "sha512-qGXIC3DIKZHcK1H9A9+Byz9gmndY6TTSRkSMTZpNXdyCw2ObSehRgccJv35n9AdUakEjQp5VFNLas6BMXizCZg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "comment-parser": "^1.4.0", - "jsdoc-type-pratt-parser": "^4.0.0", + "jsdoc-type-pratt-parser": "^7.0.0", "refa": "^0.12.1", "regexp-ast-analysis": "^0.7.1", "scslre": "^0.3.0" }, "engines": { - "node": "^18 || >=20" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": ">=8.44.0" - } - }, - "node_modules/eslint-plugin-regexp/node_modules/jsdoc-type-pratt-parser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.8.0.tgz", - "integrity": "sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" + "eslint": ">=9.38.0" } }, "node_modules/eslint-plugin-unicorn": { - "version": "60.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-60.0.0.tgz", - "integrity": "sha512-QUzTefvP8stfSXsqKQ+vBQSEsXIlAiCduS/V1Em+FKgL9c21U/IIm20/e3MFy1jyCf14tHAhqC1sX8OTy6VUCg==", + "version": "63.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-63.0.0.tgz", + "integrity": "sha512-Iqecl9118uQEXYh7adylgEmGfkn5es3/mlQTLLkd4pXkIk9CTGrAbeUux+YljSa2ohXCBmQQ0+Ej1kZaFgcfkA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "@eslint-community/eslint-utils": "^4.7.0", - "@eslint/plugin-kit": "^0.3.3", + "@babel/helper-validator-identifier": "^7.28.5", + "@eslint-community/eslint-utils": "^4.9.0", "change-case": "^5.4.4", - "ci-info": "^4.3.0", + "ci-info": "^4.3.1", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.44.0", - "esquery": "^1.6.0", + "core-js-compat": "^3.46.0", "find-up-simple": "^1.0.1", - "globals": "^16.3.0", + "globals": "^16.4.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", "regexp-tree": "^0.1.27", - "regjsparser": "^0.12.0", - "semver": "^7.7.2", - "strip-indent": "^4.0.0" + "regjsparser": "^0.13.0", + "semver": "^7.7.3", + "strip-indent": "^4.1.1" }, "engines": { "node": "^20.10.0 || >=21.0.0" @@ -11496,13 +11491,13 @@ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=9.29.0" + "eslint": ">=9.38.0" } }, "node_modules/eslint-plugin-unicorn/node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", "engines": { @@ -11512,43 +11507,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-unicorn/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/strip-indent": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.0.tgz", - "integrity": "sha512-OA95x+JPmL7kc7zCu+e+TeYxEiaIyndRx0OrBcK2QPPH09oAndr2ALvymxWA+Lx1PYYvFUm4O63pRkdJAaW96w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-vue": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.4.0.tgz", - "integrity": "sha512-K6tP0dW8FJVZLQxa2S7LcE1lLw3X8VvB3t887Q6CLrFVxHYBXGANbXvwNzYIu6Ughx1bSJ5BDT0YB3ybPT39lw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.2.tgz", + "integrity": "sha512-4g7ZP3pYcuqd7Zp0pzUKcos0W+RkjBz4EGdhJ92FcYk6v03Ti/GK5NwjgsjxHK+98eXDbHeK7VtX1az7/8doZA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", - "postcss-selector-parser": "^6.0.15", + "postcss-selector-parser": "^7.1.0", "semver": "^7.6.3", "xml-name-validator": "^4.0.0" }, @@ -11556,11 +11525,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { + "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "vue-eslint-parser": "^10.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "vue-eslint-parser": "^10.3.0" }, "peerDependenciesMeta": { + "@stylistic/eslint-plugin": { + "optional": true + }, "@typescript-eslint/parser": { "optional": true } @@ -11580,13 +11553,6 @@ "eslint": ">=9.0.0" } }, - "node_modules/eslint-rule-docs": { - "version": "1.1.235", - "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.235.tgz", - "integrity": "sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==", - "dev": true, - "license": "MIT" - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -11605,88 +11571,263 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esprima": { - "version": "4.0.1", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "license": "BSD-2-Clause", @@ -11699,9 +11840,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -11734,10 +11875,13 @@ } }, "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, "node_modules/esutils": { "version": "2.0.3", @@ -11775,6 +11919,15 @@ "node": ">=0.8.x" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -11798,10 +11951,22 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11850,9 +12015,9 @@ } }, "node_modules/fake-indexeddb": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-6.2.2.tgz", - "integrity": "sha512-SGbf7fzjeHz3+12NO1dYigcYn4ivviaeULV5yY5rdGihBvvgwMds4r4UBbNIUMwkze57KTDm32rq3j1Az8mzEw==", + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-6.2.5.tgz", + "integrity": "sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11903,6 +12068,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -11913,9 +12079,9 @@ "license": "MIT" }, "node_modules/fast-npm-meta": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-0.4.7.tgz", - "integrity": "sha512-aZU3i3eRcSb2NCq8i6N6IlyiTyF6vqAqzBGl2NBF6ngNx/GIqfYbkLDIKZ4z4P0o/RmtsFnVqHwdrSm13o4tnQ==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-0.4.8.tgz", + "integrity": "sha512-ybZVlDZ2PkO79dosM+6CLZfKWRH8MF0PiWlw8M4mVWJl8IEJrPfxYc7Tsu830Dwj/R96LKXfePGTSzKWbPJ08w==", "dev": true, "license": "MIT", "funding": { @@ -11928,10 +12094,27 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -11944,10 +12127,20 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -12023,18 +12216,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/figures/node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -12079,17 +12260,17 @@ } }, "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -12107,107 +12288,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-up/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" } }, - "node_modules/find-up/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16" } }, - "node_modules/find-up/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fix-dts-default-cjs-exports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", - "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-string": "^0.30.17", - "mlly": "^1.7.4", - "rollup": "^4.34.8" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -12217,6 +12327,21 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", "license": "MIT" }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -12246,16 +12371,16 @@ } }, "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "dev": true, "license": "MIT", "engines": { "node": "*" }, "funding": { - "type": "patreon", + "type": "github", "url": "https://github.com/sponsors/rawify" } }, @@ -12270,10 +12395,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -12293,14 +12417,63 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/fuse.js": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", - "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.4.1.tgz", + "integrity": "sha512-AY7lKAXK71hi3WgUvDy6oZL67UEHOOtvCAwVdOXHyJd6ZzftBy7QqxuXt4HxmmAhYjmp/YCuOELZtIvAdlZ+fw==", "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/krisk" + } + }, + "node_modules/fzf": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fzf/-/fzf-0.5.2.tgz", + "integrity": "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, "node_modules/gensync": { @@ -12314,9 +12487,9 @@ } }, "node_modules/get-amd-module-type": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-6.0.1.tgz", - "integrity": "sha512-MtjsmYiCXcYDDrGqtNbeIYdAl85n+5mSv2r3FbzER/YV3ZILw4HNNIw34HuV5pyl0jzs6GFYU1VHVEefhgcNHQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-6.0.2.tgz", + "integrity": "sha512-7zShVYAYtMnj9S65CfN+hvpBCByfuB1OY8xID01nZEzXTZbx4YyysAfi+nMl95JSR6odt4q8TCj2W63KAoyVLQ==", "license": "MIT", "dependencies": { "ast-module-types": "^6.0.1", @@ -12335,10 +12508,47 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-port": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", - "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.2.0.tgz", + "integrity": "sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==", "license": "MIT", "engines": { "node": ">=16" @@ -12353,6 +12563,19 @@ "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", "license": "MIT" }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -12365,10 +12588,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { @@ -12379,47 +12619,19 @@ } }, "node_modules/giget": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", - "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz", + "integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==", "license": "MIT", - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.0", - "defu": "^6.1.4", - "node-fetch-native": "^1.6.6", - "nypm": "^0.6.0", - "pathe": "^2.0.3" - }, "bin": { "giget": "dist/cli.mjs" } }, - "node_modules/git-up": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", - "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-ssh": "^1.4.0", - "parse-url": "^9.2.0" - } - }, - "node_modules/git-url-parse": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz", - "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==", - "dev": true, - "license": "MIT", - "dependencies": { - "git-up": "^8.1.0" - } - }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -12449,6 +12661,36 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/global-directory": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", @@ -12466,9 +12708,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", "dev": true, "license": "MIT", "engines": { @@ -12478,22 +12720,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz", + "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" }, "engines": { - "node": ">=10" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -12521,11 +12792,17 @@ "node": ">=0.6.0" } }, - "node_modules/gotrue-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gotrue-js/-/gotrue-js-1.0.1.tgz", - "integrity": "sha512-ZynwwM4bEo2y5yNWO3/Ynbx1AvQz9ONJSM9tB1jpooAvDPevGdvgeFP3NwM59FAlkd0szSkQRAhjINMkJSDfAQ==", - "license": "MIT" + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/graceful-fs": { "version": "4.2.11", @@ -12533,23 +12810,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/graphql": { - "version": "16.11.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", - "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } - }, "node_modules/gzip-size": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", @@ -12567,34 +12827,71 @@ } }, "node_modules/h3": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz", - "integrity": "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", "license": "MIT", "dependencies": { - "cookie-es": "^1.2.2", + "cookie-es": "^1.2.3", "crossws": "^0.3.5", - "defu": "^6.1.4", + "defu": "^6.1.6", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", - "node-mock-http": "^1.0.2", + "node-mock-http": "^1.0.4", "radix3": "^1.1.2", - "ufo": "^1.6.1", + "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "node_modules/h3-next": { + "name": "h3", + "version": "2.0.1-rc.22", + "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.22.tgz", + "integrity": "sha512-Esv0DMIuPkCTSWCA0vO73vcTqwzH1wjSrAO1TXNu/K3up1sZHa9EKMapbmxCDYBeymC3fVTk4qxp7ogQWQ+KgA==", "dev": true, "license": "MIT", + "dependencies": { + "rou3": "^0.8.1", + "srvx": "^0.11.15" + }, + "bin": { + "h3": "bin/h3.mjs" + }, "engines": { - "node": ">=6" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", + "node": ">=20.11.1" + }, + "peerDependencies": { + "crossws": "^0.4.1" + }, + "peerDependenciesMeta": { + "crossws": { + "optional": true + } + } + }, + "node_modules/h3/node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", @@ -12602,34 +12899,71 @@ "node": ">=8" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", - "bin": { - "he": "bin/he" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/headers-polyfill": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", - "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", - "dev": true, - "license": "MIT" + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/hookable": { "version": "5.5.3", @@ -12650,60 +12984,48 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" }, - "engines": { - "node": ">= 14" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-shutdown": { @@ -12730,9 +13052,9 @@ } }, "node_modules/httpxy": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.1.7.tgz", - "integrity": "sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.5.3.tgz", + "integrity": "sha512-SMS9V6Sn7VWaS11lYhoAr0ceoaiolTWf4jYdJn0NJhCdKMu9R2H9Fh0LBDWBHQF6HRLI1PmaePYsjanSpE5PEw==", "dev": true, "license": "MIT" }, @@ -12761,21 +13083,6 @@ "url": "https://github.com/sponsors/typicode" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -12797,10 +13104,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "license": "MIT", "engines": { "node": ">= 4" @@ -12867,34 +13173,39 @@ } }, "node_modules/impound": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/impound/-/impound-1.0.0.tgz", - "integrity": "sha512-8lAJ+1Arw2sMaZ9HE2ZmL5zOcMnt18s6+7Xqgq2aUVy4P1nlzAyPtzCDxsk51KVFwHEEdc6OWvUyqwHwhRYaug==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/impound/-/impound-1.1.5.tgz", + "integrity": "sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA==", "dev": true, "license": "MIT", "dependencies": { - "exsolve": "^1.0.5", - "mocked-exports": "^0.1.1", + "@jridgewell/trace-mapping": "^0.3.31", + "es-module-lexer": "^2.0.0", "pathe": "^2.0.3", - "unplugin": "^2.3.2", - "unplugin-utils": "^0.2.4" + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1" } }, - "node_modules/impound/node_modules/unplugin-utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", - "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", + "node_modules/impound/node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/impound/node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", "dev": true, "license": "MIT", "dependencies": { - "pathe": "^2.0.3", - "picomatch": "^4.0.3" + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" }, "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/imurmurhash": { @@ -12908,19 +13219,21 @@ } }, "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/index-to-position": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", - "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", "license": "MIT", "engines": { "node": ">=18" @@ -12945,22 +13258,34 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ioredis": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz", - "integrity": "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==", + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.11.1.tgz", + "integrity": "sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==", "devOptional": true, "license": "MIT", "dependencies": { - "@ioredis/commands": "^1.3.0", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "denque": "^2.1.0", - "lodash.defaults": "^4.2.0", - "lodash.isarguments": "^3.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" + "@ioredis/commands": "1.10.0", + "cluster-key-slot": "1.1.1", + "debug": "4.4.3", + "denque": "2.1.0", + "redis-errors": "1.2.0", + "redis-parser": "3.0.0", + "standard-as-callback": "2.1.0" }, "engines": { "node": ">=12.22.0" @@ -12997,6 +13322,15 @@ "ipx": "bin/ipx.mjs" } }, + "node_modules/ipx/node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/iron-webcrypto": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", @@ -13006,21 +13340,72 @@ "url": "https://github.com/sponsors/brc-dd" } }, - "node_modules/irregular-plurals": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", - "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", - "dev": true, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-builtin-module": { "version": "5.0.0", @@ -13038,13 +13423,58 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -13057,6 +13487,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -13077,6 +13508,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -13086,6 +13532,25 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -13098,10 +13563,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^3.0.0" @@ -13133,6 +13612,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -13140,10 +13631,22 @@ "dev": true, "license": "MIT" }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-network-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", - "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", "license": "MIT", "engines": { "node": ">=16" @@ -13152,13 +13655,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "dev": true, - "license": "MIT" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -13168,6 +13664,22 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-inside": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", @@ -13181,21 +13693,17 @@ } }, "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, "node_modules/is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -13206,47 +13714,123 @@ "@types/estree": "*" } }, - "node_modules/is-ssh": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", - "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", - "dev": true, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "license": "MIT", "dependencies": { - "protocols": "^2.0.1" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "license": "MIT" - }, "node_modules/is-url-superb": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz", @@ -13259,60 +13843,93 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-what": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", - "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", - "dev": true, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "license": "MIT", "engines": { - "node": ">=12.13" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/mesqueeb" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "license": "MIT", "dependencies": { - "is-inside-container": "^1.0.0" + "call-bound": "^1.0.3" }, "engines": { - "node": ">=16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is64bit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz", - "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "license": "MIT", "dependencies": { - "system-architecture": "^0.1.0" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "license": "MIT" }, "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } }, "node_modules/jackspeak": { "version": "3.4.3", @@ -13329,36 +13946,10 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -13396,10 +13987,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -13409,159 +14010,23 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-5.1.1.tgz", - "integrity": "sha512-DYYlVP1fe4QBMh2xTIs20/YeTz2GYVbWAEZweHSZD+qQ/Cx2d5RShuhhsdk64eTjNq0FeVnteP/qVOgaywSRbg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz", + "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=20.0.0" } }, - "node_modules/jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tldts-core": "^6.1.86" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/jsdom/node_modules/tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/jsdom/node_modules/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "dependencies": { - "tldts": "^6.1.32" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/jsdom/node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/jsdom/node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { "node": ">=6" @@ -13574,20 +14039,10 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", - "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -13693,16 +14148,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -13723,9 +14168,9 @@ } }, "node_modules/knitwork": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.2.0.tgz", - "integrity": "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.3.0.tgz", + "integrity": "sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==", "license": "MIT" }, "node_modules/kuler": { @@ -13751,15 +14196,36 @@ "node": ">=8" } }, + "node_modules/lambda-local/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/lambda-local/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/launch-editor": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", - "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", "dev": true, "license": "MIT", "dependencies": { "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" + "shell-quote": "^1.8.4" } }, "node_modules/lazystream": { @@ -13774,6 +14240,12 @@ "node": ">= 0.6.3" } }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/lazystream/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -13870,7 +14342,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13892,7 +14363,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13914,7 +14384,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13936,7 +14405,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13958,7 +14426,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13975,12 +14442,14 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13997,12 +14466,14 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14019,12 +14490,14 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14041,12 +14514,14 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14068,7 +14543,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14090,647 +14564,1045 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/listhen": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.10.0.tgz", + "integrity": "sha512-kfz4C0OrC6IpaVMtYDJtf6PFjurxe9NBBoDAh/o2p587INryFOO4DQ9OetbCdDrWFt1m1CJKvYrzkGsuPHw8nQ==", + "license": "MIT", + "dependencies": { + "@parcel/watcher": "^2.5.6", + "@parcel/watcher-wasm": "^2.5.6", + "citty": "^0.2.2", + "consola": "^3.4.2", + "crossws": ">=0.2.0 <0.5.0", + "defu": "^6.1.7", + "get-port-please": "^3.2.0", + "h3": "^1.15.11", + "http-shutdown": "^1.2.2", + "jiti": "^2.6.1", + "mlly": "^1.8.2", + "node-forge": "^1.4.0", + "pathe": "^2.0.3", + "std-env": "^4.1.0", + "tinyclip": "^0.1.12", + "ufo": "^1.6.4", + "untun": "^0.1.3", + "uqr": "^0.1.3" + }, + "bin": { + "listen": "bin/listhen.mjs", + "listhen": "bin/listhen.mjs" + } + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/local-pkg": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", + "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-regexp": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.10.0.tgz", + "integrity": "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12", + "mlly": "^1.7.2", + "regexp-tree": "^0.1.27", + "type-level-regexp": "~0.1.17", + "ufo": "^1.5.4", + "unplugin": "^2.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magic-string-ast": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", + "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.19" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/map-obj": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", + "integrity": "sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-options/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { - "node": ">=14" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/antonk52" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "node_modules/mime": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", "dev": true, - "license": "MIT" - }, - "node_modules/listhen": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.9.0.tgz", - "integrity": "sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==", + "funding": [ + "https://github.com/sponsors/broofa" + ], "license": "MIT", - "dependencies": { - "@parcel/watcher": "^2.4.1", - "@parcel/watcher-wasm": "^2.4.1", - "citty": "^0.1.6", - "clipboardy": "^4.0.0", - "consola": "^3.2.3", - "crossws": ">=0.2.0 <0.4.0", - "defu": "^6.1.4", - "get-port-please": "^3.1.2", - "h3": "^1.12.0", - "http-shutdown": "^1.2.2", - "jiti": "^2.1.2", - "mlly": "^1.7.1", - "node-forge": "^1.3.1", - "pathe": "^1.1.2", - "std-env": "^3.7.0", - "ufo": "^1.5.4", - "untun": "^0.1.3", - "uqr": "^0.1.2" - }, "bin": { - "listen": "bin/listhen.mjs", - "listhen": "bin/listhen.mjs" + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" } }, - "node_modules/listhen/node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "license": "MIT" - }, - "node_modules/load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", - "dev": true, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 0.6" } }, - "node_modules/local-pkg": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", - "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "mlly": "^1.7.4", - "pkg-types": "^2.3.0", - "quansync": "^0.2.11" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/local-pkg/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "license": "MIT" - }, - "node_modules/local-pkg/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "license": "MIT", + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", "dependencies": { - "p-locate": "^6.0.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "devOptional": true, - "license": "MIT" + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "license": "MIT" + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } }, - "node_modules/lodash.isarguments": { + "node_modules/minizlib": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "license": "MIT" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "license": "MIT" + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "dev": true, "license": "MIT" }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/mkdist": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/mkdist/-/mkdist-2.4.1.tgz", + "integrity": "sha512-Ezk0gi04GJBkqMfsksICU5Rjoemc4biIekwgrONWVPor2EO/N9nBgN6MZXAf7Yw4mDDhrNyKbdETaHNevfumKg==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "autoprefixer": "^10.4.21", + "citty": "^0.1.6", + "cssnano": "^7.1.1", + "defu": "^6.1.4", + "esbuild": "^0.25.9", + "jiti": "^1.21.7", + "mlly": "^1.8.0", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "postcss": "^8.5.6", + "postcss-nested": "^7.0.2", + "semver": "^7.7.2", + "tinyglobby": "^0.2.15" }, - "engines": { - "node": ">=10" + "bin": { + "mkdist": "dist/cli.cjs" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/logform": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", - "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", - "license": "MIT", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" + "peerDependencies": { + "sass": "^1.92.1", + "typescript": ">=5.9.2", + "vue": "^3.5.21", + "vue-sfc-transformer": "^0.1.1", + "vue-tsc": "^1.8.27 || ^2.0.21 || ^3.0.0" }, - "engines": { - "node": ">= 12.0.0" + "peerDependenciesMeta": { + "sass": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-sfc-transformer": { + "optional": true + }, + "vue-tsc": { + "optional": true + } } }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "node_modules/mkdist/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, - "node_modules/luxon": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", - "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/magic-regexp": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.10.0.tgz", - "integrity": "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==", + "node_modules/mkdist/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "estree-walker": "^3.0.3", - "magic-string": "^0.30.12", - "mlly": "^1.7.2", - "regexp-tree": "^0.1.27", - "type-level-regexp": "~0.1.17", - "ufo": "^1.5.4", - "unplugin": "^2.0.0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/magic-regexp/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/mkdist/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/magic-string-ast": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.2.tgz", - "integrity": "sha512-8ngQgLhcT0t3YBdn9CGkZqCYlvwW9pm7aWJwd7AxseVWf1RU8ZHCQvG1mt3N5vvUme+pXTcHB8G/7fE666U8Vw==", + "node_modules/mkdist/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "magic-string": "^0.30.17" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20.18.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "node": ">=18" } }, - "node_modules/magicast": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", - "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", - "devOptional": true, + "node_modules/mkdist/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "node_modules/mkdist/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/mdn-data": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", - "license": "CC0-1.0" - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "node_modules/mkdist/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.10.0" + "node": ">=18" } }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "node_modules/mkdist/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/meow/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/mkdist/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/meow/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/mkdist/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/meow/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "node_modules/mkdist/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "node_modules/mkdist/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/meow/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/mkdist/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "ISC" - }, - "node_modules/merge-options": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", - "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", "license": "MIT", - "dependencies": { - "is-plain-obj": "^2.1.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/mkdist/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/mkdist/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8.6" + "node": ">=18" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/mkdist/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">=18" } }, - "node_modules/mime": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz", - "integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa" + "node_modules/mkdist/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" ], + "dev": true, "license": "MIT", - "bin": { - "mime": "bin/cli.js" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">=18" } }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "node_modules/mkdist/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 0.6" + "node": ">=18" } }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "node_modules/mkdist/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 0.6" + "node": ">=18" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "node_modules/mkdist/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "node_modules/mkdist/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "node_modules/mkdist/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "node_modules/mkdist/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "node_modules/mkdist/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 6" + "node": ">=18" } }, - "node_modules/minimist-options/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "node_modules/mkdist/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "node_modules/mkdist/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" } }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "node_modules/mkdist/node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, "license": "MIT", "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" + "consola": "^3.2.3" } }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "node_modules/mkdist/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, - "license": "MIT" + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/mkdist/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } }, "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, "node_modules/mocked-exports": { @@ -14741,9 +15613,9 @@ "license": "MIT" }, "node_modules/module-definition": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-6.0.1.tgz", - "integrity": "sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-6.0.2.tgz", + "integrity": "sha512-SvAU3lB0+Yjbq55yHY3wkRZBOh+fhU1SnIF3IFbTewv6mtAh7yUT8ACHAJ2mGIJ7tCes2QuCL/cl6m0JSZ/ArA==", "license": "MIT", "dependencies": { "ast-module-types": "^6.0.1", @@ -14778,52 +15650,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/msw": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.2.tgz", - "integrity": "sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.39.1", - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "rettime": "^0.7.0", - "strict-event-emitter": "^0.5.1", - "tough-cookie": "^6.0.0", - "type-fest": "^4.26.1", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.8.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/muggle-string": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", @@ -14831,16 +15657,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -14854,9 +15670,10 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz", + "integrity": "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==", + "dev": true, "funding": [ { "type": "github", @@ -14865,23 +15682,23 @@ ], "license": "MIT", "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18 || >=20" } }, "node_modules/nanotar": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.2.0.tgz", - "integrity": "sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.3.0.tgz", + "integrity": "sha512-Kv2JYYiCzt16Kt5QwAc9BFG89xfPNBx+oQL4GQXD9nLqPkZBiNaqaCWtwnbk/q7UVsTYevvM1b0UF8zmEI4pCg==", "dev": true, "license": "MIT" }, "node_modules/napi-postinstall": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz", - "integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", "dev": true, "license": "MIT", "bin": { @@ -14908,81 +15725,81 @@ "license": "MIT" }, "node_modules/nitropack": { - "version": "2.12.6", - "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.12.6.tgz", - "integrity": "sha512-DEq31s0SP4/Z5DIoVBRo9DbWFPWwIoYD4cQMEz7eE+iJMiAP+1k9A3B9kcc6Ihc0jDJmfUcHYyh6h2XlynCx6g==", + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.13.4.tgz", + "integrity": "sha512-tX7bT6zxNeMwkc6hxHiZeUoTOjVrcjoh1Z3cmxOlodIqjl4HISgqfGOmkWSayky3Nv9Z5+KQH52F8nmXJY5AAA==", "dev": true, "license": "MIT", "dependencies": { - "@cloudflare/kv-asset-handler": "^0.4.0", - "@rollup/plugin-alias": "^5.1.1", - "@rollup/plugin-commonjs": "^28.0.6", + "@cloudflare/kv-asset-handler": "^0.4.2", + "@rollup/plugin-alias": "^6.0.0", + "@rollup/plugin-commonjs": "^29.0.2", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.1", - "@rollup/plugin-replace": "^6.0.2", - "@rollup/plugin-terser": "^0.4.4", - "@vercel/nft": "^0.30.1", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@vercel/nft": "^1.5.0", "archiver": "^7.0.1", - "c12": "^3.2.0", - "chokidar": "^4.0.3", - "citty": "^0.1.6", + "c12": "^3.3.4", + "chokidar": "^5.0.0", + "citty": "^0.2.2", "compatx": "^0.2.0", - "confbox": "^0.2.2", + "confbox": "^0.2.4", "consola": "^3.4.2", - "cookie-es": "^2.0.0", - "croner": "^9.1.0", + "cookie-es": "^2.0.1", + "croner": "^10.0.1", "crossws": "^0.3.5", - "db0": "^0.3.2", - "defu": "^6.1.4", + "db0": "^0.3.4", + "defu": "^6.1.7", "destr": "^2.0.5", - "dot-prop": "^9.0.0", - "esbuild": "^0.25.9", + "dot-prop": "^10.1.0", + "esbuild": "^0.28.0", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", - "exsolve": "^1.0.7", - "globby": "^14.1.0", + "exsolve": "^1.0.8", + "globby": "^16.2.0", "gzip-size": "^7.0.0", - "h3": "^1.15.4", + "h3": "^1.15.11", "hookable": "^5.5.3", - "httpxy": "^0.1.7", - "ioredis": "^5.7.0", - "jiti": "^2.5.1", + "httpxy": "^0.5.1", + "ioredis": "^5.10.1", + "jiti": "^2.6.1", "klona": "^2.0.6", - "knitwork": "^1.2.0", - "listhen": "^1.9.0", - "magic-string": "^0.30.19", - "magicast": "^0.3.5", - "mime": "^4.0.7", - "mlly": "^1.8.0", + "knitwork": "^1.3.0", + "listhen": "^1.9.1", + "magic-string": "^0.30.21", + "magicast": "^0.5.2", + "mime": "^4.1.0", + "mlly": "^1.8.2", "node-fetch-native": "^1.6.7", - "node-mock-http": "^1.0.3", - "ofetch": "^1.4.1", + "node-mock-http": "^1.0.4", + "ofetch": "^1.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", - "pkg-types": "^2.3.0", - "pretty-bytes": "^7.0.1", + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.1", + "pretty-bytes": "^7.1.0", "radix3": "^1.1.2", - "rollup": "^4.50.1", - "rollup-plugin-visualizer": "^6.0.3", + "rollup": "^4.60.2", + "rollup-plugin-visualizer": "^7.0.1", "scule": "^1.3.0", - "semver": "^7.7.2", + "semver": "^7.7.4", "serve-placeholder": "^2.0.2", - "serve-static": "^2.2.0", + "serve-static": "^2.2.1", "source-map": "^0.7.6", - "std-env": "^3.9.0", - "ufo": "^1.6.1", + "std-env": "^4.1.0", + "ufo": "^1.6.4", "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", - "unctx": "^2.4.1", - "unenv": "^2.0.0-rc.21", - "unimport": "^5.2.0", - "unplugin-utils": "^0.3.0", - "unstorage": "^1.17.1", + "unctx": "^2.5.0", + "unenv": "2.0.0-rc.24", + "unimport": "^6.2.0", + "unplugin-utils": "^0.3.1", + "unstorage": "^1.17.5", "untyped": "^2.0.0", - "unwasm": "^0.3.11", - "youch": "^4.1.0-beta.11", + "unwasm": "^0.5.3", + "youch": "^4.1.1", "youch-core": "^0.3.3" }, "bin": { @@ -15002,9 +15819,9 @@ } }, "node_modules/nitropack/node_modules/@vercel/nft": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.30.1.tgz", - "integrity": "sha512-2mgJZv4AYBFkD/nJ4QmiX5Ymxi+AisPLPcS/KPXVqniyQNqKXX+wjieAbDXQP3HcogfEbpHoRMs49Cd4pfkk8g==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.10.2.tgz", + "integrity": "sha512-w+WyX5Ulmj4dtTZrxaulqrjaLZHSbnPzx75SJsTNYmotKsqn1JlLnDJa+lz5hn90HJofhl/2MAtw0mCrgM3qYw==", "dev": true, "license": "MIT", "dependencies": { @@ -15015,7 +15832,7 @@ "async-sema": "^3.1.1", "bindings": "^1.4.0", "estree-walker": "2.0.2", - "glob": "^10.4.5", + "glob": "^13.0.0", "graceful-fs": "^4.2.9", "node-gyp-build": "^4.2.2", "picomatch": "^4.0.2", @@ -15025,130 +15842,147 @@ "nft": "out/cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, - "node_modules/nitropack/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "node_modules/nitropack/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/nitropack/node_modules/cookie-es": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", - "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.1.tgz", + "integrity": "sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==", "dev": true, "license": "MIT" }, - "node_modules/nitropack/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "node_modules/nitropack/node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "uncrypto": "^0.1.3" } }, - "node_modules/nitropack/node_modules/globby": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", - "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "node_modules/nitropack/node_modules/dot-prop": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-10.1.0.tgz", + "integrity": "sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==", "dev": true, "license": "MIT", "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.3", - "ignore": "^7.0.3", - "path-type": "^6.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" + "type-fest": "^5.0.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nitropack/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/nitropack/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } + "license": "MIT" }, - "node_modules/nitropack/node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "node_modules/nitropack/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, "engines": { - "node": ">=18" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/nitropack/node_modules/perfect-debounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", - "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "node_modules/nitropack/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, - "license": "MIT" + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, - "node_modules/nitropack/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/nitropack/node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "node_modules/nitropack/node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "node_modules/nitropack/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, "engines": { - "node": ">=14.16" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/nitropack/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "node_modules/nitropack/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/nitropack/node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "node_modules/nitropack/node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", "dev": true, - "license": "MIT", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -15180,24 +16014,49 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", "license": "MIT", "dependencies": { - "whatwg-url": "^5.0.0" + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" }, "engines": { - "node": "4.x || >=6.0.0" + "node": ">= 0.4" }, - "peerDependencies": { - "encoding": "^0.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/node-fetch-native": { @@ -15207,9 +16066,9 @@ "license": "MIT" }, "node_modules/node-forge": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -15227,25 +16086,28 @@ } }, "node_modules/node-mock-http": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.3.tgz", - "integrity": "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.20.tgz", - "integrity": "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==", + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/node-source-walk": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-7.0.1.tgz", - "integrity": "sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-7.0.2.tgz", + "integrity": "sha512-71kFFjYaSshDTA8/a2HiTYPLdASWjLJxUyJxGE+ffxU+KhxSBtM9kiLUX+R2yooFdSFKMFpi4n3PFtDy6qXv8A==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.7" + "@babel/parser": "^7.29.0" }, "engines": { "node": ">=18" @@ -15285,107 +16147,21 @@ "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "license": "BSD-2-Clause", "dependencies": { - "hosted-git-info": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", - "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-run-all2": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.4.tgz", - "integrity": "sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "cross-spawn": "^7.0.6", - "memorystream": "^0.3.1", - "picomatch": "^4.0.2", - "pidtree": "^0.6.0", - "read-package-json-fast": "^4.0.0", - "shell-quote": "^1.7.3", - "which": "^5.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "npm-run-all2": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": "^20.5.0 || >=22.0.0", - "npm": ">= 10" - } - }, - "node_modules/npm-run-all2/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm-run-all2/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/npm-run-all2/node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/npm-run-path": { @@ -15403,18 +16179,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -15428,82 +16192,75 @@ } }, "node_modules/nuxt": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.1.1.tgz", - "integrity": "sha512-xLDbWgz3ggAfUjcbmTzmLLPWOEB61thnjnqyasZlYyh/Ty2EDT1qvOiM9HT+9ycBxElI2DmyYewY8WOPRxWMiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nuxt/cli": "^3.28.0", - "@nuxt/devalue": "^2.0.2", - "@nuxt/devtools": "^2.6.3", - "@nuxt/kit": "4.1.1", - "@nuxt/schema": "4.1.1", - "@nuxt/telemetry": "^2.6.6", - "@nuxt/vite-builder": "4.1.1", - "@unhead/vue": "^2.0.14", - "@vue/shared": "^3.5.20", - "c12": "^3.2.0", - "chokidar": "^4.0.3", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.7.tgz", + "integrity": "sha512-4ASIbcOVF2O1HJqoKRVntxOphl9zmikgmj25D9c93l795yp8x0f4TItzrnT0xyrFxMkpL6z3rHhrfQQfoxNXxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@dxup/nuxt": "^0.4.1", + "@nuxt/cli": "^3.35.2", + "@nuxt/devtools": "^3.2.4", + "@nuxt/kit": "4.4.7", + "@nuxt/nitro-server": "4.4.7", + "@nuxt/schema": "4.4.7", + "@nuxt/telemetry": "^2.8.0", + "@nuxt/vite-builder": "4.4.7", + "@unhead/vue": "^2.1.15", + "@vue/shared": "^3.5.35", + "chokidar": "^5.0.0", "compatx": "^0.2.0", "consola": "^3.4.2", - "cookie-es": "^2.0.0", - "defu": "^6.1.4", - "destr": "^2.0.5", - "devalue": "^5.3.2", + "cookie-es": "^3.1.1", + "defu": "^6.1.7", + "devalue": "^5.8.1", "errx": "^0.1.0", - "esbuild": "^0.25.9", "escape-string-regexp": "^5.0.0", - "estree-walker": "^3.0.3", - "exsolve": "^1.0.7", - "h3": "^1.15.4", - "hookable": "^5.5.3", + "exsolve": "^1.0.8", + "hookable": "^6.1.1", "ignore": "^7.0.5", - "impound": "^1.0.0", - "jiti": "^2.5.1", + "impound": "^1.1.5", + "jiti": "^2.7.0", "klona": "^2.0.6", - "knitwork": "^1.2.0", - "magic-string": "^0.30.18", - "mlly": "^1.8.0", - "mocked-exports": "^0.1.1", - "nanotar": "^0.2.0", - "nitropack": "^2.12.4", - "nypm": "^0.6.1", - "ofetch": "^1.4.1", + "knitwork": "^1.3.0", + "magic-string": "^0.30.21", + "mlly": "^1.8.2", + "nanotar": "^0.3.0", + "nypm": "^0.6.6", + "ofetch": "^1.5.1", "ohash": "^2.0.11", - "on-change": "^5.0.1", - "oxc-minify": "^0.86.0", - "oxc-parser": "^0.86.0", - "oxc-transform": "^0.86.0", - "oxc-walker": "^0.4.0", + "on-change": "^6.0.2", + "oxc-minify": "^0.133.0", + "oxc-parser": "^0.133.0", + "oxc-transform": "^0.133.0", + "oxc-walker": "^1.0.0", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", - "pkg-types": "^2.3.0", - "radix3": "^1.1.2", + "perfect-debounce": "^2.1.0", + "picomatch": "^4.0.4", + "pkg-types": "^2.3.1", + "rou3": "^0.8.1", "scule": "^1.3.0", - "semver": "^7.7.2", - "std-env": "^3.9.0", - "tinyglobby": "0.2.14", - "ufo": "^1.6.1", + "semver": "^7.8.1", + "std-env": "^4.1.0", + "tinyglobby": "^0.2.17", + "ufo": "^1.6.4", "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", - "unctx": "^2.4.1", - "unimport": "^5.2.0", - "unplugin": "^2.3.10", - "unplugin-vue-router": "^0.15.0", - "unstorage": "^1.17.0", + "unctx": "^2.5.0", + "unhead": "^3.1.1", + "unimport": "^6.3.0", + "unplugin": "^3.0.0", + "unrouting": "^0.1.7", "untyped": "^2.0.0", - "vue": "^3.5.20", - "vue-bundle-renderer": "^2.1.2", - "vue-devtools-stub": "^0.1.0", - "vue-router": "^4.5.1" + "vue": "^3.5.35", + "vue-router": "^5.1.0" }, "bin": { "nuxi": "bin/nuxt.mjs", "nuxt": "bin/nuxt.mjs" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^22.12.0 || ^24.11.0 || >=26.0.0" }, "peerDependencies": { "@parcel/watcher": "^2.1.0", @@ -15518,177 +16275,375 @@ } } }, - "node_modules/nuxt/node_modules/@nuxt/schema": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.1.1.tgz", - "integrity": "sha512-s4ELQEw6er4kop4e9HkTZ2ByVEvOGic9YJmesr2QI3O+q01CLSZE6aepbRLsq1Hz6bbfq/UrFw8MLuHs7l03aA==", + "node_modules/nuxt/node_modules/@nuxt/devtools": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-3.2.4.tgz", + "integrity": "sha512-VPbFy7hlPzWpEZk4BsuVpNuHq1ZYGV9xezjb7/NGuePuNLqeNn74YZugU+PCtva7OwKhEeTXmMK0Mqo/6+nwNA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "^3.5.20", + "@nuxt/devtools-kit": "3.2.4", + "@nuxt/devtools-wizard": "3.2.4", + "@nuxt/kit": "^4.4.2", + "@vue/devtools-core": "^8.1.0", + "@vue/devtools-kit": "^8.1.0", + "birpc": "^4.0.0", "consola": "^3.4.2", - "defu": "^6.1.4", + "destr": "^2.0.5", + "error-stack-parser-es": "^1.0.5", + "execa": "^8.0.1", + "fast-npm-meta": "^1.4.2", + "get-port-please": "^3.2.0", + "hookable": "^6.1.0", + "image-meta": "^0.2.2", + "is-installed-globally": "^1.0.0", + "launch-editor": "^2.13.1", + "local-pkg": "^1.1.2", + "magicast": "^0.5.2", + "nypm": "^0.6.5", + "ohash": "^2.0.11", "pathe": "^2.0.3", - "std-env": "^3.9.0", - "ufo": "1.6.1" + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.0", + "semver": "^7.7.4", + "simple-git": "^3.33.0", + "sirv": "^3.0.2", + "structured-clone-es": "^2.0.0", + "tinyglobby": "^0.2.15", + "vite-plugin-inspect": "^11.3.3", + "vite-plugin-vue-tracer": "^1.3.0", + "which": "^6.0.1", + "ws": "^8.19.0" }, - "engines": { - "node": "^14.18.0 || >=16.10.0" + "bin": { + "devtools": "cli.mjs" + }, + "peerDependencies": { + "@vitejs/devtools": "*", + "vite": ">=6.0" + }, + "peerDependenciesMeta": { + "@vitejs/devtools": { + "optional": true + } } }, - "node_modules/nuxt/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "node_modules/nuxt/node_modules/@nuxt/devtools-kit": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-3.2.4.tgz", + "integrity": "sha512-Yxy2Xgmq5hf3dQy983V0xh0OJV2mYwRZz9eVIGc3EaribdFGPDNGMMbYqX9qCty3Pbxn/bCF3J0UyPaNlHVayQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^4.4.2", + "execa": "^8.0.1" + }, + "peerDependencies": { + "vite": ">=6.0" + } + }, + "node_modules/nuxt/node_modules/@nuxt/devtools-wizard": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-3.2.4.tgz", + "integrity": "sha512-5tu2+Quu9XTxwtpzM8CUN0UKn/bzZIfJcoGd+at5Yy1RiUQJ4E52tRK0idW1rMSUDkbkvX3dSnu8Tpj7SAtWdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/prompts": "^1.1.0", + "consola": "^3.4.2", + "diff": "^8.0.3", + "execa": "^8.0.1", + "magicast": "^0.5.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "semver": "^7.7.4" + }, + "bin": { + "devtools-wizard": "cli.mjs" + } + }, + "node_modules/nuxt/node_modules/@nuxt/devtools/node_modules/birpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz", + "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/nuxt/node_modules/@vue/devtools-core": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.1.2.tgz", + "integrity": "sha512-ZGGyaSBP4/+bN2Nd9ZHNYAVDRIzMw1rv2RyXWtyZlo6mQal+IDmTvKY4V+DjAEBhaXt30mHmsgYp1yXJ/2tIWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.1.2", + "@vue/devtools-shared": "^8.1.2" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/nuxt/node_modules/@vue/devtools-kit": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz", + "integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.1.2", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/nuxt/node_modules/@vue/devtools-kit/node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", "dev": true, "license": "MIT" }, - "node_modules/nuxt/node_modules/cookie-es": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", - "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", + "node_modules/nuxt/node_modules/@vue/devtools-shared": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz", + "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==", "dev": true, "license": "MIT" }, - "node_modules/nuxt/node_modules/escape-string-regexp": { + "node_modules/nuxt/node_modules/chokidar": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, "engines": { - "node": ">=12" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/nuxt/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/nuxt/node_modules/cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "license": "MIT" }, - "node_modules/nuxt/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/nuxt/node_modules/fast-npm-meta": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-1.5.1.tgz", + "integrity": "sha512-tWhw7z4jFuQgZB9tbQyUh5BY9nNd/wimM+fBLfmmJjakkJDNvbJKm0nQ5ruPKC0us1HGg7L6iBk1fxpSzcgSaA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 4" + "bin": { + "fast-npm-meta": "dist/cli.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/nuxt/node_modules/perfect-debounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", - "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "node_modules/nuxt/node_modules/hookable": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.1.1.tgz", + "integrity": "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==", "dev": true, "license": "MIT" }, - "node_modules/nuxt/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/nuxt/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/nuxt/node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "node_modules/nuxt/node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "node_modules/nuxt/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" - }, "engines": { - "node": ">=12.0.0" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "node_modules/nuxt/node_modules/structured-clone-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-2.0.0.tgz", + "integrity": "sha512-5UuAHmBLXYPCl22xWJrFuGmIhBKQzxISPVz6E7nmTmTcAOpUzlbjKJsRrCE4vADmMQ0dzeCnlWn9XufnAGf76Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/nuxt/node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } }, "node_modules/nypm": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", - "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.6.tgz", + "integrity": "sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==", + "dev": true, "license": "MIT", "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.2", + "citty": "^0.2.2", "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "tinyexec": "^1.0.1" + "tinyexec": "^1.1.1" }, "bin": { "nypm": "dist/cli.mjs" }, "engines": { - "node": "^14.16.0 || >=16.10.0" + "node": ">=18" } }, - "node_modules/nypm/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-deep-merge": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.1.tgz", + "integrity": "sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==", + "dev": true, "license": "MIT" }, - "node_modules/nypm/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/nypm/node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "license": "MIT" + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/obug": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.2.tgz", + "integrity": "sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==", "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.20.0" } }, "node_modules/ofetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz", - "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", "license": "MIT", "dependencies": { - "destr": "^2.0.3", - "node-fetch-native": "^1.6.4", - "ufo": "^1.5.4" + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" } }, "node_modules/ohash": { @@ -15704,13 +16659,13 @@ "license": "MIT" }, "node_modules/on-change": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/on-change/-/on-change-5.0.1.tgz", - "integrity": "sha512-n7THCP7RkyReRSLkJb8kUWoNsxUIBxTkIp3JKno+sEz6o/9AJ3w3P9fzQkITEkMwyTKJjZciF3v/pVoouxZZMg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/on-change/-/on-change-6.0.2.tgz", + "integrity": "sha512-08+12qcOVEA0fS9g/VxKS27HaT94nRutUT77J2dr8zv/unzXopvhBuF8tNLWsoLQ5IgrQ6eptGeGqUYat82U1w==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sindresorhus/on-change?sponsor=1" @@ -15763,19 +16718,21 @@ } }, "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", "dev": true, "license": "MIT", "dependencies": { - "default-browser": "^5.2.1", + "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -15799,128 +16756,179 @@ "node": ">= 0.8.0" } }, - "node_modules/outvariant": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", - "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", - "dev": true, - "license": "MIT" + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/oxc-minify": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.86.0.tgz", - "integrity": "sha512-pjtM94KElw/RxF3R1ls1ADcBUyZcrCgn0qeL4nD8cOotfzeVFa0xXwQQeCkk+5GPiOqdRApNFuJvK//lQgpqJw==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.133.0.tgz", + "integrity": "sha512-6bNsYU+5WNIaNHB16zHnL24cUaJuKiPzUvjENoMale3+U8ZBMbGYgdgt//frx0ge7UcgEGIpqtukGGNPT0kxfQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-minify/binding-android-arm64": "0.86.0", - "@oxc-minify/binding-darwin-arm64": "0.86.0", - "@oxc-minify/binding-darwin-x64": "0.86.0", - "@oxc-minify/binding-freebsd-x64": "0.86.0", - "@oxc-minify/binding-linux-arm-gnueabihf": "0.86.0", - "@oxc-minify/binding-linux-arm-musleabihf": "0.86.0", - "@oxc-minify/binding-linux-arm64-gnu": "0.86.0", - "@oxc-minify/binding-linux-arm64-musl": "0.86.0", - "@oxc-minify/binding-linux-riscv64-gnu": "0.86.0", - "@oxc-minify/binding-linux-s390x-gnu": "0.86.0", - "@oxc-minify/binding-linux-x64-gnu": "0.86.0", - "@oxc-minify/binding-linux-x64-musl": "0.86.0", - "@oxc-minify/binding-wasm32-wasi": "0.86.0", - "@oxc-minify/binding-win32-arm64-msvc": "0.86.0", - "@oxc-minify/binding-win32-x64-msvc": "0.86.0" + "@oxc-minify/binding-android-arm-eabi": "0.133.0", + "@oxc-minify/binding-android-arm64": "0.133.0", + "@oxc-minify/binding-darwin-arm64": "0.133.0", + "@oxc-minify/binding-darwin-x64": "0.133.0", + "@oxc-minify/binding-freebsd-x64": "0.133.0", + "@oxc-minify/binding-linux-arm-gnueabihf": "0.133.0", + "@oxc-minify/binding-linux-arm-musleabihf": "0.133.0", + "@oxc-minify/binding-linux-arm64-gnu": "0.133.0", + "@oxc-minify/binding-linux-arm64-musl": "0.133.0", + "@oxc-minify/binding-linux-ppc64-gnu": "0.133.0", + "@oxc-minify/binding-linux-riscv64-gnu": "0.133.0", + "@oxc-minify/binding-linux-riscv64-musl": "0.133.0", + "@oxc-minify/binding-linux-s390x-gnu": "0.133.0", + "@oxc-minify/binding-linux-x64-gnu": "0.133.0", + "@oxc-minify/binding-linux-x64-musl": "0.133.0", + "@oxc-minify/binding-openharmony-arm64": "0.133.0", + "@oxc-minify/binding-wasm32-wasi": "0.133.0", + "@oxc-minify/binding-win32-arm64-msvc": "0.133.0", + "@oxc-minify/binding-win32-ia32-msvc": "0.133.0", + "@oxc-minify/binding-win32-x64-msvc": "0.133.0" } }, "node_modules/oxc-parser": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.86.0.tgz", - "integrity": "sha512-v9+uomgqyLSxlq3qlaMqJJtXg2+rUsa368p/zkmgi5OMGmcZAtZt5GIeSVFF84iNET+08Hdx/rUtd/FyIdfNFQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.133.0.tgz", + "integrity": "sha512-661RSx+ZcjBmjBYid+Fpp/2F5EbtildpeoZh5HdgnGs+jZ03nqQEQW8yGkt4BGyOC3OMPDQQRl8M5kqD2/g6jw==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "^0.86.0" + "@oxc-project/types": "^0.133.0" }, "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-parser/binding-android-arm64": "0.86.0", - "@oxc-parser/binding-darwin-arm64": "0.86.0", - "@oxc-parser/binding-darwin-x64": "0.86.0", - "@oxc-parser/binding-freebsd-x64": "0.86.0", - "@oxc-parser/binding-linux-arm-gnueabihf": "0.86.0", - "@oxc-parser/binding-linux-arm-musleabihf": "0.86.0", - "@oxc-parser/binding-linux-arm64-gnu": "0.86.0", - "@oxc-parser/binding-linux-arm64-musl": "0.86.0", - "@oxc-parser/binding-linux-riscv64-gnu": "0.86.0", - "@oxc-parser/binding-linux-s390x-gnu": "0.86.0", - "@oxc-parser/binding-linux-x64-gnu": "0.86.0", - "@oxc-parser/binding-linux-x64-musl": "0.86.0", - "@oxc-parser/binding-wasm32-wasi": "0.86.0", - "@oxc-parser/binding-win32-arm64-msvc": "0.86.0", - "@oxc-parser/binding-win32-x64-msvc": "0.86.0" + "@oxc-parser/binding-android-arm-eabi": "0.133.0", + "@oxc-parser/binding-android-arm64": "0.133.0", + "@oxc-parser/binding-darwin-arm64": "0.133.0", + "@oxc-parser/binding-darwin-x64": "0.133.0", + "@oxc-parser/binding-freebsd-x64": "0.133.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.133.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.133.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.133.0", + "@oxc-parser/binding-linux-arm64-musl": "0.133.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.133.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.133.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.133.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.133.0", + "@oxc-parser/binding-linux-x64-gnu": "0.133.0", + "@oxc-parser/binding-linux-x64-musl": "0.133.0", + "@oxc-parser/binding-openharmony-arm64": "0.133.0", + "@oxc-parser/binding-wasm32-wasi": "0.133.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.133.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.133.0", + "@oxc-parser/binding-win32-x64-msvc": "0.133.0" } }, "node_modules/oxc-transform": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.86.0.tgz", - "integrity": "sha512-Ghgm/zzjPXROMpljLy4HYBcko/25sixWi2yJQJ6rDu/ltgFB1nEQ4JYCYV5F+ENt0McsJkcgmX5I4dRfDViyDA==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.133.0.tgz", + "integrity": "sha512-9lt2b+hkG6yqe0fUDMHhMk7rgI9uTjNxU9wauQiYnHzc4kZI8JP/OhBqXTIJQTrqRJ8CkSH3O5AhQ13ke28yNg==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-transform/binding-android-arm64": "0.86.0", - "@oxc-transform/binding-darwin-arm64": "0.86.0", - "@oxc-transform/binding-darwin-x64": "0.86.0", - "@oxc-transform/binding-freebsd-x64": "0.86.0", - "@oxc-transform/binding-linux-arm-gnueabihf": "0.86.0", - "@oxc-transform/binding-linux-arm-musleabihf": "0.86.0", - "@oxc-transform/binding-linux-arm64-gnu": "0.86.0", - "@oxc-transform/binding-linux-arm64-musl": "0.86.0", - "@oxc-transform/binding-linux-riscv64-gnu": "0.86.0", - "@oxc-transform/binding-linux-s390x-gnu": "0.86.0", - "@oxc-transform/binding-linux-x64-gnu": "0.86.0", - "@oxc-transform/binding-linux-x64-musl": "0.86.0", - "@oxc-transform/binding-wasm32-wasi": "0.86.0", - "@oxc-transform/binding-win32-arm64-msvc": "0.86.0", - "@oxc-transform/binding-win32-x64-msvc": "0.86.0" + "@oxc-transform/binding-android-arm-eabi": "0.133.0", + "@oxc-transform/binding-android-arm64": "0.133.0", + "@oxc-transform/binding-darwin-arm64": "0.133.0", + "@oxc-transform/binding-darwin-x64": "0.133.0", + "@oxc-transform/binding-freebsd-x64": "0.133.0", + "@oxc-transform/binding-linux-arm-gnueabihf": "0.133.0", + "@oxc-transform/binding-linux-arm-musleabihf": "0.133.0", + "@oxc-transform/binding-linux-arm64-gnu": "0.133.0", + "@oxc-transform/binding-linux-arm64-musl": "0.133.0", + "@oxc-transform/binding-linux-ppc64-gnu": "0.133.0", + "@oxc-transform/binding-linux-riscv64-gnu": "0.133.0", + "@oxc-transform/binding-linux-riscv64-musl": "0.133.0", + "@oxc-transform/binding-linux-s390x-gnu": "0.133.0", + "@oxc-transform/binding-linux-x64-gnu": "0.133.0", + "@oxc-transform/binding-linux-x64-musl": "0.133.0", + "@oxc-transform/binding-openharmony-arm64": "0.133.0", + "@oxc-transform/binding-wasm32-wasi": "0.133.0", + "@oxc-transform/binding-win32-arm64-msvc": "0.133.0", + "@oxc-transform/binding-win32-ia32-msvc": "0.133.0", + "@oxc-transform/binding-win32-x64-msvc": "0.133.0" } }, "node_modules/oxc-walker": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.4.0.tgz", - "integrity": "sha512-x5TJAZQD3kRnRBGZ+8uryMZUwkTYddwzBftkqyJIcmpBOXmoK/fwriRKATjZroR2d+aS7+2w1B0oz189bBTwfw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-1.0.0.tgz", + "integrity": "sha512-eMsHflAGfOskpWxtp9xP/f5b96XLEU8ifTd2gOOCkdux9HMxKGy5S1ru0Gh1B3aPu+YbfmWUUVkcb7MrZz3XyQ==", "dev": true, "license": "MIT", "dependencies": { - "estree-walker": "^3.0.3", - "magic-regexp": "^0.10.0" + "magic-regexp": "^0.11.0" }, "peerDependencies": { - "oxc-parser": ">=0.72.0" + "oxc-parser": ">=0.98.0", + "rolldown": ">=1.0.0" + }, + "peerDependenciesMeta": { + "oxc-parser": { + "optional": true + }, + "rolldown": { + "optional": true + } } }, - "node_modules/oxc-walker/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/oxc-walker/node_modules/magic-regexp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.11.0.tgz", + "integrity": "sha512-LG77Z/gVnwz7oaDpD4heX6ryl+lcr4l1B2gnP4MMvt2pGhGC1Dfj7dl1pXpP4ih+VQFLuAadeKVa+lARAzfW+Q==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "magic-string": "^0.30.21", + "regexp-tree": "^0.1.27", + "type-level-regexp": "~0.1.17", + "unplugin": "^3.0.0" + } + }, + "node_modules/oxc-walker/node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/p-event": { @@ -15969,9 +16977,9 @@ } }, "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "license": "MIT", "engines": { "node": ">=18" @@ -16009,611 +17017,819 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/p-wait-for": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-5.0.2.tgz", + "integrity": "sha512-lwx6u1CotQYPVju77R+D0vFomni/AqRfqLmqQ8hekklqZ6gAY9rONh7lBQ0uxWMkC2AuX9b2DVAl8To0NyP1JA==", + "license": "MIT", + "dependencies": { + "p-timeout": "^6.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-gitignore": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-gitignore/-/parse-gitignore-2.0.0.tgz", + "integrity": "sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/parse-imports": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", + "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", + "license": "Apache-2.0 AND MIT", + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 14.16" } }, - "node_modules/p-wait-for": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-5.0.2.tgz", - "integrity": "sha512-lwx6u1CotQYPVju77R+D0vFomni/AqRfqLmqQ8hekklqZ6gAY9rONh7lBQ0uxWMkC2AuX9b2DVAl8To0NyP1JA==", + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, + "node_modules/pg-gateway": { + "version": "0.3.0-beta.4", + "resolved": "https://registry.npmjs.org/pg-gateway/-/pg-gateway-0.3.0-beta.4.tgz", + "integrity": "sha512-CTjsM7Z+0Nx2/dyZ6r8zRsc3f9FScoD5UAOlfUx1Fdv/JOIWvRbF7gou6l6vP+uypXQVoYPgw8xZDXgMGvBa4Q==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", - "dependencies": { - "p-timeout": "^6.0.0" - }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/package-manager-detector": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", - "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==", - "dev": true, + "node_modules/picoquery": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/picoquery/-/picoquery-2.5.0.tgz", + "integrity": "sha512-j1kgOFxtaCyoFCkpoYG2Oj3OdGakadO7HZ7o5CqyRazlmBekKhbDoUnNnXASE07xSY4nDImWZkrZv7toSxMi/g==", "license": "MIT" }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">= 6" } }, - "node_modules/parse-gitignore": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-gitignore/-/parse-gitignore-2.0.0.tgz", - "integrity": "sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==", + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", "license": "MIT", - "engines": { - "node": ">=14" + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" } }, - "node_modules/parse-imports": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", - "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", - "license": "Apache-2.0 AND MIT", + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "es-module-lexer": "^1.5.3", - "slashes": "^3.0.12" + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" }, "engines": { - "node": ">= 18" + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" } }, - "node_modules/parse-imports-exports": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", "dev": true, - "license": "MIT", - "dependencies": { - "parse-statements": "1.0.11" - } - }, - "node_modules/parse-json": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", - "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.1.0", - "type-fest": "^4.39.1" + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" }, "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-path": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", - "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "license": "MIT", - "dependencies": { - "protocols": "^2.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/parse-statements": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "dev": true, - "license": "MIT" + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/parse-url": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz", - "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==", - "dev": true, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "@types/parse-path": "^7.0.0", - "parse-path": "^7.0.0" + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=14.13.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "node_modules/postcss-calc": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", + "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "entities": "^6.0.0" + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, "engines": { - "node": ">=0.12" + "node": "^18.12 || ^20.9 || >=22.0" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "peerDependencies": { + "postcss": "^8.4.38" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/postcss-colormin": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.10.tgz", + "integrity": "sha512-yFr6JezOolHLta/buLE71VKPh2mXursp4saVe98/ol8ZnEWhL+racShqPKlvd/DKWLre/39B6HhcMXf7RZ3hxg==", "dev": true, "license": "MIT", + "dependencies": { + "@colordx/core": "^5.4.3", + "browserslist": "^4.28.2", + "caniuse-api": "^3.0.0", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">= 0.8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "node_modules/postcss-convert-values": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.12.tgz", + "integrity": "sha512-xurKu5qqk4viR3Cp3p4xBR4KfnZm4w4ys6+UBwBmeuBSNkH7+DtLnYOYnOffgtE4yx8sH9S1VZ6RAAvROXzP2Q==", "dev": true, - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/postcss-discard-comments": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.8.tgz", + "integrity": "sha512-CvvS5S9WrXblFXCEJ9nVo+4z+eA7zSC7Z88V1HEJuwlQhlFnYTIjg1xJY+BCUiG2bvICap2tXii4mP22BD108Q==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "node_modules/postcss-discard-duplicates": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.4.tgz", + "integrity": "sha512-VBNn1+EuMZkeGVVtz0gRfbNGtx9IFgAsAV+E2pHtXPrp4qfGBkhTIiAuE/wrb+Y6Pakg9NewAlfTpYIFAWODtw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" + } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/postcss-discard-empty": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.3.tgz", + "integrity": "sha512-M2pyjQCU+/7cMHVtL6bKTHjv0lZnPLMpicgr67Dlth7AbuV9gjVTtUqaRwn6Pp6BwSDspUzhz8SaUrRykJU5Dw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "node_modules/postcss-discard-overridden": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.3.tgz", + "integrity": "sha512-aNovXo9UsZuRNLzHJtp13lHIvinDPfiXBPePpXkSjCbgp++iU2FqE+YxvjIsg6EdyPZsASFbfu+JcBFVsErXIQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14.16" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, - "node_modules/perfect-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "dev": true, - "license": "MIT" - }, - "node_modules/pg": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz", - "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "pg-connection-string": "^2.11.0", - "pg-pool": "^3.11.0", - "pg-protocol": "^1.11.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.3.0" + "node": ">= 18" }, "peerDependencies": { - "pg-native": ">=3.0.1" + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "pg-native": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/pg-cloudflare": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", - "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "node_modules/postcss-merge-longhand": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.7.tgz", + "integrity": "sha512-b3mfYUxR388u5Pt0HPcVIUtUDn/k15UfTY9M+ORW+meCR6JLNxoZffiYvXyOYQoRYQNZyX/UFkMCM/mNHxe1qA==", + "dev": true, "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz", - "integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==", - "license": "MIT" - }, - "node_modules/pg-gateway": { - "version": "0.3.0-beta.4", - "resolved": "https://registry.npmjs.org/pg-gateway/-/pg-gateway-0.3.0-beta.4.tgz", - "integrity": "sha512-CTjsM7Z+0Nx2/dyZ6r8zRsc3f9FScoD5UAOlfUx1Fdv/JOIWvRbF7gou6l6vP+uypXQVoYPgw8xZDXgMGvBa4Q==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^7.0.11" + }, "engines": { - "node": ">=4.0.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/pg-pool": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.11.0.tgz", - "integrity": "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==", + "node_modules/postcss-merge-rules": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.11.tgz", + "integrity": "sha512-SJUPM18g2BmPhf8BVlbwqWz4aK3pLu6u6xjfwEzra7xL6IBR10sUaiB++EzqcVfadPHrKBSMlNdP+XieykhI+Q==", + "dev": true, "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^5.0.3", + "postcss-selector-parser": "^7.1.1" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, "peerDependencies": { - "pg": ">=8.0" + "postcss": "^8.5.13" } }, - "node_modules/pg-protocol": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.11.0.tgz", - "integrity": "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "node_modules/postcss-minify-font-values": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.3.tgz", + "integrity": "sha512-yilG/VOaNI74IylQvAQQxm3/wZVBkXyYUqNUAdxqwtbWUXPsbK1q8Ms0mL83v+f8YicgcyfYCRZtWACUdYajpA==", + "dev": true, "license": "MIT", "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=4" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "node_modules/postcss-minify-gradients": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.5.tgz", + "integrity": "sha512-YraROyQRg3BI1+Hg8E05B/JPdnTm8EDSVu4P2BxdM+CRiOyfmou809+chGIqo6fQqwjPGQ947nbGncSjmTU1WQ==", + "dev": true, "license": "MIT", "dependencies": { - "split2": "^4.1.0" + "@colordx/core": "^5.4.3", + "cssnano-utils": "^5.0.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/postcss-minify-params": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.9.tgz", + "integrity": "sha512-R8itbB8BhlpoYyBm1ou0dD+vJnQ3F6adQipR4UnkCHUwlo+S9WXJaDRg1RHjC8YVAtIdrQzSWvJl40HnGDTKjA==", + "dev": true, "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "cssnano-utils": "^5.0.3", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=12" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/picoquery": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/picoquery/-/picoquery-2.5.0.tgz", - "integrity": "sha512-j1kgOFxtaCyoFCkpoYG2Oj3OdGakadO7HZ7o5CqyRazlmBekKhbDoUnNnXASE07xSY4nDImWZkrZv7toSxMi/g==", - "license": "MIT" - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "node_modules/postcss-minify-selectors": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.1.2.tgz", + "integrity": "sha512-aQtrEWKwqafNlExcKHQvPGsXR2+vlUqqJtf5XsCQcgsSb5PL4wlujWBYDJuWsP4UnQX1YHDHU8qRlD+1PzTQ+Q==", "dev": true, "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-api": "^3.0.0", + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": ">=0.10" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "node_modules/postcss-nested": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-7.0.2.tgz", + "integrity": "sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, "engines": { - "node": ">= 6" + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" } }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "node_modules/postcss-normalize-charset": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.3.tgz", + "integrity": "sha512-NoBfZu8PR4c2NlmjvrqQTzCzLY79hwcSRgNQ3ZiNK0ABzf9kYKloE/jNj+/8GQY1wsm8pRRgANk6ydLH8cwo0Q==", + "dev": true, "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/playwright": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", - "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "node_modules/postcss-normalize-display-values": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.3.tgz", + "integrity": "sha512-ldsCX0QIt05pKIOobZtVQ48wXJecr+czw4+e1/YjVhLMqslShgpVxgPtI2CefURR8oyVoYaU/l829MMwExDMLw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "playwright-core": "1.60.0" - }, - "bin": { - "playwright": "cli.js" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "optionalDependencies": { - "fsevents": "2.3.2" + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/playwright-core": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", - "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "node_modules/postcss-normalize-positions": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.4.tgz", + "integrity": "sha512-VEvlpeGd3Ju1Hqa/oN4jaP3+ms4laYwkEL9N9u+B6k54PZjXbW1n6wI+aVprf1BQXlCYpS5+1pl/7/vHiKgARg==", "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/postcss-normalize-repeat-style": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.4.tgz", + "integrity": "sha512-6mPKlY/8cSaDHxX502wERADarJsccwlky6yIrOapHH2ZgfoKAV94SbiTKfKEs4EEpdazuc3J72WsqeYk7hp9+Q==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/plur": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", - "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "node_modules/postcss-normalize-string": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.3.tgz", + "integrity": "sha512-HnEQPUchi1eznmDKEYrKUTqrprEq97SrpUYClgUkv7V2zRODD9DFoUsYU+m9ZOetmD5ku7fEMZB/lwy8IT6xVQ==", "dev": true, "license": "MIT", "dependencies": { - "irregular-plurals": "^3.2.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "node_modules/postcss-normalize-timing-functions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.3.tgz", + "integrity": "sha512-zmEzHdvpZBZu0OKlbJSfgASQvaayyAoVuWtvyr34IJ/LyS+DaOKvvR3EvFJ9RWWtNIx+CMvO125OVophaxNYew==", "dev": true, "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=4" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/postcss-normalize-unicode": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.9.tgz", + "integrity": "sha512-DRAdWfeh/TjmhLJsw91vdiWCnUod9iwvM7xyS02/nF/sLsCR3A8l3pztrSUrWG8DSBqfX7yEk9FM0USaVJ2mSg==", + "dev": true, "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "browserslist": "^4.28.2", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/postcss-calc": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", - "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", + "node_modules/postcss-normalize-url": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.3.tgz", + "integrity": "sha512-CL93wmloq5qsffmFv+bw24MIRbmhHrp53qoh1LDAb/5TtjWEXI/np4xcP/Gw9oWCb2XyWnqHYLDUwiKRoJBA1Q==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^18.12 || ^20.9 || >=22.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.38" + "postcss": "^8.5.13" } }, - "node_modules/postcss-calc/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/postcss-normalize-whitespace": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.3.tgz", + "integrity": "sha512-FdHjjn+Ht5Z2ZRjNOmeCbNq6lq09sUYKpmlF/Aq0XjVNSLTL6fmHlA/3swN2wP2caY9GV/tjSDcIIyS7aN7W0A==", "dev": true, "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=4" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/postcss-colormin": { + "node_modules/postcss-ordered-values": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.4.tgz", - "integrity": "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw==", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.4.tgz", + "integrity": "sha512-nubSi49hDHQk4E8KIj+IbLY8Bg+8OcSUEhgyolgM+atnOvXjV7EjaR6bac4YGZoFyPa9mWoAF3EaYbWdFkKqVg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", - "caniuse-api": "^3.0.0", - "colord": "^2.9.3", + "cssnano-utils": "^5.0.3", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, - "node_modules/postcss-convert-values": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.7.tgz", - "integrity": "sha512-HR9DZLN04Xbe6xugRH6lS4ZQH2zm/bFh/ZyRkpedZozhvh+awAfbA0P36InO4fZfDhvYfNJeNvlTf1sjwGbw/A==", + "node_modules/postcss-reduce-initial": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.9.tgz", + "integrity": "sha512-ztTNPdIxXTxtBcG03E9u8v44M4ElXbMIRT7pf2onlquGula0Y83nKKxqM22FA/hMgkfCjN7ohevkVlaNwI8iOQ==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", - "postcss-value-parser": "^4.2.0" + "browserslist": "^4.28.2", + "caniuse-api": "^3.0.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, - "node_modules/postcss-discard-comments": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz", - "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==", + "node_modules/postcss-reduce-transforms": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.3.tgz", + "integrity": "sha512-FXsnN9ZwcZTT8Yf8cAHA8qIGUXcX6WfLd9JoYhrdDfmvsVhhfqkkv7m4AC3rwFOfz+GzkUa87OCKF9dUcicd+g==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.1.0" + "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, - "node_modules/postcss-discard-comments/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -16624,757 +17840,946 @@ "node": ">=4" } }, - "node_modules/postcss-discard-duplicates": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", - "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", + "node_modules/postcss-svgo": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.3.tgz", + "integrity": "sha512-2QfoFOYMcj8lwcVEf9WeTlkVIAm7u2QvOEhMzkQU3KUhhGX/l8hVV9EtjMv4iq3E9iI3OeeMN0YoMLbGusuigw==", "dev": true, "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^4.0.1" + }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": "^18.12.0 || ^20.9.0 || >= 18" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, - "node_modules/postcss-discard-empty": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", - "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", + "node_modules/postcss-unique-selectors": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.7.tgz", + "integrity": "sha512-d+sCkaRnSefghOUdH8CMJZV9yUQhj2ojpe8Nw/lA+LV1UOfeleGkLTl6XdCFFSai9UJ+DJPb69FFuqthXYsY8w==", "dev": true, "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.1.1" + }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.5.13" } }, - "node_modules/postcss-discard-overridden": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", - "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/postcss-values-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", + "integrity": "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==", + "license": "MPL-2.0", + "dependencies": { + "color-name": "^1.1.4", + "is-url-superb": "^4.0.0", + "quote-unquote": "^1.0.0" + }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">=10" }, "peerDependencies": { - "postcss": "^8.4.32" + "postcss": "^8.2.9" } }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/postcss-merge-longhand": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", - "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", "dev": true, "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^7.0.5" - }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">=20" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-merge-rules": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.6.tgz", - "integrity": "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ==", - "dev": true, + "node_modules/precinct": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/precinct/-/precinct-12.3.2.tgz", + "integrity": "sha512-JbJevI1K80z8e/WIyDt/4vUN/4qcfBSKKqOjJA4mosPPPb7zODKRJQV7YN7apVWN3k58nZYm/vEsLgEGYmnxwg==", "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^5.0.1", - "postcss-selector-parser": "^7.1.0" + "@dependents/detective-less": "^5.0.3", + "commander": "^12.1.0", + "detective-amd": "^6.1.0", + "detective-cjs": "^6.1.1", + "detective-es6": "^5.0.2", + "detective-postcss": "^8.0.3", + "detective-sass": "^6.0.2", + "detective-scss": "^5.0.2", + "detective-stylus": "^5.0.1", + "detective-typescript": "^14.1.2", + "detective-vue2": "^2.3.0", + "module-definition": "^6.0.2", + "node-source-walk": "^7.0.2", + "postcss": "^8.5.14", + "typescript": "^5.9.3" }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "bin": { + "precinct": "bin/cli.js" }, - "peerDependencies": { - "postcss": "^8.4.32" + "engines": { + "node": ">=18" } }, - "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/precinct/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, - "node_modules/postcss-minify-font-values": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", - "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">=14" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/postcss-minify-gradients": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", - "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", + "node_modules/pretty-bytes": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.0.tgz", + "integrity": "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==", "dev": true, "license": "MIT", - "dependencies": { - "colord": "^2.9.3", - "cssnano-utils": "^5.0.1", - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">=20" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-minify-params": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.4.tgz", - "integrity": "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw==", + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", - "cssnano-utils": "^5.0.1", - "postcss-value-parser": "^4.2.0" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">= 6" } }, - "node_modules/postcss-minify-selectors": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", - "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", "dev": true, "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "postcss-selector-parser": "^7.1.0" - }, + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">= 4" + } + }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/postcss-nested": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-7.0.2.tgz", - "integrity": "sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==", + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", "dev": true, "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "type": "individual", + "url": "https://github.com/sponsors/antfu" }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ { "type": "github", - "url": "https://github.com/sponsors/ai" + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } ], + "license": "MIT" + }, + "node_modules/quote-unquote": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz", + "integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==", + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" + "node": ">= 0.6" } }, - "node_modules/postcss-nested/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "dev": true, + "node_modules/rc9": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz", + "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==", "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "defu": "^6.1.6", + "destr": "^2.0.5" } }, - "node_modules/postcss-normalize-charset": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", - "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", - "dev": true, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-normalize-display-values": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", - "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", - "dev": true, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-normalize-positions": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", - "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", - "dev": true, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/postcss-normalize-repeat-style": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", - "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", - "dev": true, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">=10" } }, - "node_modules/postcss-normalize-string": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", - "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", - "dev": true, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">= 14.18.0" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/postcss-normalize-timing-functions": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", - "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", - "dev": true, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "devOptional": true, "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">=4" } }, - "node_modules/postcss-normalize-unicode": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.4.tgz", - "integrity": "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g==", - "dev": true, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "devOptional": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", - "postcss-value-parser": "^4.2.0" + "redis-errors": "^1.0.0" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">=4" } }, - "node_modules/postcss-normalize-url": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", - "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", + "node_modules/refa": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", + "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", "dev": true, "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "@eslint-community/regexpp": "^4.8.0" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/postcss-normalize-whitespace": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", - "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", - "dev": true, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">= 0.4" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss-ordered-values": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", - "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", + "node_modules/regexp-ast-analysis": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", + "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-utils": "^5.0.1", - "postcss-value-parser": "^4.2.0" + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.1" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" } }, - "node_modules/postcss-reduce-initial": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.4.tgz", - "integrity": "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q==", - "dev": true, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "license": "MIT", "dependencies": { - "browserslist": "^4.25.1", - "caniuse-api": "^3.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "node": ">= 0.4" }, - "peerDependencies": { - "postcss": "^8.4.32" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss-reduce-transforms": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", - "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" + "jsesc": "~3.1.0" }, - "peerDependencies": { - "postcss": "^8.4.32" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "license": "ISC" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/postcss-svgo": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.0.tgz", - "integrity": "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==", - "dev": true, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^4.0.0" - }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >= 18" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">=0.10.0" } }, - "node_modules/postcss-unique-selectors": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz", - "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==", - "dev": true, + "node_modules/require-in-the-middle": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", + "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.1.0" + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3" }, "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">=9.3.0 || >=8.10.0 <9.0.0" } }, - "node_modules/postcss-unique-selectors/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/require-package-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", + "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==", + "license": "MIT" + }, + "node_modules/reserved-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz", + "integrity": "sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==", "dev": true, "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-values-parser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", - "integrity": "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==", - "license": "MPL-2.0", + "node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "license": "MIT", "dependencies": { - "color-name": "^1.1.4", - "is-url-superb": "^4.0.0", - "quote-unquote": "^1.0.0" + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, - "peerDependencies": { - "postcss": "^8.2.9" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, "engines": { + "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/precinct": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/precinct/-/precinct-12.2.0.tgz", - "integrity": "sha512-NFBMuwIfaJ4SocE9YXPU/n4AcNSoFMVFjP72nvl3cx69j/ke61/hPOWFREVxLkFhhEGnA8ZuVfTqJBa+PK3b5w==", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, "license": "MIT", "dependencies": { - "@dependents/detective-less": "^5.0.1", - "commander": "^12.1.0", - "detective-amd": "^6.0.1", - "detective-cjs": "^6.0.1", - "detective-es6": "^5.0.1", - "detective-postcss": "^7.0.1", - "detective-sass": "^6.0.1", - "detective-scss": "^5.0.1", - "detective-stylus": "^5.0.1", - "detective-typescript": "^14.0.0", - "detective-vue2": "^2.2.0", - "module-definition": "^6.0.1", - "node-source-walk": "^7.0.1", - "postcss": "^8.5.1", - "typescript": "^5.7.3" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "precinct": "bin/cli.js" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18" - } - }, - "node_modules/precinct/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "license": "MIT", - "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "node_modules/rollup": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", + "devOptional": true, "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", + "fsevents": "~2.3.2" } }, - "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "node_modules/rollup-plugin-dts": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.4.1.tgz", + "integrity": "sha512-l//F3Zf7ID5GoOfLfD8kroBjQKEKpy1qfhtAdnpibFZMffPaylrg1CoDC2vGkPeTeyxUe4bVFCln2EFuL7IGGg==", "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" + "license": "LGPL-3.0-only", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "convert-source-map": "^2.0.0", + "magic-string": "^0.30.21" }, "engines": { - "node": ">=14" + "node": ">=20" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://github.com/sponsors/Swatinem" + }, + "optionalDependencies": { + "@babel/code-frame": "^7.29.0" + }, + "peerDependencies": { + "rollup": "^3.29.4 || ^4", + "typescript": "^4.5 || ^5.0 || ^6.0" } }, - "node_modules/pretty-bytes": { + "node_modules/rollup-plugin-visualizer": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.0.1.tgz", - "integrity": "sha512-285/jRCYIbMGDciDdrw0KPNC4LKEEwz/bwErcYNxSJOi4CpGUuLpb9gQpg3XJP0XYj9ldSRluXxih4lX2YN8Xw==", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-7.0.1.tgz", + "integrity": "sha512-UJUT4+1Ho4OcWmPYU3sYXgUqI8B8Ayfe06MX7y0qCJ1K8aGoKtR/NDd/2nZqM7ADkrzny+I99Ul7GgyoiVNAgg==", "dev": true, "license": "MIT", + "dependencies": { + "open": "^11.0.0", + "picomatch": "^4.0.2", + "source-map": "^0.7.4", + "yargs": "^18.0.0" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, "engines": { - "node": ">=20" + "node": ">=22" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "rolldown": "1.x || ^1.0.0-beta || ^1.0.0-rc", + "rollup": "2.x || 3.x || 4.x" + }, + "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + } } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/rollup-plugin-visualizer/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=20" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/rollup-plugin-visualizer/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup-plugin-visualizer/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "node_modules/rollup-plugin-visualizer/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">= 0.6.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/rollup-plugin-visualizer/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, "license": "MIT", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">= 6" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/protocols": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", - "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "node_modules/rollup-plugin-visualizer/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, - "license": "MIT" - }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/rou3": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz", + "integrity": "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/quansync": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", - "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { - "type": "individual", - "url": "https://github.com/sponsors/antfu" + "type": "github", + "url": "https://github.com/sponsors/feross" }, { - "type": "individual", - "url": "https://github.com/sponsors/sxzz" + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -17391,284 +18796,362 @@ ], "license": "MIT" }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/quote-unquote": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz", - "integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==", - "license": "MIT" - }, - "node_modules/radix3": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", - "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/rc9": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", - "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scslre": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", + "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "dev": true, "license": "MIT", "dependencies": { - "defu": "^6.1.4", - "destr": "^2.0.3" + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.0", + "regexp-ast-analysis": "^0.7.0" + }, + "engines": { + "node": "^14.0.0 || >=16.0.0" } }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", "license": "MIT" }, - "node_modules/read-package-json-fast": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", - "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", - "dev": true, + "node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=10" } }, - "node_modules/read-package-up": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", - "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, "license": "MIT", "dependencies": { - "find-up-simple": "^1.0.0", - "read-pkg": "^9.0.0", - "type-fest": "^4.6.0" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">=18" + "node": ">= 18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/read-pkg": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", - "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "node_modules/serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/seroval": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", + "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/serve-placeholder": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/serve-placeholder/-/serve-placeholder-2.0.2.tgz", + "integrity": "sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.3", - "normalize-package-data": "^6.0.0", - "parse-json": "^8.0.0", - "type-fest": "^4.6.0", - "unicorn-magic": "^0.1.0" + "defu": "^6.1.4" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">=18" + "node": ">= 18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "license": "MIT", "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/read-pkg-up/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, "license": "ISC" }, - "node_modules/read-pkg-up/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/read-pkg-up/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/shell-quote": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "dev": true, "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg-up/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg-up/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg-up/node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -17677,484 +19160,437 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg-up/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } + "license": "ISC" }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/readable-stream": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "node_modules/simple-git": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.36.0.tgz", + "integrity": "sha512-cGQjLjK8bxJw4QuYT7gxHw3/IouVESbhahSsHrX97MzCL1gu2u7oy38W6L2ZIGECEfIBG4BabsWDPjBxJENv9Q==", + "dev": true, "license": "MIT", "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "@simple-git/args-pathspec": "^1.0.3", + "@simple-git/argv-parser": "^1.1.0", + "debug": "^4.4.0" }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.1.0" + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" } }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">=14.16" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "license": "ISC" + }, + "node_modules/smob": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.2.tgz", + "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", "dev": true, "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, "engines": { - "node": ">=8" + "node": ">=20.0.0" } }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "devOptional": true, - "license": "MIT", + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">= 12" } }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "devOptional": true, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", "dependencies": { - "redis-errors": "^1.0.0" - }, + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/refa": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", - "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", - "dev": true, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.8.0" - }, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/regexp-ast-analysis": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", - "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.8.0", - "refa": "^0.12.1" - }, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/regexp-tree": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", - "dev": true, - "license": "MIT", - "bin": { - "regexp-tree": "bin/regexp-tree" - } + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "license": "CC0-1.0" }, - "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.0.2" - }, - "bin": { - "regjsparser": "bin/parser" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, + "node_modules/srvx": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.16.tgz", + "integrity": "sha512-bp07zRuycfTY43IjAvvTFnmnJi8ikW0VFiHwOhhYcVW/L4xQ1XY4PAd4Nuum1rsA17C39zL7x+CDhrn5AL32Rw==", + "devOptional": true, "license": "MIT", "bin": { - "jsesc": "bin/jsesc" + "srvx": "bin/srvx.mjs" }, "engines": { - "node": ">=6" + "node": ">=20.16.0" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "license": "ISC" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.0.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/require-in-the-middle": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", - "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3" - }, "engines": { - "node": ">=9.3.0 || >=8.10.0 <9.0.0" + "node": ">= 0.8" } }, - "node_modules/require-package-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", - "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==", + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "license": "MIT" }, - "node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, + "node_modules/streamx": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.26.0.tgz", + "integrity": "sha512-VvNG1K72Po/xwJzxZFnZ++Tbrv4lwSptsbkFuzXCJAYZvCK5nnxsvXU6ajqkv7chyiI1Y0YXq2Jh8Iy8Y7NF/A==", "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" } }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", - "engines": { - "node": ">= 4" + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "node_modules/rettime": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", - "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rolldown": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", - "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", - "dev": true, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.115.0", - "@rolldown/pluginutils": "1.0.0-rc.9" - }, - "bin": { - "rolldown": "bin/cli.mjs" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-x64": "1.0.0-rc.9", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" - } - }, - "node_modules/rolldown/node_modules/@oxc-project/types": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", - "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", - "dev": true, + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" + "engines": { + "node": ">=8" } }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", - "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", - "dev": true, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "node_modules/rollup": { - "version": "4.50.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", - "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", - "devOptional": true, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.1", - "@rollup/rollup-android-arm64": "4.50.1", - "@rollup/rollup-darwin-arm64": "4.50.1", - "@rollup/rollup-darwin-x64": "4.50.1", - "@rollup/rollup-freebsd-arm64": "4.50.1", - "@rollup/rollup-freebsd-x64": "4.50.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", - "@rollup/rollup-linux-arm-musleabihf": "4.50.1", - "@rollup/rollup-linux-arm64-gnu": "4.50.1", - "@rollup/rollup-linux-arm64-musl": "4.50.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", - "@rollup/rollup-linux-ppc64-gnu": "4.50.1", - "@rollup/rollup-linux-riscv64-gnu": "4.50.1", - "@rollup/rollup-linux-riscv64-musl": "4.50.1", - "@rollup/rollup-linux-s390x-gnu": "4.50.1", - "@rollup/rollup-linux-x64-gnu": "4.50.1", - "@rollup/rollup-linux-x64-musl": "4.50.1", - "@rollup/rollup-openharmony-arm64": "4.50.1", - "@rollup/rollup-win32-arm64-msvc": "4.50.1", - "@rollup/rollup-win32-ia32-msvc": "4.50.1", - "@rollup/rollup-win32-x64-msvc": "4.50.1", - "fsevents": "~2.3.2" + "node": ">=8" } }, - "node_modules/rollup-plugin-dts": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.2.3.tgz", - "integrity": "sha512-UgnEsfciXSPpASuOelix7m4DrmyQgiaWBnvI0TM4GxuDh5FkqW8E5hu57bCxXB90VvR1WNfLV80yEDN18UogSA==", - "dev": true, - "license": "LGPL-3.0-only", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", "dependencies": { - "magic-string": "^0.30.17" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/Swatinem" - }, - "optionalDependencies": { - "@babel/code-frame": "^7.27.1" - }, - "peerDependencies": { - "rollup": "^3.29.4 || ^4", - "typescript": "^4.5 || ^5.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup-plugin-visualizer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.3.tgz", - "integrity": "sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw==", - "dev": true, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "license": "MIT", "dependencies": { - "open": "^8.0.0", - "picomatch": "^4.0.2", - "source-map": "^0.7.4", - "yargs": "^17.5.1" - }, - "bin": { - "rollup-plugin-visualizer": "dist/bin/cli.js" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "rolldown": "1.x || ^1.0.0-beta", - "rollup": "2.x || 3.x || 4.x" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "rolldown": { - "optional": true - }, - "rollup": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup-plugin-visualizer/node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup-plugin-visualizer/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/rollup-plugin-visualizer/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/rollup-plugin-visualizer/node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, "engines": { "node": ">=12" }, @@ -18162,1354 +19598,1360 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rollup-plugin-visualizer/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, "license": "MIT", "dependencies": { - "queue-microtask": "^1.2.2" + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, "license": "MIT" }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/structured-clone-es": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-1.0.0.tgz", + "integrity": "sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "license": "ISC" }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", + "node_modules/stubborn-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-2.0.0.tgz", + "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", + "license": "MIT", "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" + "stubborn-utils": "^1.0.1" } }, - "node_modules/scslre": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", - "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "node_modules/stubborn-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stubborn-utils/-/stubborn-utils-1.0.2.tgz", + "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==", + "license": "MIT" + }, + "node_modules/stylehacks": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.11.tgz", + "integrity": "sha512-iODNfhXVLqc5LADs+Y6Oh5wJuK5ZcHbVng8aiK3y9pjMQdc5hLrBW0eFU6FtnpNrE6PoEg/MmFTU4waotj5WNg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.8.0", - "refa": "^0.12.0", - "regexp-ast-analysis": "^0.7.0" + "browserslist": "^4.28.2", + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": "^14.0.0 || >=16.0.0" - } - }, - "node_modules/scule": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", - "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "postcss": "^8.5.13" } }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">= 18" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/serve-placeholder": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/serve-placeholder/-/serve-placeholder-2.0.2.tgz", - "integrity": "sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==", + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, "license": "MIT", - "dependencies": { - "defu": "^6.1.4" + "engines": { + "node": ">= 6" } }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "copy-anything": "^4" }, "engines": { - "node": ">= 18" + "node": ">=16" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", "dev": true, - "license": "ISC" - }, - "node_modules/sharp": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", - "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.4", - "semver": "^7.7.2" - }, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=18" }, "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.3", - "@img/sharp-darwin-x64": "0.34.3", - "@img/sharp-libvips-darwin-arm64": "1.2.0", - "@img/sharp-libvips-darwin-x64": "1.2.0", - "@img/sharp-libvips-linux-arm": "1.2.0", - "@img/sharp-libvips-linux-arm64": "1.2.0", - "@img/sharp-libvips-linux-ppc64": "1.2.0", - "@img/sharp-libvips-linux-s390x": "1.2.0", - "@img/sharp-libvips-linux-x64": "1.2.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0", - "@img/sharp-linux-arm": "0.34.3", - "@img/sharp-linux-arm64": "0.34.3", - "@img/sharp-linux-ppc64": "0.34.3", - "@img/sharp-linux-s390x": "0.34.3", - "@img/sharp-linux-x64": "0.34.3", - "@img/sharp-linuxmusl-arm64": "0.34.3", - "@img/sharp-linuxmusl-x64": "0.34.3", - "@img/sharp-wasm32": "0.34.3", - "@img/sharp-win32-arm64": "0.34.3", - "@img/sharp-win32-ia32": "0.34.3", - "@img/sharp-win32-x64": "0.34.3" - } - }, - "node_modules/sharp/node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, "engines": { - "node": ">=12.5.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/svgo": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo.js" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/svgo/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=16" } }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=20" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=14" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/simple-git": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.28.0.tgz", - "integrity": "sha512-Rs/vQRwsn1ILH1oBUy8NucJlXmnnLeLCfcvbSehkPzbv3wwoFWIdtfd6Ndo6ZPhlPsCZ60CPI4rxurnwAa+a2w==", - "dev": true, - "license": "MIT", + "node_modules/tar": { + "version": "7.5.16", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", + "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", + "license": "BlueOak-1.0.0", "dependencies": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.4.0" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/steveukx/git-js?sponsor=1" + "engines": { + "node": ">=18" } }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", "license": "MIT", "dependencies": { - "is-arrayish": "^0.3.1" + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, - "node_modules/sirv": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", - "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=18" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/terser": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/slashes": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", - "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", - "license": "ISC" - }, - "node_modules/smob": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", - "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "license": "MIT" }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "any-promise": "^1.0.0" } }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, "license": "MIT", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "license": "CC0-1.0" + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" }, - "node_modules/speakingurl": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT" + }, + "node_modules/tinyclip": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.14.tgz", + "integrity": "sha512-F1oWdz8tjT17qe1d5JgDK6z03WGOhYYAN0lK3/D/fzNiy93xswLLEw7pk+3g05onhAy6Bsc6PLNUGhdgVjemMQ==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >= 17.3.0" } }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.x" + "node": ">=18" } }, - "node_modules/stable-hash-x": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", - "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", - "dev": true, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, "engines": { "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": "^18.0.0 || >=20.0.0" } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, - "license": "MIT" - }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=14.0.0" } }, - "node_modules/std-env": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", - "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", - "license": "MIT" + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } }, - "node_modules/streamx": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", - "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", "license": "MIT", "dependencies": { - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" + "tmp": "^0.2.0" } }, - "node_modules/strict-event-emitter": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", - "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/to-valid-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-valid-identifier/-/to-valid-identifier-1.0.0.tgz", + "integrity": "sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==", + "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "@sindresorhus/base62": "^1.0.0", + "reserved-identifiers": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { - "node": ">=8" + "node": ">=0.6" } }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tomlify-j0.4": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz", + "integrity": "sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ==", + "license": "MIT" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">= 14.0.0" } }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, "engines": { - "node": ">=12" + "node": ">=18.12" }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", + "node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" + } + ], + "license": "BSD-3-Clause", "dependencies": { - "ansi-regex": "^5.0.1" + "picomatch": "^4.0.2" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "typescript": ">=4.0.0" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, "engines": { - "node": ">=8" + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsup": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", + "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "dev": true, "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.27.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "^0.7.6", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, "engines": { - "node": ">=12" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "node_modules/tsup/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/tsup/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/strip-literal": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", - "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", + "node_modules/tsup/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "license": "MIT" - }, - "node_modules/structured-clone-es": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-1.0.0.tgz", - "integrity": "sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==", + "node_modules/tsup/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC" - }, - "node_modules/stubborn-fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-2.0.0.tgz", - "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", "license": "MIT", - "dependencies": { - "stubborn-utils": "^1.0.1" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/stubborn-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stubborn-utils/-/stubborn-utils-1.0.2.tgz", - "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==", - "license": "MIT" - }, - "node_modules/stylehacks": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.6.tgz", - "integrity": "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg==", + "node_modules/tsup/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "browserslist": "^4.25.1", - "postcss-selector-parser": "^7.1.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" + "node": ">=18" } }, - "node_modules/stylehacks/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/tsup/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "node_modules/tsup/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" } }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/tsup/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 6" + "node": ">=18" } }, - "node_modules/superjson": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", - "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "node_modules/tsup/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "copy-anything": "^3.0.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">=18" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/tsup/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "node_modules/tsup/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/tsup/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/svgo": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", - "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "node_modules/tsup/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, "license": "MIT", - "dependencies": { - "commander": "^11.1.0", - "css-select": "^5.1.0", - "css-tree": "^3.0.1", - "css-what": "^6.1.0", - "csso": "^5.0.5", - "picocolors": "^1.1.1", - "sax": "^1.4.1" - }, - "bin": { - "svgo": "bin/svgo.js" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" + "node": ">=18" } }, - "node_modules/svgo/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "node_modules/tsup/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">=18" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "node_modules/tsup/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/system-architecture": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", - "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tapable": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", - "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "node_modules/tsup/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=18" } }, - "node_modules/tar": { - "version": "7.5.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", - "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, + "node_modules/tsup/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" } }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "node_modules/tsup/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/terser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", - "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "node_modules/tsup/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "node_modules/tsup/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "node_modules/tsup/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "node_modules/tsup/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=0.8" + "node": ">=18" } }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "node_modules/tsup/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "node": ">=18" } }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "node_modules/tsup/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": ">=18" } }, - "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "node_modules/tsup/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/tinyspy": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", - "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", + "node_modules/tsup/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/tldts": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.13.tgz", - "integrity": "sha512-z/SgnxiICGb7Gli0z7ci9BZdjy1tQORUbdmzEUA7NbIJKWhdONn78Ji8gV0PAGfHPyEd+I+W2rMzhLjWkv2Olg==", + "node_modules/tsup/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "tldts-core": "^7.0.13" - }, "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.13.tgz", - "integrity": "sha512-Td0LeWLgXJGsikI4mO82fRexgPCEyTcwWiXJERF/GBHX3Dm+HQq/wx4HnYowCbiwQ8d+ENLZc+ktbZw8H+0oEA==", + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/tsup/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true, "license": "MIT" }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "license": "MIT", - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "prelude-ls": "^1.2.1" }, "engines": { - "node": ">=8.0" + "node": ">= 0.8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=0.6" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/toml": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", - "license": "MIT" - }, - "node_modules/tomlify-j0.4": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz", - "integrity": "sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ==", + "node_modules/type-level-regexp": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/type-level-regexp/-/type-level-regexp-0.1.17.tgz", + "integrity": "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==", + "dev": true, "license": "MIT" }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "tldts": "^7.0.5" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" }, "engines": { - "node": ">=16" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" + "node": ">= 0.4" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, "engines": { - "node": ">= 14.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, "engines": { - "node": ">=18.12" + "node": ">= 0.4" }, - "peerDependencies": { - "typescript": ">=4.8.4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ts-declaration-location": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", - "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", - "dev": true, - "funding": [ - { - "type": "ko-fi", - "url": "https://ko-fi.com/rebeccastevens" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" - } - ], - "license": "BSD-3-Clause", - "dependencies": { - "picomatch": "^4.0.2" + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "peerDependencies": { - "typescript": ">=4.0.0" + "engines": { + "node": ">=14.17" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/tsconfck": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", - "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "node_modules/typescript-eslint": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", + "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", "dev": true, "license": "MIT", - "bin": { - "tsconfck": "bin/tsconfck.js" + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.60.1", + "@typescript-eslint/parser": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1" }, "engines": { - "node": "^18 || >=20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "typescript": "^5.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/tsd": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.32.0.tgz", - "integrity": "sha512-R5lBZCbxGBowOcW0gpQaiIjGYrG5NmU+PfFDKcc3zbtzWjML1o/zAwzdDnS2ZheSlPu9GW51azpFqEPUBq9DoQ==", - "dev": true, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, + "node_modules/ulid": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/ulid/-/ulid-3.0.2.tgz", + "integrity": "sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w==", "license": "MIT", - "dependencies": { - "@tsd/typescript": "~5.8.3", - "eslint-formatter-pretty": "^4.1.0", - "globby": "^11.0.1", - "jest-diff": "^29.0.3", - "meow": "^9.0.0", - "path-exists": "^4.0.0", - "read-pkg-up": "^7.0.0" - }, "bin": { - "tsd": "dist/cli.js" - }, - "engines": { - "node": ">=14.16" + "ulid": "dist/cli.js" } }, - "node_modules/tsd/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/ultrahtml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", + "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", "dev": true, + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tsup": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", - "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "node_modules/unbuild": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/unbuild/-/unbuild-3.6.1.tgz", + "integrity": "sha512-+U5CdtrdjfWkZhuO4N9l5UhyiccoeMEXIc2Lbs30Haxb+tRwB3VwB8AoZRxlAzORXunenSo+j6lh45jx+xkKgg==", "dev": true, "license": "MIT", "dependencies": { - "bundle-require": "^5.1.0", - "cac": "^6.7.14", - "chokidar": "^4.0.3", - "consola": "^3.4.0", - "debug": "^4.4.0", - "esbuild": "^0.27.0", - "fix-dts-default-cjs-exports": "^1.0.0", - "joycon": "^3.1.1", - "picocolors": "^1.1.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.34.8", - "source-map": "^0.7.6", - "sucrase": "^3.35.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.11", - "tree-kill": "^1.2.2" + "@rollup/plugin-alias": "^5.1.1", + "@rollup/plugin-commonjs": "^28.0.6", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.1", + "@rollup/plugin-replace": "^6.0.2", + "@rollup/pluginutils": "^5.2.0", + "citty": "^0.1.6", + "consola": "^3.4.2", + "defu": "^6.1.4", + "esbuild": "^0.25.9", + "fix-dts-default-cjs-exports": "^1.0.1", + "hookable": "^5.5.3", + "jiti": "^2.5.1", + "magic-string": "^0.30.17", + "mkdist": "^2.3.0", + "mlly": "^1.7.4", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "pretty-bytes": "^7.0.1", + "rollup": "^4.46.2", + "rollup-plugin-dts": "^6.2.1", + "scule": "^1.3.0", + "tinyglobby": "^0.2.14", + "untyped": "^2.0.0" }, "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" - }, - "engines": { - "node": ">=18" + "unbuild": "dist/cli.mjs" }, "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" + "typescript": "^5.9.2" }, "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "@swc/core": { - "optional": true - }, - "postcss": { - "optional": true - }, "typescript": { "optional": true } } }, - "node_modules/tsup/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.1.tgz", - "integrity": "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==", + "node_modules/unbuild/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -19523,10 +20965,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/android-arm": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.1.tgz", - "integrity": "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==", + "node_modules/unbuild/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -19540,10 +20982,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/android-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.1.tgz", - "integrity": "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==", + "node_modules/unbuild/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -19557,10 +20999,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/android-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.1.tgz", - "integrity": "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==", + "node_modules/unbuild/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -19574,10 +21016,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.1.tgz", - "integrity": "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==", + "node_modules/unbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -19591,10 +21033,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/darwin-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.1.tgz", - "integrity": "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==", + "node_modules/unbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -19608,10 +21050,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.1.tgz", - "integrity": "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==", + "node_modules/unbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -19625,10 +21067,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.1.tgz", - "integrity": "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==", + "node_modules/unbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -19642,10 +21084,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-arm": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.1.tgz", - "integrity": "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==", + "node_modules/unbuild/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -19659,10 +21101,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.1.tgz", - "integrity": "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==", + "node_modules/unbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -19676,10 +21118,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-ia32": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.1.tgz", - "integrity": "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==", + "node_modules/unbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -19693,10 +21135,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-loong64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.1.tgz", - "integrity": "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==", + "node_modules/unbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -19710,10 +21152,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.1.tgz", - "integrity": "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==", + "node_modules/unbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -19727,10 +21169,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.1.tgz", - "integrity": "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==", + "node_modules/unbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -19744,10 +21186,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.1.tgz", - "integrity": "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==", + "node_modules/unbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -19761,10 +21203,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-s390x": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.1.tgz", - "integrity": "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==", + "node_modules/unbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -19778,10 +21220,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/linux-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.1.tgz", - "integrity": "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==", + "node_modules/unbuild/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -19795,10 +21237,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.1.tgz", - "integrity": "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==", + "node_modules/unbuild/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -19812,10 +21254,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.1.tgz", - "integrity": "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==", + "node_modules/unbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -19829,10 +21271,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.1.tgz", - "integrity": "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==", + "node_modules/unbuild/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -19846,10 +21288,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.1.tgz", - "integrity": "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==", + "node_modules/unbuild/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -19863,10 +21305,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.1.tgz", - "integrity": "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==", + "node_modules/unbuild/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "cpu": [ "arm64" ], @@ -19880,10 +21322,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/sunos-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.1.tgz", - "integrity": "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==", + "node_modules/unbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -19897,10 +21339,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/win32-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.1.tgz", - "integrity": "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==", + "node_modules/unbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -19914,10 +21356,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/win32-ia32": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.1.tgz", - "integrity": "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==", + "node_modules/unbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -19931,10 +21373,10 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/@esbuild/win32-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.1.tgz", - "integrity": "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==", + "node_modules/unbuild/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -19948,270 +21390,109 @@ "node": ">=18" } }, - "node_modules/tsup/node_modules/esbuild": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz", - "integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.1", - "@esbuild/android-arm": "0.27.1", - "@esbuild/android-arm64": "0.27.1", - "@esbuild/android-x64": "0.27.1", - "@esbuild/darwin-arm64": "0.27.1", - "@esbuild/darwin-x64": "0.27.1", - "@esbuild/freebsd-arm64": "0.27.1", - "@esbuild/freebsd-x64": "0.27.1", - "@esbuild/linux-arm": "0.27.1", - "@esbuild/linux-arm64": "0.27.1", - "@esbuild/linux-ia32": "0.27.1", - "@esbuild/linux-loong64": "0.27.1", - "@esbuild/linux-mips64el": "0.27.1", - "@esbuild/linux-ppc64": "0.27.1", - "@esbuild/linux-riscv64": "0.27.1", - "@esbuild/linux-s390x": "0.27.1", - "@esbuild/linux-x64": "0.27.1", - "@esbuild/netbsd-arm64": "0.27.1", - "@esbuild/netbsd-x64": "0.27.1", - "@esbuild/openbsd-arm64": "0.27.1", - "@esbuild/openbsd-x64": "0.27.1", - "@esbuild/openharmony-arm64": "0.27.1", - "@esbuild/sunos-x64": "0.27.1", - "@esbuild/win32-arm64": "0.27.1", - "@esbuild/win32-ia32": "0.27.1", - "@esbuild/win32-x64": "0.27.1" - } - }, - "node_modules/tsup/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-level-regexp": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/type-level-regexp/-/type-level-regexp-0.1.17.tgz", - "integrity": "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==", - "dev": true, - "license": "MIT" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.43.0.tgz", - "integrity": "sha512-FyRGJKUGvcFekRRcBKFBlAhnp4Ng8rhe8tuvvkR9OiU0gfd4vyvTRQHEckO6VDlH57jbeUQem2IpqPq9kLJH+w==", + "node_modules/unbuild/node_modules/@rollup/plugin-alias": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", + "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.43.0", - "@typescript-eslint/parser": "8.43.0", - "@typescript-eslint/typescript-estree": "8.43.0", - "@typescript-eslint/utils": "8.43.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", - "license": "MIT" - }, - "node_modules/ulid": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ulid/-/ulid-3.0.1.tgz", - "integrity": "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q==", - "license": "MIT", - "bin": { - "ulid": "dist/cli.js" - } - }, - "node_modules/ultrahtml": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", - "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unbuild": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/unbuild/-/unbuild-3.6.1.tgz", - "integrity": "sha512-+U5CdtrdjfWkZhuO4N9l5UhyiccoeMEXIc2Lbs30Haxb+tRwB3VwB8AoZRxlAzORXunenSo+j6lh45jx+xkKgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/plugin-alias": "^5.1.1", - "@rollup/plugin-commonjs": "^28.0.6", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.1", - "@rollup/plugin-replace": "^6.0.2", - "@rollup/pluginutils": "^5.2.0", - "citty": "^0.1.6", - "consola": "^3.4.2", - "defu": "^6.1.4", - "esbuild": "^0.25.9", - "fix-dts-default-cjs-exports": "^1.0.1", - "hookable": "^5.5.3", - "jiti": "^2.5.1", - "magic-string": "^0.30.17", - "mkdist": "^2.3.0", - "mlly": "^1.7.4", - "pathe": "^2.0.3", - "pkg-types": "^2.2.0", - "pretty-bytes": "^7.0.1", - "rollup": "^4.46.2", - "rollup-plugin-dts": "^6.2.1", - "scule": "^1.3.0", - "tinyglobby": "^0.2.14", - "untyped": "^2.0.0" - }, - "bin": { - "unbuild": "dist/cli.mjs" + "node": ">=14.0.0" }, "peerDependencies": { - "typescript": "^5.9.2" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { - "typescript": { + "rollup": { "optional": true } - } - }, - "node_modules/unbuild/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unbuild/node_modules/mkdist": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/mkdist/-/mkdist-2.3.0.tgz", - "integrity": "sha512-thkRk+pHdudjdZT3FJpPZ2+pncI6mGlH/B+KBVddlZj4MrFGW41sRIv1wZawZUHU8v7cttGaj+5nx8P+dG664A==", - "dev": true, - "license": "MIT", - "dependencies": { - "autoprefixer": "^10.4.21", - "citty": "^0.1.6", - "cssnano": "^7.0.6", - "defu": "^6.1.4", - "esbuild": "^0.25.2", - "jiti": "^1.21.7", - "mlly": "^1.7.4", - "pathe": "^2.0.3", - "pkg-types": "^2.1.0", - "postcss": "^8.5.3", - "postcss-nested": "^7.0.2", - "semver": "^7.7.1", - "tinyglobby": "^0.2.12" + } + }, + "node_modules/unbuild/node_modules/@rollup/plugin-commonjs": { + "version": "28.0.9", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.9.tgz", + "integrity": "sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" }, - "bin": { - "mkdist": "dist/cli.cjs" + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" }, "peerDependencies": { - "sass": "^1.85.0", - "typescript": ">=5.7.3", - "vue": "^3.5.13", - "vue-sfc-transformer": "^0.1.1", - "vue-tsc": "^1.8.27 || ^2.0.21" + "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { - "sass": { - "optional": true - }, - "typescript": { - "optional": true - }, - "vue": { - "optional": true - }, - "vue-sfc-transformer": { - "optional": true - }, - "vue-tsc": { + "rollup": { "optional": true } } }, - "node_modules/unbuild/node_modules/mkdist/node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "node_modules/unbuild/node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "dev": true, "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" + "dependencies": { + "consola": "^3.2.3" } }, - "node_modules/unbuild/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/unbuild/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" - } + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/unbuild/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" }, "node_modules/uncrypto": { "version": "0.1.3", @@ -20220,68 +21501,76 @@ "license": "MIT" }, "node_modules/unctx": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.4.1.tgz", - "integrity": "sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.5.0.tgz", + "integrity": "sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==", "license": "MIT", "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "estree-walker": "^3.0.3", - "magic-string": "^0.30.17", - "unplugin": "^2.1.0" - } - }, - "node_modules/unctx/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/undici": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.7.tgz", - "integrity": "sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" + "magic-string": "^0.30.21", + "unplugin": "^2.3.11" } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, "license": "MIT" }, "node_modules/unenv": { - "version": "2.0.0-rc.21", - "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.21.tgz", - "integrity": "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==", + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", "dev": true, "license": "MIT", "dependencies": { - "defu": "^6.1.4", - "exsolve": "^1.0.7", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "ufo": "^1.6.1" + "pathe": "^2.0.3" } }, "node_modules/unhead": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.0.14.tgz", - "integrity": "sha512-dRP6OCqtShhMVZQe1F4wdt/WsYl2MskxKK+cvfSo0lQnrPJ4oAUQEkxRg7pPP+vJENabhlir31HwAyHUv7wfMg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-3.1.1.tgz", + "integrity": "sha512-tKPzJLM/maN/OQ5xhFJawHEp91U3LgQL5kd8lrZcU1hc/B8U+fM0EJqSe49AjgSUAkbLPXoL4YVPrMx2894WUA==", "dev": true, "license": "MIT", "dependencies": { - "hookable": "^5.5.3" + "hookable": "^6.1.1", + "unplugin": "^3.0.0" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" + }, + "peerDependencies": { + "vite": ">=6.4.2" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/unhead/node_modules/hookable": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.1.1.tgz", + "integrity": "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unhead/node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/unicorn-magic": { @@ -20297,82 +21586,56 @@ } }, "node_modules/unimport": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.2.0.tgz", - "integrity": "sha512-bTuAMMOOqIAyjV4i4UH7P07pO+EsVxmhOzQ2YJ290J6mkLUdozNhb5I/YoOEheeNADC03ent3Qj07X0fWfUpmw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-6.3.0.tgz", + "integrity": "sha512-M+Dxk5W9WRd+8j56W9tp8lGW/dmMc7g5zj7BWQnEjKQhryBstqsi1V0izb0zHwSkEN8cSYV7K75/bykairV2tA==", + "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", - "local-pkg": "^1.1.1", - "magic-string": "^0.30.17", - "mlly": "^1.7.4", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.2", "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "pkg-types": "^2.2.0", + "picomatch": "^4.0.4", + "pkg-types": "^2.3.1", "scule": "^1.3.0", - "strip-literal": "^3.0.0", - "tinyglobby": "^0.2.14", - "unplugin": "^2.3.5", - "unplugin-utils": "^0.2.4" + "strip-literal": "^3.1.0", + "tinyglobby": "^0.2.16", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1" }, "engines": { "node": ">=18.12.0" - } - }, - "node_modules/unimport/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "license": "MIT" - }, - "node_modules/unimport/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unimport/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/unimport/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", - "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "peerDependencies": { + "oxc-parser": "*", + "rolldown": "^1.0.0" + }, + "peerDependenciesMeta": { + "oxc-parser": { + "optional": true + }, + "rolldown": { + "optional": true + } } }, - "node_modules/unimport/node_modules/unplugin-utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", - "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", + "node_modules/unimport/node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "dev": true, "license": "MIT", "dependencies": { - "pathe": "^2.0.3", - "picomatch": "^4.0.3" + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" }, "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/unixify": { @@ -20400,9 +21663,9 @@ } }, "node_modules/unplugin": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", - "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", @@ -20415,9 +21678,9 @@ } }, "node_modules/unplugin-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz", - "integrity": "sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", "dev": true, "license": "MIT", "dependencies": { @@ -20431,106 +21694,69 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/unplugin-vue-router": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.15.0.tgz", - "integrity": "sha512-PyGehCjd9Ny9h+Uer4McbBjjib3lHihcyUEILa7pHKl6+rh8N7sFyw4ZkV+N30Oq2zmIUG7iKs3qpL0r+gXAaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue-macros/common": "3.0.0-beta.16", - "@vue/language-core": "^3.0.1", - "ast-walker-scope": "^0.8.1", - "chokidar": "^4.0.3", - "json5": "^2.2.3", - "local-pkg": "^1.1.1", - "magic-string": "^0.30.17", - "mlly": "^1.7.4", - "muggle-string": "^0.4.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "scule": "^1.3.0", - "tinyglobby": "^0.2.14", - "unplugin": "^2.3.5", - "unplugin-utils": "^0.2.4", - "yaml": "^2.8.0" - }, - "peerDependencies": { - "@vue/compiler-sfc": "^3.5.17", - "vue-router": "^4.5.1" - }, - "peerDependenciesMeta": { - "vue-router": { - "optional": true - } - } - }, - "node_modules/unplugin-vue-router/node_modules/unplugin-utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", - "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", + "node_modules/unrouting": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/unrouting/-/unrouting-0.1.7.tgz", + "integrity": "sha512-+0hfD+CVWtD636rc5Fn9VEjjTEDhdqgMpbwAuVoUmydSHDaMNiFW93SJG4LV++RoGSEAyvQN5uABAscYpDphpQ==", "dev": true, "license": "MIT", "dependencies": { - "pathe": "^2.0.3", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "escape-string-regexp": "^5.0.0", + "ufo": "^1.6.3" } }, "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "napi-postinstall": "^0.3.0" + "napi-postinstall": "^0.3.4" }, "funding": { "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" } }, "node_modules/unstorage": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.1.tgz", - "integrity": "sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", "license": "MIT", "dependencies": { "anymatch": "^3.1.3", - "chokidar": "^4.0.3", + "chokidar": "^5.0.0", "destr": "^2.0.5", - "h3": "^1.15.4", - "lru-cache": "^10.4.3", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", - "ofetch": "^1.4.1", - "ufo": "^1.6.1" + "ofetch": "^1.5.1", + "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", @@ -20539,14 +21765,14 @@ "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", - "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", - "@vercel/kv": "^1.0.1", + "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", @@ -20613,6 +21839,43 @@ } } }, + "node_modules/unstorage/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/unstorage/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/unstorage/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/untun": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz", @@ -20627,6 +21890,15 @@ "untun": "bin/untun.mjs" } }, + "node_modules/untun/node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/untun/node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -20649,44 +21921,34 @@ "untyped": "dist/cli.mjs" } }, - "node_modules/unwasm": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.3.11.tgz", - "integrity": "sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==", - "dev": true, + "node_modules/untyped/node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "license": "MIT", "dependencies": { - "knitwork": "^1.2.0", - "magic-string": "^0.30.17", - "mlly": "^1.7.4", - "pathe": "^2.0.3", - "pkg-types": "^2.2.0", - "unplugin": "^2.3.6" + "consola": "^3.2.3" } }, - "node_modules/unwasm/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unwasm/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "node_modules/unwasm": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.5.3.tgz", + "integrity": "sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==", "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "exsolve": "^1.0.8", + "knitwork": "^1.3.0", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0" } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -20715,15 +21977,16 @@ } }, "node_modules/uqr": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz", - "integrity": "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.3.tgz", + "integrity": "sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA==", "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -20751,6 +22014,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/validate-npm-package-name": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", @@ -20761,18 +22034,17 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -20788,9 +22060,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -20803,13 +22076,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { "optional": true }, - "lightningcss": { + "jiti": { + "optional": true + }, + "less": { "optional": true }, "sass": { @@ -20831,371 +22107,77 @@ "optional": true }, "yaml": { - "optional": true - } - } - }, - "node_modules/vite-dev-rpc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz", - "integrity": "sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==", - "dev": true, - "license": "MIT", - "dependencies": { - "birpc": "^2.4.0", - "vite-hot-client": "^2.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0" - } - }, - "node_modules/vite-hot-client": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz", - "integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0" - } - }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite-plugin-inspect": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz", - "integrity": "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansis": "^4.1.0", - "debug": "^4.4.1", - "error-stack-parser-es": "^1.0.5", - "ohash": "^2.0.11", - "open": "^10.2.0", - "perfect-debounce": "^2.0.0", - "sirv": "^3.0.1", - "unplugin-utils": "^0.3.0", - "vite-dev-rpc": "^1.1.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "@nuxt/kit": { - "optional": true - } - } - }, - "node_modules/vite-plugin-inspect/node_modules/perfect-debounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", - "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite-plugin-vue-tracer": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/vite-plugin-vue-tracer/-/vite-plugin-vue-tracer-1.1.3.tgz", - "integrity": "sha512-fM7hfHELZvbPnSn8EKZwHfzxm5EfYFQIclz8rwcNXfodNbRkwNvh0AGMtaBfMxQ9HC5KVa3KitwHnmE4ezDemw==", - "dev": true, - "license": "MIT", - "dependencies": { - "estree-walker": "^3.0.3", - "exsolve": "^1.0.7", - "magic-string": "^0.30.21", - "pathe": "^2.0.3", - "source-map-js": "^1.2.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "vite": "^6.0.0 || ^7.0.0", - "vue": "^3.5.0" - } - }, - "node_modules/vite-plugin-vue-tracer/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" + "optional": true + } } }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", - "cpu": [ - "arm64" - ], + "node_modules/vite-dev-rpc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz", + "integrity": "sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" + "dependencies": { + "birpc": "^4.0.0", + "vite-hot-client": "^2.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", - "cpu": [ - "ia32" - ], + "node_modules/vite-dev-rpc/node_modules/birpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz", + "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", - "cpu": [ - "loong64" - ], + "node_modules/vite-hot-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.2.0.tgz", + "integrity": "sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0" } }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", - "cpu": [ - "mips64el" - ], + "node_modules/vite-node": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-5.3.0.tgz", + "integrity": "sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, + "dependencies": { + "cac": "^6.7.14", + "es-module-lexer": "^2.0.0", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "vite": "^7.3.1" + }, + "bin": { + "vite-node": "dist/cli.mjs" + }, "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://opencollective.com/antfu" } }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "node_modules/vite-node/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -21203,107 +22185,33 @@ "license": "MIT", "optional": true, "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" + "aix" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "node_modules/vite-node/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ - "x64" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" + "android" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "node_modules/vite-node/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -21311,17 +22219,16 @@ "license": "MIT", "optional": true, "os": [ - "openbsd" + "android" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "node_modules/vite-node/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -21329,17 +22236,16 @@ "license": "MIT", "optional": true, "os": [ - "openbsd" + "android" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -21347,17 +22253,16 @@ "license": "MIT", "optional": true, "os": [ - "openharmony" + "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "node_modules/vite-node/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -21365,17 +22270,16 @@ "license": "MIT", "optional": true, "os": [ - "sunos" + "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "node_modules/vite-node/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -21383,35 +22287,16 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" + "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "node_modules/vite-node/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -21419,2859 +22304,2889 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.4", - "@esbuild/android-arm": "0.27.4", - "@esbuild/android-arm64": "0.27.4", - "@esbuild/android-x64": "0.27.4", - "@esbuild/darwin-arm64": "0.27.4", - "@esbuild/darwin-x64": "0.27.4", - "@esbuild/freebsd-arm64": "0.27.4", - "@esbuild/freebsd-x64": "0.27.4", - "@esbuild/linux-arm": "0.27.4", - "@esbuild/linux-arm64": "0.27.4", - "@esbuild/linux-ia32": "0.27.4", - "@esbuild/linux-loong64": "0.27.4", - "@esbuild/linux-mips64el": "0.27.4", - "@esbuild/linux-ppc64": "0.27.4", - "@esbuild/linux-riscv64": "0.27.4", - "@esbuild/linux-s390x": "0.27.4", - "@esbuild/linux-x64": "0.27.4", - "@esbuild/netbsd-arm64": "0.27.4", - "@esbuild/netbsd-x64": "0.27.4", - "@esbuild/openbsd-arm64": "0.27.4", - "@esbuild/openbsd-x64": "0.27.4", - "@esbuild/openharmony-arm64": "0.27.4", - "@esbuild/sunos-x64": "0.27.4", - "@esbuild/win32-arm64": "0.27.4", - "@esbuild/win32-ia32": "0.27.4", - "@esbuild/win32-x64": "0.27.4" - } - }, - "node_modules/vitest": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", - "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest-environment-nuxt": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vitest-environment-nuxt/-/vitest-environment-nuxt-1.0.1.tgz", - "integrity": "sha512-eBCwtIQriXW5/M49FjqNKfnlJYlG2LWMSNFsRVKomc8CaMqmhQPBS5LZ9DlgYL9T8xIVsiA6RZn2lk7vxov3Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nuxt/test-utils": ">=3.13.1" - } - }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vue": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", - "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.21", - "@vue/compiler-sfc": "3.5.21", - "@vue/runtime-dom": "3.5.21", - "@vue/server-renderer": "3.5.21", - "@vue/shared": "3.5.21" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/vue-bundle-renderer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.1.2.tgz", - "integrity": "sha512-M4WRBO/O/7G9phGaGH9AOwOnYtY9ZpPoDVpBpRzR2jO5rFL9mgIlQIgums2ljCTC2HL1jDXFQc//CzWcAQHgAw==", + "node_modules/vite-node/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "ufo": "^1.6.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/vue-devtools-stub": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz", - "integrity": "sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vue-eslint-parser": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz", - "integrity": "sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==", + "node_modules/vite-node/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.6.0", - "semver": "^7.6.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "node": ">=18" } }, - "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/vite-node/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/vue-router": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", - "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", + "node_modules/vite-node/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.6.4" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.2.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/vue-sfc-transformer": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/vue-sfc-transformer/-/vue-sfc-transformer-0.1.16.tgz", - "integrity": "sha512-pXx4pkHigOJCzGPXhGA9Rdou1oIuNiF9n4n5GQ7C4QehTXFEpKUjcpvc3PZ6LvC6ccUL021qor8j1153Y7/6Ig==", + "node_modules/vite-node/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@vue/compiler-core": "^3.5.13", - "esbuild": "*", - "vue": "^3.5.13" + "node": ">=18" } }, - "node_modules/vue-tsc": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.0.6.tgz", - "integrity": "sha512-Tbs8Whd43R2e2nxez4WXPvvdjGbW24rOSgRhLOHXzWiT4pcP4G7KeWh0YCn18rF4bVwv7tggLLZ6MJnO6jXPBg==", + "node_modules/vite-node/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@volar/typescript": "2.4.23", - "@vue/language-core": "3.0.6" - }, - "bin": { - "vue-tsc": "bin/vue-tsc.js" - }, - "peerDependencies": { - "typescript": ">=5.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "node_modules/vite-node/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" } }, - "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "node_modules/vite-node/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "node_modules/vite-node/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "license": "MIT" - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "node_modules/vite-node/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, + "os": [ + "netbsd" + ], "engines": { "node": ">=18" } }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "node_modules/vite-node/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", "optional": true, - "peer": true, + "os": [ + "netbsd" + ], "engines": { "node": ">=18" } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/vite-node/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/when-exit": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.5.tgz", - "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==", - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "node_modules/vite-node/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "node_modules/vite-node/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/winston": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", - "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", - "license": "MIT", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.7.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.9.0" - }, + "node_modules/vite-node/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">= 12.0.0" + "node": ">=18" } }, - "node_modules/winston-transport": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", - "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "node_modules/vite-node/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "logform": "^2.7.0", - "readable-stream": "^3.6.2", - "triple-beam": "^1.3.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 12.0.0" + "node": ">=18" } }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/vite-node/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 6" + "node": ">=18" } }, - "node_modules/winston/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/vite-node/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/vite-node/node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-node/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/vite-node/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.10.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/vite-node/node_modules/vite": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/vite-plugin-checker": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.14.1.tgz", + "integrity": "sha512-Mv8oQc9XYBYf+XkP/riqqQCt8lBP6Iad75PZPho1lHRrpxQI0BwX2gwE10enn4f6Hgc+PvR1F7N38KARcaJtzw==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@babel/code-frame": "^7.29.0", + "chokidar": "^5.0.0", + "npm-run-path": "^6.0.0", + "picocolors": "^1.1.1", + "picomatch": "^4.0.4", + "proper-lockfile": "^4.1.2", + "tiny-invariant": "^1.3.3" }, "engines": { - "node": ">=10" + "node": ">=20.19.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "@biomejs/biome": ">=2.4.12", + "eslint": ">=9.39.4", + "meow": "^13.2.0 || ^14.0.0", + "optionator": "^0.9.4", + "oxlint": ">=1", + "stylelint": ">=16.26.1", + "typescript": "*", + "vite": ">=5.4.21", + "vue-tsc": "~2.2.10 || ^3.0.0" + }, + "peerDependenciesMeta": { + "@biomejs/biome": { + "optional": true + }, + "eslint": { + "optional": true + }, + "meow": { + "optional": true + }, + "optionator": { + "optional": true + }, + "oxlint": { + "optional": true + }, + "stylelint": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/vite-plugin-checker/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/vite-plugin-checker/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/vite-plugin-checker/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/vite-plugin-checker/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "node_modules/vite-plugin-inspect": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.4.1.tgz", + "integrity": "sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==", + "dev": true, "license": "MIT", + "dependencies": { + "ansis": "^4.3.0", + "error-stack-parser-es": "^1.0.5", + "obug": "^2.1.1", + "ohash": "^2.0.11", + "open": "^11.0.0", + "perfect-debounce": "^2.1.0", + "sirv": "^3.0.2", + "unplugin-utils": "^0.3.1", + "vite-dev-rpc": "^2.0.0" + }, "engines": { - "node": ">=10.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0" }, "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { + "@nuxt/kit": { "optional": true } } }, - "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "node_modules/vite-plugin-vue-tracer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-tracer/-/vite-plugin-vue-tracer-1.4.0.tgz", + "integrity": "sha512-0tQCjCqZWVSK6UeRW9S4ABbf47lKQ68zvrT2FNvZmiL+alDydCVyH/T3Jlfbdc3T3C2Iuyyl5aVsMbF8IQIoxA==", "dev": true, "license": "MIT", "dependencies": { - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" + "estree-walker": "^3.0.3", + "exsolve": "^1.0.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3", + "source-map-js": "^1.2.1" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0", + "vue": "^3.5.0" } }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "license": "Apache-2.0", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", "dev": true, - "license": "MIT" - }, - "node_modules/xss": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz", - "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==", "license": "MIT", "dependencies": { - "commander": "^2.20.3", - "cssfilter": "0.0.10" + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" }, "bin": { - "xss": "bin/xss" + "vitest": "vitest.mjs" }, "engines": { - "node": ">= 0.10.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "node_modules/xss/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "node_modules/vitest-environment-nuxt": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vitest-environment-nuxt/-/vitest-environment-nuxt-1.0.1.tgz", + "integrity": "sha512-eBCwtIQriXW5/M49FjqNKfnlJYlG2LWMSNFsRVKomc8CaMqmhQPBS5LZ9DlgYL9T8xIVsiA6RZn2lk7vxov3Ow==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" + "dependencies": { + "@nuxt/test-utils": ">=3.13.1" } }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { "node": ">=18" } }, - "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/yauzl/node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", - "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/youch": { - "version": "4.1.0-beta.11", - "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.11.tgz", - "integrity": "sha512-sQi6PERyO/mT8w564ojOVeAlYTtVQmC2GaktQAf+IdI75/GKIggosBuvyVXvEV+FATAT6RbLdIjFoiIId4ozoQ==", + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@poppinss/colors": "^4.1.5", - "@poppinss/dumper": "^0.6.4", - "@speed-highlight/core": "^1.2.7", - "cookie": "^1.0.2", - "youch-core": "^0.3.3" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/youch-core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", - "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@poppinss/exception": "^1.2.2", - "error-stack-parser-es": "^1.0.5" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/zip-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", - "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, "license": "MIT", - "dependencies": { - "archiver-utils": "^5.0.0", - "compress-commons": "^6.0.2", - "readable-stream": "^4.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 14" + "node": ">=18" } }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "packages/ai": { - "name": "@netlify/ai", - "version": "0.4.1", - "dependencies": { - "@netlify/api": "^14.0.18" - }, - "devDependencies": { - "@types/node": "20.14.15", - "npm-run-all2": "^7.0.2", - "tsup": "8.5.1", - "typescript": "5.9.3", - "vitest": "^3.0.0" - }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.6.1" + "node": ">=18" } }, - "packages/ai/node_modules/@types/node": { - "version": "20.14.15", + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "packages/ai/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "packages/ai/node_modules/isexe": { - "version": "3.1.1", + "node_modules/vitest/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=16" + "node": ">=18" } }, - "packages/ai/node_modules/npm-run-all2": { - "version": "7.0.2", + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "cross-spawn": "^7.0.6", - "memorystream": "^0.3.1", - "minimatch": "^9.0.0", - "pidtree": "^0.6.0", - "read-package-json-fast": "^4.0.0", - "shell-quote": "^1.7.3", - "which": "^5.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "npm-run-all2": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": "^18.17.0 || >=20.5.0", - "npm": ">= 9" + "node": ">=18" } }, - "packages/ai/node_modules/which": { - "version": "5.0.0", + "node_modules/vitest/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=18" } }, - "packages/aws-lambda-compat": { - "name": "@netlify/aws-lambda-compat", - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "npm-run-all2": "^5.0.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=20.6.1" + "node": ">=18" } }, - "packages/aws-lambda-compat/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/vitest/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "packages/aws-lambda-compat/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "packages/aws-lambda-compat/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "packages/aws-lambda-compat/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "packages/aws-lambda-compat/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "packages/aws-lambda-compat/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "packages/aws-lambda-compat/node_modules/npm-run-all2": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-5.0.2.tgz", - "integrity": "sha512-S2G6FWZ3pNWAAKm2PFSOtEAG/N+XO/kz3+9l6V91IY+Y3XFSt7Lp7DV92KCgEboEW0hRTu0vFaMe4zXDZYaOyA==", + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^5.0.0", - "cross-spawn": "^7.0.3", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.5.0", - "read-pkg": "^5.2.0", - "shell-quote": "^1.6.1" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "packages/aws-lambda-compat/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "packages/aws-lambda-compat/node_modules/pidtree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", - "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", + "node_modules/vitest/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, + "hasInstallScript": true, "license": "MIT", "bin": { - "pidtree": "bin/pidtree.js" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=0.10" - } - }, - "packages/aws-lambda-compat/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/vitest/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "packages/aws-lambda-compat/node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "node_modules/vitest/node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/vite": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { - "resolve": "bin/resolve" + "vite": "bin/vite.js" }, "engines": { - "node": ">= 0.4" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/aws-lambda-compat/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "packages/aws-lambda-compat/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "packages/blobs": { - "name": "@netlify/blobs", - "version": "10.7.9", - "license": "MIT", - "dependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/otel": "^6.0.3", - "@netlify/runtime-utils": "2.3.0" + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "devDependencies": { - "@types/node": "^18.19.110", - "node-fetch": "^3.3.1", - "npm-run-all2": "^8.0.4", - "semver": "^7.5.3", - "tmp-promise": "^3.0.3", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "optionalDependencies": { + "fsevents": "~2.3.3" }, - "engines": { - "node": "^14.16.0 || >=16.0.0" - } - }, - "packages/blobs/node_modules/@types/node": { - "version": "18.19.124", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", - "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "packages/blobs/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "node_modules/vitest/node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", "dev": true, "license": "MIT", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "url": "https://opencollective.com/vitest" } }, - "packages/cache": { - "name": "@netlify/cache", - "version": "3.4.8", + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz", + "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==", + "dev": true, "license": "MIT", "dependencies": { - "@netlify/runtime-utils": "2.3.0" + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-sfc": "3.5.35", + "@vue/runtime-dom": "3.5.35", + "@vue/server-renderer": "3.5.35", + "@vue/shared": "3.5.35" }, - "devDependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/types": "2.8.0", - "npm-run-all2": "^7.0.2", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "peerDependencies": { + "typescript": "*" }, - "engines": { - "node": ">=20.6.1" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "packages/cache/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/vue-bundle-renderer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.2.0.tgz", + "integrity": "sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "dependencies": { + "ufo": "^1.6.1" } }, - "packages/cache/node_modules/isexe": { - "version": "3.1.1", + "node_modules/vue-devtools-stub": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz", + "integrity": "sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } + "license": "MIT" }, - "packages/cache/node_modules/npm-run-all2": { - "version": "7.0.2", + "node_modules/vue-eslint-parser": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.1.tgz", + "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "cross-spawn": "^7.0.6", - "memorystream": "^0.3.1", - "minimatch": "^9.0.0", - "pidtree": "^0.6.0", - "read-package-json-fast": "^4.0.0", - "shell-quote": "^1.7.3", - "which": "^5.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "npm-run-all2": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" + "debug": "^4.4.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", + "esquery": "^1.6.0", + "semver": "^7.6.3" }, "engines": { - "node": "^18.17.0 || >=20.5.0", - "npm": ">= 9" - } - }, - "packages/cache/node_modules/which": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "bin": { - "node-which": "bin/which.js" + "funding": { + "url": "https://github.com/sponsors/mysticatea" }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" } }, - "packages/database/dev": { - "name": "@netlify/database-dev", - "version": "0.10.1", + "node_modules/vue-router": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.1.0.tgz", + "integrity": "sha512-HAbiLzLEHQwxPgvsbOJDAwtavszEgLwri6XfyrsPECIFez8+59xc9LofWVdc/HEaSRT822lJ8H9Ns38VVond5g==", + "dev": true, "license": "MIT", "dependencies": { - "@electric-sql/pglite": "^0.3.15", - "pg-gateway": "0.3.0-beta.4" + "@babel/generator": "^8.0.0-rc.4", + "@vue-macros/common": "^3.1.1", + "@vue/devtools-api": "^8.1.2", + "ast-walker-scope": "^0.9.0", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.2", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.16", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1", + "yaml": "^2.9.0" }, - "devDependencies": { - "@types/pg": "^8.11.0", - "pg": "^8.11.0", - "tmp-promise": "^3.0.3", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "funding": { + "url": "https://github.com/sponsors/posva" }, - "engines": { - "node": ">=20.6.1" + "peerDependencies": { + "@pinia/colada": ">=0.21.2", + "@vue/compiler-sfc": "^3.5.34", + "pinia": "^3.0.4", + "vite": "^7.0.0 || ^8.0.0", + "vue": "^3.5.34" + }, + "peerDependenciesMeta": { + "@pinia/colada": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "pinia": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "packages/database/prod": { - "name": "@netlify/database", - "version": "1.0.0", + "node_modules/vue-router/node_modules/@babel/generator": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0-rc.6.tgz", + "integrity": "sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==", + "dev": true, "license": "MIT", "dependencies": { - "@neondatabase/serverless": "^1.1.0", - "@netlify/runtime-utils": "2.3.0", - "pg": "^8.13.0", - "waddler": "^0.1.1", - "ws": "^8.18.0" - }, - "devDependencies": { - "@types/ws": "^8.18.1", - "npm-run-all2": "^5.0.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "@babel/parser": "^8.0.0-rc.6", + "@babel/types": "^8.0.0-rc.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "@types/jsesc": "^2.5.0", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=20.6.1" + "node": "^22.18.0 || >=24.11.0" } }, - "packages/database/prod/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/vue-router/node_modules/@babel/helper-string-parser": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0-rc.6.tgz", + "integrity": "sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^22.18.0 || >=24.11.0" } }, - "packages/database/prod/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "node_modules/vue-router/node_modules/@babel/helper-validator-identifier": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.0-rc.6.tgz", + "integrity": "sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": "^22.18.0 || >=24.11.0" } }, - "packages/database/prod/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "packages/database/prod/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "packages/database/prod/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/vue-router/node_modules/@babel/parser": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0-rc.6.tgz", + "integrity": "sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/types": "^8.0.0-rc.6" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": "*" - } - }, - "packages/database/prod/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "node": "^22.18.0 || >=24.11.0" } }, - "packages/database/prod/node_modules/npm-run-all2": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-5.0.2.tgz", - "integrity": "sha512-S2G6FWZ3pNWAAKm2PFSOtEAG/N+XO/kz3+9l6V91IY+Y3XFSt7Lp7DV92KCgEboEW0hRTu0vFaMe4zXDZYaOyA==", + "node_modules/vue-router/node_modules/@babel/types": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0-rc.6.tgz", + "integrity": "sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^5.0.0", - "cross-spawn": "^7.0.3", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.5.0", - "read-pkg": "^5.2.0", - "shell-quote": "^1.6.1" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" + "@babel/helper-string-parser": "^8.0.0-rc.6", + "@babel/helper-validator-identifier": "^8.0.0-rc.6" }, "engines": { - "node": ">= 10" + "node": "^22.18.0 || >=24.11.0" } }, - "packages/database/prod/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/vue-router/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "readdirp": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://paulmillr.com/funding/" } }, - "packages/database/prod/node_modules/pidtree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", - "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", + "node_modules/vue-router/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, "engines": { - "node": ">=0.10" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "packages/database/prod/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/vue-router/node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", "dev": true, "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" }, "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" } }, - "packages/database/prod/node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "node_modules/vue-sfc-transformer": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/vue-sfc-transformer/-/vue-sfc-transformer-0.1.17.tgz", + "integrity": "sha512-0mpkDTWm1ybtp/Mp3vhrXP4r8yxcGF+quxGyJfrHDl2tl5naQjK3xkIGaVR5BtR5KG1LWJbdCrqn7I6f460j9A==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "@babel/parser": "^7.27.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@vue/compiler-core": "^3.5.13", + "esbuild": "*", + "vue": "^3.5.13" } }, - "packages/database/prod/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/vue-tsc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.3.tgz", + "integrity": "sha512-SWUEG7YRUeDJHT7Xsuhf02elYX2gxPzzAII7OxDAh4KNOr4QHQ0Lls0YfnaO5GNd560CwVa2HTfdqmA5MqvRqQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.3.3" + }, "bin": { - "semver": "bin/semver" - } - }, - "packages/database/prod/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" } }, - "packages/database/prod/node_modules/waddler": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/waddler/-/waddler-0.1.1.tgz", - "integrity": "sha512-lBJXYFBLEpYe+scAeCJmLj6Iqweuq1whM6Am3I9WfopOCFxvKz8Nq5hXoy8/b3zwJqHIQMglFIvM4skRydSpZg==", - "license": "MIT", - "peerDependencies": { - "@clickhouse/client": "^1.11.2", - "@duckdb/node-api": "^1.1.2-alpha.4", - "@electric-sql/pglite": "^0.2.17", - "@libsql/client": "^0.15.4", - "@libsql/client-wasm": "^0.15.4", - "@neondatabase/serverless": "^1.0.0", - "@planetscale/database": "^1.19.0", - "@tidbcloud/serverless": "^0.2.0", - "@vercel/postgres": "^0.10.0", - "@xata.io/client": "^0.30.1", - "better-sqlite3": "^11.9.1", - "bun-types": "*", - "duckdb": "^1.2.1", - "gel": "^2.0.2", - "mysql2": "^3.14.0", - "pg": "^8.14.0", - "pg-query-stream": "^4.8.0", - "postgres": "^3.4.5" - }, - "peerDependenciesMeta": { - "@clickhouse/client": { - "optional": true - }, - "@cloudflare/workers-types": { - "optional": true - }, - "@duckdb/node-api": { - "optional": true - }, - "@electric-sql/pglite": { - "optional": true - }, - "@libsql/client": { - "optional": true - }, - "@libsql/client-wasm": { - "optional": true - }, - "@neondatabase/serverless": { - "optional": true - }, - "@op-engineering/op-sqlite": { - "optional": true - }, - "@planetscale/database": { - "optional": true - }, - "@tidbcloud/serverless": { - "optional": true - }, - "@vercel/postgres": { - "optional": true - }, - "@xata.io/client": { - "optional": true - }, - "better-sqlite3": { - "optional": true - }, - "bun-types": { - "optional": true - }, - "duckdb": { - "optional": true - }, - "gel": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-query-stream": { - "optional": true - }, - "postgres": { - "optional": true - } + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "packages/database/proxy": { - "name": "@netlify/database-proxy", - "version": "0.1.5", + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { - "pg": "^8.11.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/when-exit": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.5.tgz", + "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==", + "license": "MIT" + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" }, - "devDependencies": { - "@netlify/database-dev": "0.10.1", - "@types/pg": "^8.11.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">=20.6.1" + "node": "^18.17.0 || >=20.5.0" } }, - "packages/db/dev": { - "name": "@netlify/db-dev", - "version": "0.7.0", - "extraneous": true, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "license": "MIT", "dependencies": { - "@electric-sql/pglite": "^0.3.15", - "pg-gateway": "0.3.0-beta.4" - }, - "devDependencies": { - "@types/pg": "^8.11.0", - "pg": "^8.11.0", - "tmp-promise": "^3.0.3", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" }, "engines": { - "node": ">=20.6.1" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "packages/db/prod": { - "name": "@netlify/db", - "version": "0.4.0", - "extraneous": true, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "license": "MIT", "dependencies": { - "@netlify/runtime-utils": "2.3.0", - "waddler": "^0.1.1", - "ws": "^8.18.0" - }, - "devDependencies": { - "@neondatabase/serverless": "^1.0.0", - "@types/ws": "^8.18.1", - "npm-run-all2": "^5.0.0", - "pg": "^8.13.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" }, "engines": { - "node": ">=20.6.1" + "node": ">= 0.4" }, - "peerDependencies": { - "@neondatabase/serverless": ">=0.10.0", - "pg": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "packages/db/proxy": { - "name": "@netlify/db-proxy", - "version": "0.1.1", - "extraneous": true, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "license": "MIT", "dependencies": { - "pg": "^8.11.0" - }, - "devDependencies": { - "@netlify/db-dev": "*", - "@types/pg": "^8.11.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" }, "engines": { - "node": ">=20.6.1" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "packages/dev": { - "name": "@netlify/dev", - "version": "4.18.7", + "node_modules/which-typed-array": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.21.tgz", + "integrity": "sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==", "license": "MIT", "dependencies": { - "@netlify/ai": "^0.4.1", - "@netlify/blobs": "10.7.9", - "@netlify/config": "^24.5.0", - "@netlify/database-dev": "0.10.1", - "@netlify/dev-utils": "4.4.6", - "@netlify/edge-functions-dev": "1.0.20", - "@netlify/functions-dev": "1.3.0", - "@netlify/headers": "2.1.11", - "@netlify/images": "1.3.10", - "@netlify/redirects": "3.1.13", - "@netlify/runtime": "4.1.25", - "@netlify/static": "3.1.10", - "ulid": "^3.0.0" - }, - "devDependencies": { - "@netlify/api": "^14.0.18", - "@netlify/types": "2.8.0", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=20.6.1" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "packages/dev-utils": { - "name": "@netlify/dev-utils", - "version": "4.4.6", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, "license": "MIT", "dependencies": { - "@whatwg-node/server": "^0.10.0", - "ansis": "^4.1.0", - "atomically": "^2.0.3", - "chokidar": "^4.0.1", - "decache": "^4.6.2", - "dettle": "^1.0.5", - "dot-prop": "9.0.0", - "empathic": "^2.0.0", - "env-paths": "^3.0.0", - "image-size": "^2.0.2", - "js-image-generator": "^1.0.4", - "parse-gitignore": "^2.0.0", - "semver": "^7.7.2", - "tmp-promise": "^3.0.3" + "siginfo": "^2.0.0", + "stackback": "0.0.2" }, - "devDependencies": { - "@netlify/types": "2.8.0", - "@types/node": "^18.19.110", - "@types/parse-gitignore": "^1.0.2", - "execa": "^8.0.1", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "bin": { + "why-is-node-running": "cli.js" }, "engines": { - "node": "^18.14.0 || >=20" + "node": ">=8" } }, - "packages/dev-utils/node_modules/@types/node": { - "version": "18.19.124", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", - "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", - "dev": true, + "node_modules/winston": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.8", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" } }, - "packages/edge-functions": { - "name": "@netlify/edge-functions", - "version": "3.0.8", + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", "license": "MIT", "dependencies": { - "@netlify/dev-utils": "4.3.0", - "@netlify/edge-bundler": "^14.5.2", - "@netlify/edge-functions-bootstrap": "2.16.0", - "@netlify/runtime-utils": "2.2.0", - "@netlify/types": "2.1.0", - "get-port": "^7.1.0" - }, - "devDependencies": { - "execa": "^8.0.1", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" }, "engines": { - "node": ">=18.0.0" + "node": ">= 12.0.0" } }, - "packages/edge-functions/dev": { - "name": "@netlify/edge-functions-dev", - "version": "1.0.20", + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/edge-bundler": "^14.10.1", - "@netlify/edge-functions": "3.0.8", - "@netlify/edge-functions-bootstrap": "2.16.0", - "@netlify/runtime-utils": "2.3.0", - "get-port": "^7.1.0" - }, - "devDependencies": { - "execa": "^8.0.1", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=20.6.1" + "node": ">= 6" } }, - "packages/edge-functions/prod": { - "name": "@netlify/edge-functions", - "version": "3.0.8", + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", - "dependencies": { - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, "engines": { - "node": ">=18.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/functions": { - "name": "@netlify/functions", - "version": "5.3.0", + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { - "@netlify/blobs": "10.1.0", - "@netlify/dev-utils": "4.3.0", - "@netlify/types": "2.1.0", - "@netlify/zip-it-and-ship-it": "^14.1.3", - "cron-parser": "^4.9.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", - "source-map-support": "^0.5.21" - }, - "devDependencies": { - "@types/semver": "^7.5.8", - "@types/source-map-support": "^0.5.10", - "npm-run-all2": "^5.0.0", - "semver": "^7.6.3", - "tsd": "^0.32.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=18.0.0" + "node": ">= 6" } }, - "packages/functions/dev": { - "name": "@netlify/functions-dev", - "version": "1.3.0", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", - "dependencies": { - "@netlify/blobs": "10.7.9", - "@netlify/dev-utils": "4.4.6", - "@netlify/functions": "5.3.0", - "@netlify/zip-it-and-ship-it": "^14.5.5", - "cron-parser": "^4.9.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", - "semver": "^7.6.3", - "source-map-support": "^0.5.21" - }, - "devDependencies": { - "@types/semver": "^7.5.8", - "@types/source-map-support": "^0.5.10", - "npm-run-all2": "^5.0.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=20.6.1" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "packages/functions/node_modules/ansi-styles": { - "version": "5.2.0", - "dev": true, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "packages/functions/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=8" } }, - "packages/functions/node_modules/hosted-git-info": { - "version": "2.8.9", - "dev": true, - "license": "ISC" - }, - "packages/functions/node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "packages/functions/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "packages/functions/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": "*" + "node": ">=8" } }, - "packages/functions/node_modules/normalize-package-data": { - "version": "2.5.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "packages/functions/node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, - "packages/functions/node_modules/npm-run-all2": { - "version": "5.0.2", + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^5.0.0", - "cross-spawn": "^7.0.3", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.5.0", - "read-pkg": "^5.2.0", - "shell-quote": "^1.6.1" + "engines": { + "node": ">=10.0.0" }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" }, - "engines": { - "node": ">= 10" + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "packages/functions/node_modules/parse-json": { - "version": "5.2.0", + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" }, "engines": { - "node": ">=8" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/functions/node_modules/pidtree": { - "version": "0.5.0", + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, + "license": "Apache-2.0", "engines": { - "node": ">=0.10" + "node": ">=12" } }, - "packages/functions/node_modules/read-pkg": { - "version": "5.2.0", - "dev": true, + "node_modules/xss": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz", + "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==", "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "commander": "^2.20.3", + "cssfilter": "0.0.10" + }, + "bin": { + "xss": "bin/xss" }, "engines": { - "node": ">=8" + "node": ">= 0.10.0" + } + }, + "node_modules/xss/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" } }, - "packages/functions/node_modules/resolve": { - "version": "1.22.10", + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", "bin": { - "resolve": "bin/resolve" + "yaml": "bin.mjs" }, "engines": { - "node": ">= 0.4" + "node": ">= 14.6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/functions/node_modules/type-fest": { - "version": "0.6.0", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/eemeli" } }, - "packages/functions/prod": { - "name": "@netlify/functions", - "version": "5.3.0", + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "license": "MIT", "dependencies": { - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "npm-run-all2": "^5.0.0", - "semver": "^7.6.3", - "tsd": "^0.32.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=12" } }, - "packages/headers": { - "name": "@netlify/headers", - "version": "2.1.11", - "license": "MIT", - "dependencies": { - "@netlify/headers-parser": "^9.0.3" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/node": "^20.17.57", - "tsup": "^8.0.0", - "vitest": "^3.1.4" - }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", "engines": { - "node": ">=20.6.1" + "node": ">=12" } }, - "packages/headers/node_modules/@types/node": { - "version": "20.19.11", - "dev": true, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "engines": { + "node": ">=8" } }, - "packages/headers/node_modules/undici-types": { - "version": "6.21.0", - "dev": true, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "packages/identity/prod": { - "name": "@netlify/identity", - "version": "1.2.0", + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { - "gotrue-js": "^1.0.1" - }, - "devDependencies": { - "@types/node": "^22.0.0", - "jsdom": "^28.1.0", - "tsup": "^8.0.0", - "vitest": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=8" } }, - "packages/identity/prod/node_modules/@asamuzakjp/css-color": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.1.tgz", - "integrity": "sha512-iGWN8E45Ws0XWx3D44Q1t6vX2LqhCKcwfmwBYCDsFrYFS6m4q/Ks61L2veETaLv+ckDC6+dTETJoaAAb7VjLiw==", - "dev": true, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "license": "MIT", "dependencies": { - "@csstools/css-calc": "^3.1.1", - "@csstools/css-color-parser": "^4.0.2", - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "lru-cache": "^11.2.7" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, - "packages/identity/prod/node_modules/@csstools/color-helpers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", - "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/yauzl/node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", "engines": { - "node": ">=20.19.0" + "node": "*" } }, - "packages/identity/prod/node_modules/@csstools/css-calc": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", - "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", "license": "MIT", "engines": { - "node": ">=20.19.0" + "node": ">=12.20" }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/identity/prod/node_modules/@csstools/css-color-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", - "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", + "node_modules/youch": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.1.tgz", + "integrity": "sha512-mxW3qiSnl+GRxXsaUMzv2Mbada1Y8CDltET9UxejDQe6DBYlSekghl5U5K0ReAikcHDi0G1vKZEmmo/NWAGKLA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.1.1" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" + "@poppinss/colors": "^4.1.6", + "@poppinss/dumper": "^0.7.0", + "@speed-highlight/core": "^1.2.14", + "cookie-es": "^3.0.1", + "youch-core": "^0.3.3" } }, - "packages/identity/prod/node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "node_modules/youch-core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", + "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^4.0.0" + "dependencies": { + "@poppinss/exception": "^1.2.2", + "error-stack-parser-es": "^1.0.5" } }, - "packages/identity/prod/node_modules/@csstools/css-tokenizer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "node_modules/youch/node_modules/cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "license": "MIT" + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, "engines": { - "node": ">=20.19.0" + "node": ">= 14" } }, - "packages/identity/prod/node_modules/@types/node": { - "version": "22.19.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz", - "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==", - "dev": true, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, - "packages/identity/prod/node_modules/cssstyle": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", - "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", - "dev": true, + "packages/nuxt-module": { + "name": "@netlify/nuxt", + "version": "0.3.7", "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^5.0.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.28", - "css-tree": "^3.1.0", - "lru-cache": "^11.2.6" + "@netlify/dev": "^4.18.7", + "@netlify/dev-utils": "^4.4.6", + "@nuxt/kit": "^4.0.0", + "h3": "^1.15.3" + }, + "devDependencies": { + "@nuxt/devtools": "^2.6.2", + "@nuxt/devtools-kit": "^2.6.2", + "@nuxt/eslint-config": "^1.5.2", + "@nuxt/module-builder": "^1.0.1", + "@nuxt/schema": "^3.17.6", + "@nuxt/test-utils": "^3.19.2", + "@types/node": "^22.16.3", + "eslint": "^9.30.1", + "nuxt": "^4.0.0", + "typescript": "~5.9.0", + "vitest": "^3.2.4", + "vue-tsc": "^3.0.1" }, "engines": { - "node": ">=20" + "node": "^20.19.0 || >=22.12.0" } }, - "packages/identity/prod/node_modules/data-urls": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", - "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "packages/nuxt-module/node_modules/@nuxt/schema": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.21.7.tgz", + "integrity": "sha512-H35IqlFu4YHXnW0Aw24yCpRuWOJjd9iwS6u9vinsopJo8rrM1/2aKMajX3l9ifhni1XN8nqcKo622z+5ZCQM4w==", "dev": true, "license": "MIT", "dependencies": { - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0" + "@vue/shared": "^3.5.34", + "defu": "^6.1.7", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "std-env": "^4.1.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "packages/identity/prod/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "node": "^14.18.0 || >=16.10.0" } }, - "packages/identity/prod/node_modules/html-encoding-sniffer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", - "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", - "dev": true, + "packages/vite-plugin": { + "name": "@netlify/vite-plugin", + "version": "2.12.7", "license": "MIT", "dependencies": { - "@exodus/bytes": "^1.6.0" + "@netlify/dev": "4.18.7", + "@netlify/dev-utils": "^4.4.6", + "dedent": "^1.7.0" + }, + "devDependencies": { + "@types/node": "^20.17.57", + "playwright": "^1.60.0", + "tsup": "^8.0.0", + "vite": "^6.3.6", + "vitest": "^3.0.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^20.6.1 || >=22" + }, + "peerDependencies": { + "vite": "^5 || ^6 || ^7 || ^8" } }, - "packages/identity/prod/node_modules/jsdom": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", - "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", - "dev": true, + "packages/vite-plugin-tanstack-start": { + "name": "@netlify/vite-plugin-tanstack-start", + "version": "1.3.15", "license": "MIT", "dependencies": { - "@acemir/cssom": "^0.9.31", - "@asamuzakjp/dom-selector": "^6.8.1", - "@bramus/specificity": "^2.4.2", - "@exodus/bytes": "^1.11.0", - "cssstyle": "^6.0.1", - "data-urls": "^7.0.0", - "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^6.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "parse5": "^8.0.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.0", - "undici": "^7.21.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.1", - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0", - "xml-name-validator": "^5.0.0" + "@netlify/vite-plugin": "^2.12.7" + }, + "devDependencies": { + "@netlify/dev-utils": "^4.4.6", + "@types/node": "^22.18.5", + "normalize-package-data": "^8.0.0", + "playwright": "^1.60.0", + "semver": "^7.7.2", + "tsup": "^8.0.0", + "vite": "^8.0.0", + "vitest": "^3.0.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.12.0 || >=24.0.0" }, "peerDependencies": { - "canvas": "^3.0.0" + "@tanstack/react-start": ">=1.132.0", + "@tanstack/solid-start": ">=1.132.0", + "vite": ">=7.0.0" }, "peerDependenciesMeta": { - "canvas": { + "@tanstack/react-start": { + "optional": true + }, + "@tanstack/solid-start": { "optional": true } } }, - "packages/identity/prod/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "packages/vite-plugin-tanstack-start/node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "packages/vite-plugin-tanstack-start/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, - "packages/identity/prod/node_modules/parse5": { + "packages/vite-plugin-tanstack-start/node_modules/normalize-package-data": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", + "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "entities": "^6.0.0" + "hosted-git-info": "^9.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "packages/identity/prod/node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "packages/vite-plugin/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=20" + "node": ">=18" } }, - "packages/identity/prod/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "packages/identity/prod/node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "packages/vite-plugin/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20" + "node": ">=18" } }, - "packages/identity/prod/node_modules/whatwg-mimetype": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", - "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "packages/vite-plugin/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20" + "node": ">=18" } }, - "packages/identity/prod/node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "packages/vite-plugin/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=18" } }, - "packages/identity/prod/node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "packages/vite-plugin/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": ">=18" } }, - "packages/images": { - "name": "@netlify/images", - "version": "1.3.10", + "packages/vite-plugin/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "ipx": "^3.1.1" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "tsup": "^8.5.0", - "vitest": "^3.1.4" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=20.6.1" + "node": ">=18" } }, - "packages/nuxt-module": { - "name": "@netlify/nuxt", - "version": "0.3.7", + "packages/vite-plugin/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@netlify/dev": "^4.18.7", - "@netlify/dev-utils": "^4.4.6", - "@nuxt/kit": "^4.0.0", - "h3": "^1.15.3" - }, - "devDependencies": { - "@nuxt/devtools": "^2.6.2", - "@nuxt/devtools-kit": "^2.6.2", - "@nuxt/eslint-config": "^1.5.2", - "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^3.17.6", - "@nuxt/test-utils": "^3.19.2", - "@types/node": "^22.16.3", - "eslint": "^9.30.1", - "nuxt": "^4.0.0", - "typescript": "~5.9.0", - "vitest": "^3.2.4", - "vue-tsc": "^3.0.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "packages/nuxt-module/node_modules/@types/node": { - "version": "22.17.2", + "packages/vite-plugin/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "packages/nuxt-module/node_modules/undici-types": { - "version": "6.21.0", + "packages/vite-plugin/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" - }, - "packages/otel": { - "name": "@netlify/otel", - "version": "6.0.3", "license": "MIT", - "dependencies": { - "@opentelemetry/api": "1.9.0", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/instrumentation": "^0.217.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-trace-node": "2.7.1" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "msw": "^2.10.5", - "npm-run-all2": "^7.0.2", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || >=20.6.1" + "node": ">=18" } }, - "packages/otel/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "packages/vite-plugin/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "packages/otel/node_modules/isexe": { - "version": "3.1.1", + "packages/vite-plugin/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">=18" } }, - "packages/otel/node_modules/npm-run-all2": { - "version": "7.0.2", + "packages/vite-plugin/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "cross-spawn": "^7.0.6", - "memorystream": "^0.3.1", - "minimatch": "^9.0.0", - "pidtree": "^0.6.0", - "read-package-json-fast": "^4.0.0", - "shell-quote": "^1.7.3", - "which": "^5.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "npm-run-all2": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.17.0 || >=20.5.0", - "npm": ">= 9" + "node": ">=18" } }, - "packages/otel/node_modules/which": { - "version": "5.0.0", + "packages/vite-plugin/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=18" } }, - "packages/redirects": { - "name": "@netlify/redirects", - "version": "3.1.13", + "packages/vite-plugin/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/redirect-parser": "^15.0.4", - "cookie": "^1.0.2", - "jsonwebtoken": "9.0.3", - "netlify-redirector": "^0.5.0" - }, - "devDependencies": { - "@types/jsonwebtoken": "9.0.10", - "tsup": "^8.5.0", - "vitest": "^3.1.4" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.6.1" + "node": ">=18" } }, - "packages/runtime": { - "name": "@netlify/runtime", - "version": "4.1.25", + "packages/vite-plugin/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@netlify/blobs": "^10.7.9", - "@netlify/cache": "3.4.8", - "@netlify/runtime-utils": "2.3.0", - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/node": "^20.17.57", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.6.1" + "node": ">=18" } }, - "packages/runtime-utils": { - "name": "@netlify/runtime-utils", - "version": "2.3.0", + "packages/vite-plugin/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, "license": "MIT", - "devDependencies": { - "@types/node": "^18.19.110", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || >=20" + "node": ">=18" } }, - "packages/runtime-utils/node_modules/@types/node": { - "version": "18.19.124", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", - "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", + "packages/vite-plugin/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "packages/runtime/node_modules/@types/node": { - "version": "20.19.11", + "packages/vite-plugin/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "packages/runtime/node_modules/undici-types": { - "version": "6.21.0", + "packages/vite-plugin/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "packages/static": { - "name": "@netlify/static", - "version": "3.1.10", "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/mime-types": "^2.1.4", - "tsup": "^8.5.0", - "vitest": "^3.1.4" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=20.6.1" + "node": ">=18" } }, - "packages/types": { - "name": "@netlify/types", - "version": "2.8.0", + "packages/vite-plugin/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "devDependencies": { - "@types/node": "^18.19.110", - "tsup": "^8.0.0", - "typescript": "^5.8.3", - "vitest": "^3.0.0" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": "^18.14.0 || >=20" + "node": ">=18" } }, - "packages/types/node_modules/@types/node": { - "version": "18.19.124", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", - "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", + "packages/vite-plugin/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "packages/vite-plugin": { - "name": "@netlify/vite-plugin", - "version": "2.12.7", + "packages/vite-plugin/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@netlify/dev": "4.18.7", - "@netlify/dev-utils": "^4.4.6", - "dedent": "^1.7.0" - }, - "devDependencies": { - "@types/node": "^20.17.57", - "playwright": "^1.60.0", - "tsup": "^8.0.0", - "vite": "^6.3.6", - "vitest": "^3.0.0" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": "^20.6.1 || >=22" - }, - "peerDependencies": { - "vite": "^5 || ^6 || ^7 || ^8" + "node": ">=18" } }, - "packages/vite-plugin-tanstack-start": { - "name": "@netlify/vite-plugin-tanstack-start", - "version": "1.3.15", + "packages/vite-plugin/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@netlify/vite-plugin": "^2.12.7" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/node": "^22.18.5", - "normalize-package-data": "^8.0.0", - "playwright": "^1.60.0", - "semver": "^7.7.2", - "tsup": "^8.0.0", - "vite": "^8.0.0", - "vitest": "^3.0.0" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": "^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@tanstack/react-start": ">=1.132.0", - "@tanstack/solid-start": ">=1.132.0", - "vite": ">=7.0.0" - }, - "peerDependenciesMeta": { - "@tanstack/react-start": { - "optional": true - }, - "@tanstack/solid-start": { - "optional": true - } + "node": ">=18" } }, - "packages/vite-plugin-tanstack-start/node_modules/@types/node": { - "version": "22.18.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", - "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", + "packages/vite-plugin/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "packages/vite-plugin-tanstack-start/node_modules/hosted-git-info": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.0.tgz", - "integrity": "sha512-gEf705MZLrDPkbbhi8PnoO4ZwYgKoNL+ISZ3AjZMht2r3N5tuTwncyDi6Fv2/qDnMmZxgs0yI8WDOyR8q3G+SQ==", + "packages/vite-plugin/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=18" } }, - "packages/vite-plugin-tanstack-start/node_modules/lru-cache": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.1.tgz", - "integrity": "sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==", + "packages/vite-plugin/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "20 || >=22" + "node": ">=18" } }, - "packages/vite-plugin-tanstack-start/node_modules/normalize-package-data": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", - "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", + "packages/vite-plugin/node_modules/@types/node": { + "version": "20.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", + "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "hosted-git-info": "^9.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" + "undici-types": "~6.21.0" } }, - "packages/vite-plugin-tanstack-start/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "packages/vite-plugin-tanstack-start/node_modules/vite": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz", - "integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==", + "packages/vite-plugin/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@oxc-project/runtime": "0.115.0", - "lightningcss": "^1.32.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.9", - "tinyglobby": "^0.2.15" - }, "bin": { - "vite": "bin/vite.js" + "esbuild": "bin/esbuild" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" + "node": ">=18" }, "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.0.0-alpha.31", - "esbuild": "^0.27.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "packages/vite-plugin/node_modules/@types/node": { - "version": "20.19.11", + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "packages/vite-plugin/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "packages/vite-plugin/node_modules/undici-types": { - "version": "6.21.0", - "dev": true, - "license": "MIT" - }, "packages/vite-plugin/node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index d9c160f..04b36b7 100644 --- a/package.json +++ b/package.json @@ -3,29 +3,7 @@ "private": true, "type": "module", "workspaces": [ - "packages/types", - "packages/dev-utils", - "packages/runtime-utils", - "packages/otel", - "packages/blobs", - "packages/cache", - "packages/database/dev", - "packages/database/proxy", - "packages/database/prod", - "packages/edge-functions/prod", - "packages/edge-functions/dev", - "packages/functions/prod", - "packages/functions/dev", - "packages/headers", - "packages/images", - "packages/redirects", - "packages/runtime", - "packages/static", - "packages/ai", - "packages/dev", "packages/nuxt-module", - "packages/aws-lambda-compat", - "packages/identity/prod", "packages/vite-plugin", "packages/vite-plugin-tanstack-start" ], diff --git a/packages/ai/.gitignore b/packages/ai/.gitignore deleted file mode 100644 index 53c37a1..0000000 --- a/packages/ai/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist \ No newline at end of file diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md deleted file mode 100644 index 0bf4e07..0000000 --- a/packages/ai/CHANGELOG.md +++ /dev/null @@ -1,93 +0,0 @@ -# Changelog - -## [0.4.1](https://github.com/netlify/primitives/compare/ai-v0.4.0...ai-v0.4.1) (2026-03-13) - - -### Bug Fixes - -* **deps:** update netlify packages ([#626](https://github.com/netlify/primitives/issues/626)) ([a87ba84](https://github.com/netlify/primitives/commit/a87ba84fa23c3a4ff506cd9c3d5f3b5cd78d9f3c)) - -## [0.4.0](https://github.com/netlify/primitives/compare/ai-v0.3.8...ai-v0.4.0) (2026-03-03) - - -### Features - -* account-based token fetch ([#604](https://github.com/netlify/primitives/issues/604)) ([b772f0d](https://github.com/netlify/primitives/commit/b772f0d96d1b2cb1d313d8397cce5b8b2d4161ae)) - -## [0.3.8](https://github.com/netlify/primitives/compare/ai-v0.3.7...ai-v0.3.8) (2026-02-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#583](https://github.com/netlify/primitives/issues/583)) ([bcd8241](https://github.com/netlify/primitives/commit/bcd824172757fecac5aa91dc36b06163efb63497)) - -## [0.3.7](https://github.com/netlify/primitives/compare/ai-v0.3.6...ai-v0.3.7) (2026-02-16) - - -### Bug Fixes - -* **ai:** remove unnecessary peer dep on `@netlify/api` ([#586](https://github.com/netlify/primitives/issues/586)) ([4534873](https://github.com/netlify/primitives/commit/4534873798b95564b196c679d6b9bcf79fa3124d)) - -## [0.3.6](https://github.com/netlify/primitives/compare/ai-v0.3.5...ai-v0.3.6) (2026-01-28) - - -### Bug Fixes - -* **deps:** update netlify packages ([#576](https://github.com/netlify/primitives/issues/576)) ([1c6ff24](https://github.com/netlify/primitives/commit/1c6ff247318b8cdb1961ce76e96fe423a4ec8cd7)) - -## [0.3.5](https://github.com/netlify/primitives/compare/ai-v0.3.4...ai-v0.3.5) (2025-12-08) - - -### Bug Fixes - -* **deps:** update netlify packages ([#557](https://github.com/netlify/primitives/issues/557)) ([60644bf](https://github.com/netlify/primitives/commit/60644bf6863a0ba41d9e73b0d8d1cfa90205c963)) - -## [0.3.4](https://github.com/netlify/primitives/compare/ai-v0.3.3...ai-v0.3.4) (2025-12-03) - - -### Bug Fixes - -* **deps:** update netlify packages ([#549](https://github.com/netlify/primitives/issues/549)) ([ec4fb29](https://github.com/netlify/primitives/commit/ec4fb2978af5cf75c12645ade9f771bc94a796e2)) - -## [0.3.3](https://github.com/netlify/primitives/compare/ai-v0.3.2...ai-v0.3.3) (2025-11-05) - - -### Bug Fixes - -* **deps:** update dependency @netlify/api to v14.0.10 ([#521](https://github.com/netlify/primitives/issues/521)) ([61869e9](https://github.com/netlify/primitives/commit/61869e902052157006031d64089afb90c298b92c)) -* **deps:** update netlify packages ([#515](https://github.com/netlify/primitives/issues/515)) ([67034cc](https://github.com/netlify/primitives/commit/67034cce9f80e35582f328b1990d0f26e7181cff)) - -## [0.3.2](https://github.com/netlify/primitives/compare/ai-v0.3.1...ai-v0.3.2) (2025-10-29) - - -### Bug Fixes - -* **deps:** update netlify packages ([#504](https://github.com/netlify/primitives/issues/504)) ([3586853](https://github.com/netlify/primitives/commit/35868533dd9f878b4162685131219419ca33bd8a)) - -## [0.3.1](https://github.com/netlify/primitives/compare/ai-v0.3.0...ai-v0.3.1) (2025-10-23) - - -### Bug Fixes - -* update AI endpoints to use api client ([#495](https://github.com/netlify/primitives/issues/495)) ([f270b1f](https://github.com/netlify/primitives/commit/f270b1fa3912bcdac30699523a582ca1de5e04ad)) - -## [0.3.0](https://github.com/netlify/primitives/compare/ai-v0.2.1...ai-v0.3.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - -## [0.2.1](https://github.com/netlify/primitives/compare/ai-v0.2.0...ai-v0.2.1) (2025-09-17) - - -### Bug Fixes - -* add repository field to @netlify/ai package.json ([#453](https://github.com/netlify/primitives/issues/453)) ([0cc1622](https://github.com/netlify/primitives/commit/0cc1622d560d56cb2c991d9daefe5233e99e1c63)) - -## [0.2.0](https://github.com/netlify/primitives/compare/ai-v0.1.0...ai-v0.2.0) (2025-09-17) - - -### Features - -* add AI gateway ([#450](https://github.com/netlify/primitives/issues/450)) ([aece659](https://github.com/netlify/primitives/commit/aece65980d8a016dffa24fa3e91ef0f0630ef5f8)) diff --git a/packages/ai/package.json b/packages/ai/package.json deleted file mode 100644 index 472a8d7..0000000 --- a/packages/ai/package.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "name": "@netlify/ai", - "version": "0.4.1", - "description": "TypeScript utilities for interacting with Netlify AI features", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json", - "./bootstrap": { - "require": { - "types": "./dist/bootstrap/main.d.cts", - "default": "./dist/bootstrap/main.cjs" - }, - "import": { - "types": "./dist/bootstrap/main.d.ts", - "default": "./dist/bootstrap/main.js" - }, - "default": { - "types": "./dist/bootstrap/main.d.ts", - "default": "./dist/bootstrap/main.js" - } - } - }, - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "test": "run-s build test:ci", - "test:dev": "run-s build test:dev:*", - "test:ci": "run-s build test:ci:*", - "test:dev:vitest": "vitest", - "test:dev:vitest:watch": "vitest watch", - "test:ci:vitest": "vitest run", - "publint": "npx -y publint --strict" - }, - "dependencies": { - "@netlify/api": "^14.0.18" - }, - "devDependencies": { - "@types/node": "20.14.15", - "npm-run-all2": "^7.0.2", - "tsup": "8.5.1", - "typescript": "5.9.3", - "vitest": "^3.0.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/ai" - }, - "homepage": "https://github.com/netlify/primitives/tree/main/packages/ai", - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - } -} diff --git a/packages/ai/src/bootstrap/main.ts b/packages/ai/src/bootstrap/main.ts deleted file mode 100644 index 3c94a6a..0000000 --- a/packages/ai/src/bootstrap/main.ts +++ /dev/null @@ -1,160 +0,0 @@ -import type { NetlifyAPI } from '@netlify/api' - -export interface AIGatewayContext { - token: string - url: string -} - -export interface AIGatewayConfig { - api: NetlifyAPI - env: Record - siteID?: string | undefined - siteURL?: string | undefined - accountID?: string | undefined - /** Whether the site has a published deploy. When false, site-scoped tokens are skipped. */ - siteHasDeploy?: boolean | undefined -} - -export interface AIProviderEnvVar { - key: string - url: string -} - -export interface AIGatewayTokenResponse { - token: string - url: string - envVars?: AIProviderEnvVar[] -} - -export const fetchAIProviders = async ({ api }: { api: NetlifyAPI }): Promise => { - try { - if (!api.accessToken) { - return [] - } - - const data = await api.getAIGatewayProviders() - - if (!data.providers) { - return [] - } - - const envVars: AIProviderEnvVar[] = [] - - for (const provider of Object.values(data.providers)) { - if (provider.token_env_var && provider.url_env_var) { - envVars.push({ - key: provider.token_env_var, - url: provider.url_env_var, - }) - } - } - - return envVars - } catch (error) { - console.warn(`Failed to fetch AI providers: ${error instanceof Error ? error.message : String(error)}`) - return [] - } -} - -export const fetchAIGatewayToken = async ({ - api, - siteId, -}: { - api: NetlifyAPI - siteId: string -}): Promise => { - try { - if (!api.accessToken) { - return null - } - - const data = await api.getAIGatewayToken({ site_id: siteId }) - - if (!data.token || !data.url) { - return null - } - - return { - token: data.token, - url: data.url, - } - } catch (error) { - console.warn( - `Failed to fetch AI Gateway token for site ${siteId}: ${error instanceof Error ? error.message : String(error)}`, - ) - return null - } -} - -export const fetchAccountAIGatewayToken = async ({ - api, - accountId, -}: { - api: NetlifyAPI - accountId: string -}): Promise => { - try { - if (!api.accessToken) { - return null - } - - const data = await api.getAccountAIGatewayToken({ account_id: accountId }) - - if (!data.token || !data.url) { - return null - } - - return { - token: data.token, - url: data.url, - } - } catch (error) { - console.warn( - `Failed to fetch AI Gateway token for account ${accountId}: ${error instanceof Error ? error.message : String(error)}`, - ) - return null - } -} - -export const setupAIGateway = async (config: AIGatewayConfig): Promise => { - const { api, env, siteID, siteURL, accountID, siteHasDeploy = true } = config - - let aiGatewayToken: AIGatewayTokenResponse | null = null - let gatewayUrl: string | null = null - - const providersPromise = fetchAIProviders({ api }) - - if (siteID && siteID !== 'unlinked' && siteURL && siteHasDeploy) { - aiGatewayToken = await fetchAIGatewayToken({ api, siteId: siteID }) - if (aiGatewayToken) gatewayUrl = `${siteURL}/.netlify/ai` - } - - if (!aiGatewayToken && accountID) { - aiGatewayToken = await fetchAccountAIGatewayToken({ api, accountId: accountID }) - if (aiGatewayToken) gatewayUrl = aiGatewayToken.url - } - - if (aiGatewayToken && gatewayUrl) { - const envVars = await providersPromise - const aiGatewayContext = JSON.stringify({ - token: aiGatewayToken.token, - url: gatewayUrl, - envVars, - }) - const base64Context = Buffer.from(aiGatewayContext).toString('base64') - env.AI_GATEWAY = { sources: ['internal'], value: base64Context } - } -} - -export const parseAIGatewayContext = (aiGatewayValue?: string): AIGatewayTokenResponse | undefined => { - try { - if (aiGatewayValue) { - const decodedContext = Buffer.from(aiGatewayValue, 'base64').toString('utf8') - const aiGatewayContext = JSON.parse(decodedContext) as AIGatewayTokenResponse - return aiGatewayContext - } - } catch { - // Ignore parsing errors - AI Gateway is optional - } - return undefined -} diff --git a/packages/ai/src/main.test.ts b/packages/ai/src/main.test.ts deleted file mode 100644 index 93725f6..0000000 --- a/packages/ai/src/main.test.ts +++ /dev/null @@ -1,470 +0,0 @@ -import { describe, test, expect, vi, beforeEach } from 'vitest' -import { - fetchAIGatewayToken, - fetchAccountAIGatewayToken, - setupAIGateway, - parseAIGatewayContext, - fetchAIProviders, -} from './bootstrap/main.js' -import type { NetlifyAPI } from '@netlify/api' - -describe('fetchAIGatewayToken', () => { - const mockGetAIGatewayToken = vi.fn() - const mockApi: NetlifyAPI = { - scheme: 'https', - host: 'api.netlify.com', - accessToken: 'test-token', - getAIGatewayToken: mockGetAIGatewayToken, - } as unknown as NetlifyAPI - - beforeEach(() => { - vi.clearAllMocks() - }) - - test('successfully fetches AI Gateway token', async () => { - const mockResponse = { - token: 'ai-gateway-token', - url: 'https://ai-gateway.com/.netlify/ai/', - } - - mockGetAIGatewayToken.mockResolvedValue(mockResponse) - - const result = await fetchAIGatewayToken({ - api: mockApi, - siteId: 'test-site-id', - }) - - expect(result).toEqual(mockResponse) - expect(mockGetAIGatewayToken).toHaveBeenCalledWith({ site_id: 'test-site-id' }) - }) - - test('returns null when no access token is provided', async () => { - const apiWithoutToken: NetlifyAPI = { - scheme: mockApi.scheme, - host: mockApi.host, - accessToken: undefined, - getAIGatewayToken: mockGetAIGatewayToken, - } as unknown as NetlifyAPI - - const result = await fetchAIGatewayToken({ - api: apiWithoutToken, - siteId: 'test-site-id', - }) - - expect(result).toBeNull() - expect(mockGetAIGatewayToken).not.toHaveBeenCalled() - }) - - test('returns null when API returns 404', async () => { - const error = new Error('Not Found') as Error & { status: number } - error.status = 404 - mockGetAIGatewayToken.mockRejectedValue(error) - - const result = await fetchAIGatewayToken({ - api: mockApi, - siteId: 'test-site-id', - }) - - expect(result).toBeNull() - }) - - test('throws error for non-404 HTTP errors', async () => { - const error = new Error('Internal Server Error') - mockGetAIGatewayToken.mockRejectedValue(error) - - const result = await fetchAIGatewayToken({ - api: mockApi, - siteId: 'test-site-id', - }) - - expect(result).toBeNull() - }) - - test('handles invalid response format', async () => { - mockGetAIGatewayToken.mockResolvedValue({ invalid: 'response' }) - - const result = await fetchAIGatewayToken({ - api: mockApi, - siteId: 'test-site-id', - }) - - expect(result).toBeNull() - }) - - test('handles network errors', async () => { - mockGetAIGatewayToken.mockRejectedValue(new Error('Network error')) - - const result = await fetchAIGatewayToken({ - api: mockApi, - siteId: 'test-site-id', - }) - - expect(result).toBeNull() - }) -}) - -describe('fetchAccountAIGatewayToken', () => { - const mockGetAccountAIGatewayToken = vi.fn() - const mockApi: NetlifyAPI = { - scheme: 'https', - host: 'api.netlify.com', - accessToken: 'test-token', - getAccountAIGatewayToken: mockGetAccountAIGatewayToken, - } as unknown as NetlifyAPI - - beforeEach(() => { - vi.clearAllMocks() - }) - - test('successfully fetches account AI Gateway token', async () => { - const mockResponse = { - token: 'ai-gateway-token', - url: 'https://ai-gateway.com/.netlify/ai/', - } - - mockGetAccountAIGatewayToken.mockResolvedValue(mockResponse) - - const result = await fetchAccountAIGatewayToken({ - api: mockApi, - accountId: 'test-account-id', - }) - - expect(result).toEqual(mockResponse) - expect(mockGetAccountAIGatewayToken).toHaveBeenCalledWith({ account_id: 'test-account-id' }) - }) - - test('returns null when no access token is provided', async () => { - const apiWithoutToken: NetlifyAPI = { - scheme: mockApi.scheme, - host: mockApi.host, - accessToken: undefined, - getAccountAIGatewayToken: mockGetAccountAIGatewayToken, - } as unknown as NetlifyAPI - - const result = await fetchAccountAIGatewayToken({ - api: apiWithoutToken, - accountId: 'test-account-id', - }) - - expect(result).toBeNull() - expect(mockGetAccountAIGatewayToken).not.toHaveBeenCalled() - }) - - test('returns null when API returns 404', async () => { - const error = new Error('Not Found') as Error & { status: number } - error.status = 404 - mockGetAccountAIGatewayToken.mockRejectedValue(error) - - const result = await fetchAccountAIGatewayToken({ - api: mockApi, - accountId: 'test-account-id', - }) - - expect(result).toBeNull() - }) - - test('throws error for non-404 HTTP errors', async () => { - const error = new Error('Internal Server Error') - mockGetAccountAIGatewayToken.mockRejectedValue(error) - - const result = await fetchAccountAIGatewayToken({ - api: mockApi, - accountId: 'test-account-id', - }) - - expect(result).toBeNull() - }) - - test('handles invalid response format', async () => { - mockGetAccountAIGatewayToken.mockResolvedValue({ invalid: 'response' }) - - const result = await fetchAccountAIGatewayToken({ - api: mockApi, - accountId: 'test-account-id', - }) - - expect(result).toBeNull() - }) - - test('handles network errors', async () => { - mockGetAccountAIGatewayToken.mockRejectedValue(new Error('Network error')) - - const result = await fetchAccountAIGatewayToken({ - api: mockApi, - accountId: 'test-account-id', - }) - - expect(result).toBeNull() - }) -}) - -describe('fetchAIProviders', () => { - const mockGetAIGatewayProviders = vi.fn() - const mockApi: NetlifyAPI = { - scheme: 'https', - host: 'api.netlify.com', - accessToken: 'test-token', - getAIGatewayProviders: mockGetAIGatewayProviders, - } as unknown as NetlifyAPI - - beforeEach(() => { - vi.clearAllMocks() - }) - - test('successfully fetches AI providers and transforms to env vars', async () => { - const mockProvidersResponse = { - providers: { - anthropic: { - token_env_var: 'ANTHROPIC_API_KEY', - url_env_var: 'ANTHROPIC_BASE_URL', - models: ['claude-3-haiku-20240307'], - }, - openai: { - token_env_var: 'OPENAI_API_KEY', - url_env_var: 'OPENAI_BASE_URL', - models: ['gpt-4'], - }, - gemini: { - token_env_var: 'GEMINI_API_KEY', - url_env_var: 'GOOGLE_GEMINI_BASE_URL', - models: ['gemini-pro'], - }, - }, - } - - mockGetAIGatewayProviders.mockResolvedValue(mockProvidersResponse) - - const result = await fetchAIProviders({ api: mockApi }) - - expect(result).toEqual([ - { key: 'ANTHROPIC_API_KEY', url: 'ANTHROPIC_BASE_URL' }, - { key: 'OPENAI_API_KEY', url: 'OPENAI_BASE_URL' }, - { key: 'GEMINI_API_KEY', url: 'GOOGLE_GEMINI_BASE_URL' }, - ]) - expect(mockGetAIGatewayProviders).toHaveBeenCalled() - }) - - test('returns empty array when no access token is provided', async () => { - const apiWithoutToken: NetlifyAPI = { - scheme: mockApi.scheme, - host: mockApi.host, - accessToken: undefined, - getAIGatewayProviders: mockGetAIGatewayProviders, - } as unknown as NetlifyAPI - - const result = await fetchAIProviders({ api: apiWithoutToken }) - - expect(result).toEqual([]) - expect(mockGetAIGatewayProviders).not.toHaveBeenCalled() - }) - - test('returns empty array when API returns 404', async () => { - const error = new Error('Not Found') as Error & { status: number } - error.status = 404 - mockGetAIGatewayProviders.mockRejectedValue(error) - - const result = await fetchAIProviders({ api: mockApi }) - - expect(result).toEqual([]) - }) - - test('returns empty array for other HTTP errors', async () => { - const error = new Error('Internal Server Error') - mockGetAIGatewayProviders.mockRejectedValue(error) - - const result = await fetchAIProviders({ api: mockApi }) - - expect(result).toEqual([]) - }) - - test('handles invalid response format', async () => { - mockGetAIGatewayProviders.mockResolvedValue({ invalid: 'response' }) - - const result = await fetchAIProviders({ api: mockApi }) - - expect(result).toEqual([]) - }) - - test('handles network errors', async () => { - mockGetAIGatewayProviders.mockRejectedValue(new Error('Network error')) - - const result = await fetchAIProviders({ api: mockApi }) - - expect(result).toEqual([]) - }) -}) - -describe('setupAIGateway', () => { - const mockGetAIGatewayToken = vi.fn() - const mockGetAccountAIGatewayToken = vi.fn() - const mockGetAIGatewayProviders = vi.fn() - const mockApi: NetlifyAPI = { - scheme: 'https', - host: 'api.netlify.com', - accessToken: 'test-token', - getAIGatewayToken: mockGetAIGatewayToken, - getAccountAIGatewayToken: mockGetAccountAIGatewayToken, - getAIGatewayProviders: mockGetAIGatewayProviders, - } as unknown as NetlifyAPI - - beforeEach(() => { - vi.clearAllMocks() - }) - - test('sets up AI Gateway when conditions are met', async () => { - const mockTokenResponse = { - token: 'ai-gateway-token', - url: 'https://ai-gateway.com/.netlify/ai', - } - - const mockProvidersResponse = { - providers: { - openai: { - token_env_var: 'OPENAI_API_KEY', - url_env_var: 'OPENAI_BASE_URL', - models: ['gpt-4'], - }, - }, - } - - mockGetAIGatewayToken.mockResolvedValue(mockTokenResponse) - mockGetAIGatewayProviders.mockResolvedValue(mockProvidersResponse) - - const env = {} - const config = { - api: mockApi, - env, - siteID: 'test-site', - siteURL: 'https://example.com', - } - - await setupAIGateway(config) - - expect(env).toHaveProperty('AI_GATEWAY') - expect((env as { AI_GATEWAY: { sources: string[] } }).AI_GATEWAY.sources).toEqual(['internal']) - - const base64Value = (env as { AI_GATEWAY: { value: string } }).AI_GATEWAY.value - const decodedContext = JSON.parse(Buffer.from(base64Value, 'base64').toString('utf8')) - expect(decodedContext).toEqual({ - token: 'ai-gateway-token', - url: 'https://example.com/.netlify/ai', - envVars: [{ key: 'OPENAI_API_KEY', url: 'OPENAI_BASE_URL' }], - }) - }) - - test('skips setup when site is unlinked', async () => { - const env = {} - const config = { - api: mockApi, - env, - siteID: 'unlinked', - siteURL: 'https://example.com', - } - - await setupAIGateway(config) - - expect(env).not.toHaveProperty('AI_GATEWAY') - }) - - test('skips setup when no siteURL', async () => { - const env = {} - const config = { - api: mockApi, - env, - siteID: 'test-site', - siteURL: undefined, - } - - await setupAIGateway(config) - - expect(env).not.toHaveProperty('AI_GATEWAY') - }) - - test('falls back to account-scoped token when site token unavailable', async () => { - const mockAccountTokenResponse = { - token: 'account-gateway-token', - url: 'https://ai-gateway.com/.netlify/ai', - } - const mockProvidersResponse = { - providers: { - openai: { - token_env_var: 'OPENAI_API_KEY', - url_env_var: 'OPENAI_BASE_URL', - models: ['gpt-4'], - }, - }, - } - - mockGetAIGatewayToken.mockResolvedValue(null) - mockGetAccountAIGatewayToken.mockResolvedValue(mockAccountTokenResponse) - mockGetAIGatewayProviders.mockResolvedValue(mockProvidersResponse) - - const env = {} - await setupAIGateway({ - api: mockApi, - env, - siteID: 'test-site', - siteURL: 'https://example.com', - accountID: 'test-account-id', - siteHasDeploy: false, - }) - - expect(env).toHaveProperty('AI_GATEWAY') - const base64Value = (env as { AI_GATEWAY: { value: string } }).AI_GATEWAY.value - const decodedContext = JSON.parse(Buffer.from(base64Value, 'base64').toString('utf8')) - expect(decodedContext).toEqual({ - token: 'account-gateway-token', - url: 'https://ai-gateway.com/.netlify/ai', - envVars: [{ key: 'OPENAI_API_KEY', url: 'OPENAI_BASE_URL' }], - }) - expect(mockGetAIGatewayToken).not.toHaveBeenCalled() - expect(mockGetAccountAIGatewayToken).toHaveBeenCalledWith({ account_id: 'test-account-id' }) - }) -}) - -describe('parseAIGatewayContext', () => { - test('parses valid AI Gateway context', () => { - const contextData = { token: 'test-token', url: 'https://example.com/.netlify/ai' } - const base64Data = Buffer.from(JSON.stringify(contextData)).toString('base64') - - const result = parseAIGatewayContext(base64Data) - - expect(result).toEqual(contextData) - }) - - test('parses AI Gateway context with envVars', () => { - const contextData = { - token: 'test-token', - url: 'https://example.com/.netlify/ai', - envVars: [ - { key: 'OPENAI_API_KEY', url: 'OPENAI_BASE_URL' }, - { key: 'ANTHROPIC_API_KEY', url: 'ANTHROPIC_BASE_URL' }, - ], - } - const base64Data = Buffer.from(JSON.stringify(contextData)).toString('base64') - - const result = parseAIGatewayContext(base64Data) - - expect(result).toEqual(contextData) - }) - - test('returns undefined when no value provided', () => { - const result = parseAIGatewayContext() - - expect(result).toBeUndefined() - }) - - test('returns undefined when value is invalid base64', () => { - const result = parseAIGatewayContext('invalid-base64') - - expect(result).toBeUndefined() - }) - - test('returns undefined when value contains invalid JSON', () => { - const invalidBase64 = Buffer.from('invalid-json').toString('base64') - - const result = parseAIGatewayContext(invalidBase64) - - expect(result).toBeUndefined() - }) -}) diff --git a/packages/ai/src/main.ts b/packages/ai/src/main.ts deleted file mode 100644 index d3157b4..0000000 --- a/packages/ai/src/main.ts +++ /dev/null @@ -1 +0,0 @@ -// Future user-facing AI utilities will be exported from here diff --git a/packages/ai/tsconfig.json b/packages/ai/tsconfig.json deleted file mode 100644 index 5e65f52..0000000 --- a/packages/ai/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "allowImportingTsExtensions": true, - "emitDeclarationOnly": true, - "target": "ES2022", - "module": "es2022", - "allowJs": true, - "declaration": true, - "declarationMap": false, - "sourceMap": false, - "outDir": "./dist", - "removeComments": false, - "strict": true, - "moduleResolution": "node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/ai/tsup.config.ts b/packages/ai/tsup.config.ts deleted file mode 100644 index 4a1ceab..0000000 --- a/packages/ai/tsup.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'tsup' - -export default defineConfig({ - entry: ['src/main.ts', 'src/bootstrap/main.ts'], - format: ['esm', 'cjs'], - dts: true, - splitting: false, - sourcemap: true, - clean: true, - tsconfig: 'tsconfig.json', -}) diff --git a/packages/ai/vitest.config.ts b/packages/ai/vitest.config.ts deleted file mode 100644 index eff32b2..0000000 --- a/packages/ai/vitest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - }, -}) diff --git a/packages/aws-lambda-compat/.gitignore b/packages/aws-lambda-compat/.gitignore deleted file mode 100644 index de4d1f0..0000000 --- a/packages/aws-lambda-compat/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules diff --git a/packages/aws-lambda-compat/CHANGELOG.md b/packages/aws-lambda-compat/CHANGELOG.md deleted file mode 100644 index 4ec47c6..0000000 --- a/packages/aws-lambda-compat/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# Changelog - -## [1.0.2](https://github.com/netlify/primitives/compare/aws-lambda-compat-v1.0.1...aws-lambda-compat-v1.0.2) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.7.0 to 2.8.0 - -## [1.0.1](https://github.com/netlify/primitives/compare/aws-lambda-compat-v1.0.0...aws-lambda-compat-v1.0.1) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.6.0 to 2.7.0 - -## 1.0.0 (2026-04-07) - - -### Features - -* add `aws-lambda-compat` package ([#635](https://github.com/netlify/primitives/issues/635)) ([1160e89](https://github.com/netlify/primitives/commit/1160e894fb542cae45ec9b82356b7144bb1029ef)) -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) diff --git a/packages/aws-lambda-compat/README.md b/packages/aws-lambda-compat/README.md deleted file mode 100644 index 73c324f..0000000 --- a/packages/aws-lambda-compat/README.md +++ /dev/null @@ -1,60 +0,0 @@ -[![Build](https://github.com/netlify/primitives/workflows/Build/badge.svg)](https://github.com/netlify/primitives/actions) -[![Node](https://img.shields.io/node/v/@netlify/aws-lambda-compat.svg?logo=node.js)](https://www.npmjs.com/package/@netlify/aws-lambda-compat) - -# @netlify/aws-lambda-compat - -AWS Lambda compatibility wrapper for Netlify Functions. Lets you author Netlify Functions using the AWS Lambda handler -signature. - -## Installation - -```shell -npm install @netlify/aws-lambda-compat -``` - -## Usage - -Wrap your Lambda-style handler with `withLambda` and export the result as your Netlify Function: - -```ts -import { withLambda } from '@netlify/aws-lambda-compat' -import type { HandlerEvent, HandlerContext, HandlerResponse } from '@netlify/aws-lambda-compat' - -export default withLambda(async (event: HandlerEvent, context: HandlerContext): Promise => { - const name = event.queryStringParameters?.name ?? 'World' - - return { - statusCode: 200, - headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ message: `Hello, ${name}!` }), - } -}) -``` - -## How it works - -`withLambda` converts between the two function signatures: - -1. Incoming `Request` is converted to a Lambda `HandlerEvent` (URL, headers, query string, body with automatic base64 - encoding for binary payloads) -2. The Netlify `Context` is mapped to a `HandlerContext` with sensible defaults for AWS-specific fields -3. The `HandlerResponse` returned by your handler is converted back to a web-standard `Response` - -## TypeScript types - -The package exports the following AWS Lambda-compatible types: - -- `Handler` -- `HandlerCallback` -- `HandlerContext` -- `HandlerEvent` -- `HandlerResponse` - -Additionally, the package exports: - -- `LambdaHandler` — the type of the handler function passed to `withLambda` - -## Contributors - -Please see [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on how to set up and work on this repository. -Thanks for contributing! diff --git a/packages/aws-lambda-compat/package.json b/packages/aws-lambda-compat/package.json deleted file mode 100644 index fe6bd2f..0000000 --- a/packages/aws-lambda-compat/package.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "@netlify/aws-lambda-compat", - "version": "1.0.2", - "description": "AWS Lambda compatibility wrapper for Netlify Functions", - "type": "module", - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - } - }, - "files": [ - "dist/**/*.js", - "dist/**/*.cjs", - "dist/**/*.mjs", - "dist/**/*.d.ts", - "dist/**/*.d.cts", - "dist/**/*.d.mts" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "test": "run-s test:ci", - "test:ci": "run-s test:ci:*", - "test:ci:vitest": "npm run build && vitest run" - }, - "keywords": [ - "netlify", - "aws", - "lambda", - "functions", - "compatibility" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/aws-lambda-compat" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "npm-run-all2": "^5.0.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, - "engines": { - "node": ">=20.6.1" - } -} diff --git a/packages/aws-lambda-compat/src/lib/handler.ts b/packages/aws-lambda-compat/src/lib/handler.ts deleted file mode 100644 index d503653..0000000 --- a/packages/aws-lambda-compat/src/lib/handler.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { HandlerContext } from './handler_context.js' -import type { HandlerEvent } from './handler_event.js' -import type { HandlerResponse } from './handler_response.js' - -export type HandlerCallback = ( - error: unknown, - response: ResponseType, -) => void - -export type Handler = ( - event: HandlerEvent, - context: HandlerContext, - callback?: HandlerCallback, -) => undefined | Promise diff --git a/packages/aws-lambda-compat/src/lib/handler_context.ts b/packages/aws-lambda-compat/src/lib/handler_context.ts deleted file mode 100644 index 69799b2..0000000 --- a/packages/aws-lambda-compat/src/lib/handler_context.ts +++ /dev/null @@ -1,24 +0,0 @@ -// From https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html. -export interface HandlerContext { - callbackWaitsForEmptyEventLoop: boolean - functionName: string - functionVersion: string - invokedFunctionArn: string - memoryLimitInMB: string - awsRequestId: string - logGroupName: string - logStreamName: string - identity?: Record - clientContext?: Record - - getRemainingTimeInMillis(): number - - /** @deprecated Use handler callback or promise result */ - done(error?: Error, result?: unknown): void - /** @deprecated Use handler callback with first argument or reject a promise result */ - fail(error: Error | string): void - /** @deprecated Use handler callback with second argument or resolve a promise result */ - succeed(messageOrObject: unknown): void - /** @deprecated Use handler callback or promise result */ - succeed(message: string, object: unknown): void -} diff --git a/packages/aws-lambda-compat/src/lib/handler_event.ts b/packages/aws-lambda-compat/src/lib/handler_event.ts deleted file mode 100644 index 63a3067..0000000 --- a/packages/aws-lambda-compat/src/lib/handler_event.ts +++ /dev/null @@ -1,21 +0,0 @@ -type EventHeaders = Record - -type EventMultiValueHeaders = Record - -type EventQueryStringParameters = Record - -type EventMultiValueQueryStringParameters = Record - -export interface HandlerEvent { - rawUrl: string - rawQuery: string - path: string - httpMethod: string - headers: EventHeaders - multiValueHeaders: EventMultiValueHeaders - queryStringParameters: EventQueryStringParameters | null - multiValueQueryStringParameters: EventMultiValueQueryStringParameters | null - body: string | null - isBase64Encoded: boolean - route?: string -} diff --git a/packages/aws-lambda-compat/src/lib/handler_response.ts b/packages/aws-lambda-compat/src/lib/handler_response.ts deleted file mode 100644 index a1403c8..0000000 --- a/packages/aws-lambda-compat/src/lib/handler_response.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface HandlerResponse { - statusCode: number - headers?: Record - multiValueHeaders?: Record - body?: string - isBase64Encoded?: boolean -} diff --git a/packages/aws-lambda-compat/src/lib/request_to_event.ts b/packages/aws-lambda-compat/src/lib/request_to_event.ts deleted file mode 100644 index c599b3f..0000000 --- a/packages/aws-lambda-compat/src/lib/request_to_event.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { HandlerContext } from './handler_context.js' -import type { HandlerEvent } from './handler_event.js' - -const textContentTypes = new Set([ - 'application/csp-report', - 'application/graphql', - 'application/json', - 'application/javascript', - 'application/x-www-form-urlencoded', - 'application/x-ndjson', - 'application/xml', -]) - -function shouldBase64Encode(contentType: string): boolean { - if (!contentType) { - return true - } - - const [contentTypeSegment] = contentType.split(';') - const normalized = contentTypeSegment.toLowerCase() - - if (normalized.startsWith('text/')) { - return false - } - - if (normalized.endsWith('+json') || normalized.endsWith('+xml')) { - return false - } - - if (textContentTypes.has(normalized)) { - return false - } - - return true -} - -export async function buildEventFromRequest(request: Request): Promise { - const url = new URL(request.url) - const queryStringParameters: Record = {} - const multiValueQueryStringParameters: Record = {} - - url.searchParams.forEach((value, key) => { - queryStringParameters[key] = value - multiValueQueryStringParameters[key] = [...(multiValueQueryStringParameters[key] ?? []), value] - }) - - const headers: Record = {} - const multiValueHeaders: Record = {} - - request.headers.forEach((value, key) => { - headers[key] = value - multiValueHeaders[key] = value.split(',').map((v) => v.trim()) - }) - - const contentType = request.headers.get('content-type') ?? '' - const isBinary = shouldBase64Encode(contentType) - - let body: string | null = null - let isBase64Encoded = false - - if (request.body) { - if (isBinary) { - const buffer = await request.arrayBuffer() - const bytes = new Uint8Array(buffer) - let binaryString = '' - - for (const byte of bytes) { - binaryString += String.fromCharCode(byte) - } - - body = btoa(binaryString) - isBase64Encoded = true - } else { - body = await request.text() - isBase64Encoded = false - } - } - - return { - rawUrl: url.toString(), - rawQuery: url.search.replace(/^\?/, ''), - path: url.pathname, - httpMethod: request.method, - headers, - multiValueHeaders, - queryStringParameters: Object.keys(queryStringParameters).length > 0 ? queryStringParameters : null, - multiValueQueryStringParameters: - Object.keys(multiValueQueryStringParameters).length > 0 ? multiValueQueryStringParameters : null, - body, - isBase64Encoded, - } -} - -export function buildLambdaContext(context: { requestId: string }): HandlerContext { - return { - awsRequestId: context.requestId, - callbackWaitsForEmptyEventLoop: true, - functionName: '', - functionVersion: '', - invokedFunctionArn: '', - memoryLimitInMB: '', - logGroupName: '', - logStreamName: '', - getRemainingTimeInMillis: () => 0, - done: () => { - throw new Error('context.done() is not supported in Netlify Functions') - }, - fail: () => { - throw new Error('context.fail() is not supported in Netlify Functions') - }, - succeed: () => { - throw new Error('context.succeed() is not supported in Netlify Functions') - }, - } -} diff --git a/packages/aws-lambda-compat/src/lib/response_from_handler.ts b/packages/aws-lambda-compat/src/lib/response_from_handler.ts deleted file mode 100644 index 7400f3b..0000000 --- a/packages/aws-lambda-compat/src/lib/response_from_handler.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { HandlerResponse } from './handler_response.js' - -export function buildResponseFromResult(result: HandlerResponse): Response { - const headers = new Headers() - - if (result.headers) { - for (const [name, value] of Object.entries(result.headers)) { - headers.set(name.toLowerCase(), value.toString()) - } - } - - if (result.multiValueHeaders) { - for (const [name, values] of Object.entries(result.multiValueHeaders)) { - for (const value of values) { - headers.append(name.toLowerCase(), value.toString()) - } - } - } - - let body: BodyInit | null = null - - if (result.body != null) { - if (result.isBase64Encoded) { - const binaryString = atob(result.body) - const bytes = new Uint8Array(binaryString.length) - - for (let i = 0; i < binaryString.length; i++) { - bytes[i] = binaryString.charCodeAt(i) - } - - body = bytes - } else { - body = result.body - } - } - - return new Response(body, { - status: result.statusCode, - headers, - }) -} diff --git a/packages/aws-lambda-compat/src/main.test.ts b/packages/aws-lambda-compat/src/main.test.ts deleted file mode 100644 index d89a578..0000000 --- a/packages/aws-lambda-compat/src/main.test.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import type { Context } from '@netlify/types' - -import type { HandlerEvent, HandlerContext } from './main.js' - -import { buildLambdaContext } from './lib/request_to_event.js' -import { withLambda } from './main.js' - -const createNetlifyContext = (overrides: Partial = {}): Context => - ({ - requestId: 'test-request-id', - account: { id: 'test-account' }, - cookies: {}, - deploy: { context: 'dev', id: 'deploy-id', published: false }, - geo: {}, - ip: '127.0.0.1', - json: () => new Response(), - log: () => {}, - next: () => Promise.resolve(new Response()), - params: {}, - rewrite: () => Promise.resolve(new Response()), - server: {}, - site: {}, - url: new URL('http://localhost'), - waitUntil: () => {}, - ...overrides, - }) as Context - -describe('withLambda', () => { - test('basic GET request', async () => { - const handler = withLambda((event: HandlerEvent) => ({ - statusCode: 200, - body: JSON.stringify({ method: event.httpMethod, path: event.path }), - })) - - const request = new Request('https://example.com/hello') - const response = await handler(request, createNetlifyContext()) - - expect(response.status).toBe(200) - const body = (await response.json()) as { method: string; path: string } - expect(body.method).toBe('GET') - expect(body.path).toBe('/hello') - }) - - test('GET request populates rawUrl and headers', async () => { - let capturedEvent: HandlerEvent | undefined - - const handler = withLambda((event: HandlerEvent) => { - capturedEvent = event - - return { statusCode: 200, body: '' } - }) - - const request = new Request('https://example.com/test?foo=bar', { - headers: { 'x-custom': 'value' }, - }) - await handler(request, createNetlifyContext()) - - expect(capturedEvent).toBeDefined() - expect(capturedEvent?.rawUrl).toBe('https://example.com/test?foo=bar') - expect(capturedEvent?.headers['x-custom']).toBe('value') - }) - - test('POST with text body', async () => { - let capturedEvent: HandlerEvent | undefined - - const handler = withLambda((event: HandlerEvent) => { - capturedEvent = event - - return { statusCode: 200, body: '' } - }) - - const request = new Request('https://example.com/submit', { - method: 'POST', - headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ name: 'test' }), - }) - await handler(request, createNetlifyContext()) - - expect(capturedEvent).toBeDefined() - expect(capturedEvent?.body).toBe('{"name":"test"}') - expect(capturedEvent?.isBase64Encoded).toBe(false) - expect(capturedEvent?.httpMethod).toBe('POST') - }) - - test('POST with binary body', async () => { - let capturedEvent: HandlerEvent | undefined - - const handler = withLambda((event: HandlerEvent) => { - capturedEvent = event - - return { statusCode: 200, body: '' } - }) - - const binaryData = new Uint8Array([0x89, 0x50, 0x4e, 0x47]) - const request = new Request('https://example.com/upload', { - method: 'POST', - headers: { 'content-type': 'image/png' }, - body: binaryData, - }) - await handler(request, createNetlifyContext()) - - expect(capturedEvent).toBeDefined() - expect(capturedEvent?.isBase64Encoded).toBe(true) - expect(capturedEvent?.body).toBe(btoa(String.fromCharCode(0x89, 0x50, 0x4e, 0x47))) - }) - - test('query parameters', async () => { - let capturedEvent: HandlerEvent | undefined - - const handler = withLambda((event: HandlerEvent) => { - capturedEvent = event - - return { statusCode: 200, body: '' } - }) - - const request = new Request('https://example.com/search?color=red&color=blue&size=large') - await handler(request, createNetlifyContext()) - - expect(capturedEvent).toBeDefined() - expect(capturedEvent?.queryStringParameters).toEqual({ - color: 'blue', - size: 'large', - }) - expect(capturedEvent?.multiValueQueryStringParameters).toEqual({ - color: ['red', 'blue'], - size: ['large'], - }) - expect(capturedEvent?.rawQuery).toBe('color=red&color=blue&size=large') - }) - - test('response headers from headers and multiValueHeaders', async () => { - const handler = withLambda(() => ({ - statusCode: 200, - headers: { 'x-single': 'one' }, - multiValueHeaders: { 'set-cookie': ['a=1', 'b=2'] }, - body: 'ok', - })) - - const request = new Request('https://example.com/') - const response = await handler(request, createNetlifyContext()) - - expect(response.headers.get('x-single')).toBe('one') - expect(response.headers.getSetCookie()).toEqual(['a=1', 'b=2']) - }) - - test('base64 encoded response body', async () => { - const originalBytes = new Uint8Array([72, 101, 108, 108, 111]) - const base64Body = btoa(String.fromCharCode(...originalBytes)) - - const handler = withLambda(() => ({ - statusCode: 200, - body: base64Body, - isBase64Encoded: true, - })) - - const request = new Request('https://example.com/') - const response = await handler(request, createNetlifyContext()) - - const buffer = await response.arrayBuffer() - const resultBytes = new Uint8Array(buffer) - expect(resultBytes).toEqual(originalBytes) - }) - - test('context mapping', async () => { - let capturedContext: HandlerContext | undefined - - const handler = withLambda((_event: HandlerEvent, context: HandlerContext) => { - capturedContext = context - - return { statusCode: 200, body: '' } - }) - - const request = new Request('https://example.com/') - await handler(request, createNetlifyContext({ requestId: 'my-request-123' })) - - expect(capturedContext).toBeDefined() - expect(capturedContext?.awsRequestId).toBe('my-request-123') - expect(capturedContext?.callbackWaitsForEmptyEventLoop).toBe(true) - expect(capturedContext?.functionName).toBe('') - expect(capturedContext?.getRemainingTimeInMillis()).toBe(0) - }) - - test('context deprecated methods throw', () => { - const ctx = buildLambdaContext({ requestId: 'test' }) - - /* eslint-disable @typescript-eslint/no-deprecated */ - expect(() => { - ctx.done() - }).toThrow('not supported') - expect(() => { - ctx.fail('err') - }).toThrow('not supported') - expect(() => { - ctx.succeed('ok') - }).toThrow('not supported') - /* eslint-enable @typescript-eslint/no-deprecated */ - }) - - test('null body for GET requests', async () => { - let capturedEvent: HandlerEvent | undefined - - const handler = withLambda((event: HandlerEvent) => { - capturedEvent = event - - return { statusCode: 200, body: '' } - }) - - const request = new Request('https://example.com/') - await handler(request, createNetlifyContext()) - - expect(capturedEvent).toBeDefined() - expect(capturedEvent?.body).toBeNull() - }) - - test('response with no body', async () => { - const handler = withLambda(() => ({ - statusCode: 204, - })) - - const request = new Request('https://example.com/') - const response = await handler(request, createNetlifyContext()) - - expect(response.status).toBe(204) - expect(response.body).toBeNull() - }) - - test('empty query string results in null parameters', async () => { - let capturedEvent: HandlerEvent | undefined - - const handler = withLambda((event: HandlerEvent) => { - capturedEvent = event - - return { statusCode: 200, body: '' } - }) - - const request = new Request('https://example.com/path') - await handler(request, createNetlifyContext()) - - expect(capturedEvent).toBeDefined() - expect(capturedEvent?.queryStringParameters).toBeNull() - expect(capturedEvent?.multiValueQueryStringParameters).toBeNull() - expect(capturedEvent?.rawQuery).toBe('') - }) -}) diff --git a/packages/aws-lambda-compat/src/main.ts b/packages/aws-lambda-compat/src/main.ts deleted file mode 100644 index 4e229a5..0000000 --- a/packages/aws-lambda-compat/src/main.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Context } from '@netlify/types' - -import type { HandlerContext } from './lib/handler_context.js' -import type { HandlerEvent } from './lib/handler_event.js' -import type { HandlerResponse } from './lib/handler_response.js' -import { buildEventFromRequest, buildLambdaContext } from './lib/request_to_event.js' -import { buildResponseFromResult } from './lib/response_from_handler.js' - -type LambdaHandler = (event: HandlerEvent, context: HandlerContext) => Promise | HandlerResponse - -export function withLambda(handler: LambdaHandler) { - return async (request: Request, context: Context): Promise => { - const event = await buildEventFromRequest(request) - const lambdaContext = buildLambdaContext(context) - const result = await handler(event, lambdaContext) - - return buildResponseFromResult(result) - } -} - -export type { LambdaHandler } -export type { Handler, HandlerCallback } from './lib/handler.js' -export type { HandlerContext } from './lib/handler_context.js' -export type { HandlerEvent } from './lib/handler_event.js' -export type { HandlerResponse } from './lib/handler_response.js' diff --git a/packages/aws-lambda-compat/tsconfig.json b/packages/aws-lambda-compat/tsconfig.json deleted file mode 100644 index c8b61a2..0000000 --- a/packages/aws-lambda-compat/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "node", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/aws-lambda-compat/tsup.config.ts b/packages/aws-lambda-compat/tsup.config.ts deleted file mode 100644 index 73244c3..0000000 --- a/packages/aws-lambda-compat/tsup.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - format: ['cjs', 'esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, -}) diff --git a/packages/blobs/.gitattributes b/packages/blobs/.gitattributes deleted file mode 100644 index 6313b56..0000000 --- a/packages/blobs/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto eol=lf diff --git a/packages/blobs/.gitignore b/packages/blobs/.gitignore deleted file mode 100644 index 6a5f751..0000000 --- a/packages/blobs/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -*~ -*.swp -npm-debug.log -node_modules -/core -.eslintcache -.npmrc -.yarn-error.log -/coverage -/build -.vscode -/dist diff --git a/packages/blobs/CHANGELOG.md b/packages/blobs/CHANGELOG.md deleted file mode 100644 index cb5a909..0000000 --- a/packages/blobs/CHANGELOG.md +++ /dev/null @@ -1,856 +0,0 @@ -# Changelog - -## [10.7.9](https://github.com/netlify/primitives/compare/blobs-v10.7.8...blobs-v10.7.9) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.5 to 4.4.6 - * @netlify/otel bumped from ^6.0.2 to ^6.0.3 - -## [10.7.8](https://github.com/netlify/primitives/compare/blobs-v10.7.7...blobs-v10.7.8) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.4 to 4.4.5 - * @netlify/otel bumped from ^6.0.1 to ^6.0.2 - -## [10.7.7](https://github.com/netlify/primitives/compare/blobs-v10.7.6...blobs-v10.7.7) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.3 to 4.4.4 - * @netlify/otel bumped from ^6.0.0 to ^6.0.1 - -## [10.7.6](https://github.com/netlify/primitives/compare/blobs-v10.7.5...blobs-v10.7.6) (2026-05-12) - - -### Bug Fixes - -* update readme badges to point to current repo ([#594](https://github.com/netlify/primitives/issues/594)) ([0e05d46](https://github.com/netlify/primitives/commit/0e05d46b645b66d20d01e824fe5b82a121b491a2)) - -## [10.7.5](https://github.com/netlify/primitives/compare/blobs-v10.7.4...blobs-v10.7.5) (2026-05-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/otel bumped from ^5.1.5 to ^6.0.0 - -## [10.7.4](https://github.com/netlify/primitives/compare/blobs-v10.7.3...blobs-v10.7.4) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.2 to 4.4.3 - * @netlify/otel bumped from ^5.1.4 to ^5.1.5 - -## [10.7.3](https://github.com/netlify/primitives/compare/blobs-v10.7.2...blobs-v10.7.3) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.1 to 4.4.2 - * @netlify/otel bumped from ^5.1.3 to ^5.1.4 - -## [10.7.2](https://github.com/netlify/primitives/compare/blobs-v10.7.1...blobs-v10.7.2) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.0 to 4.4.1 - * @netlify/otel bumped from ^5.1.2 to ^5.1.3 - -## [10.7.1](https://github.com/netlify/primitives/compare/blobs-v10.7.0...blobs-v10.7.1) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.3 to 4.4.0 - * @netlify/otel bumped from ^5.1.1 to ^5.1.2 - -## [10.7.0](https://github.com/netlify/primitives/compare/blobs-v10.6.0...blobs-v10.7.0) (2026-02-16) - - -### Features - -* add `db` package ([#581](https://github.com/netlify/primitives/issues/581)) ([b60a313](https://github.com/netlify/primitives/commit/b60a313bd9ba19fd5deced4736012c3d7c7fe842)) - -## [10.6.0](https://github.com/netlify/primitives/compare/blobs-v10.5.0...blobs-v10.6.0) (2026-02-06) - - -### Features - -* move `getEnvironment` to `runtime-utils` ([#579](https://github.com/netlify/primitives/issues/579)) ([639ba5f](https://github.com/netlify/primitives/commit/639ba5f5d5659bcf96894dc627a87af42c8fc19f)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.2.1 to 2.3.0 - -## [10.5.0](https://github.com/netlify/primitives/compare/blobs-v10.4.4...blobs-v10.5.0) (2025-12-17) - - -### Features - -* add overload to `getStore` and `getDeployStore` ([#567](https://github.com/netlify/primitives/issues/567)) ([c3fba21](https://github.com/netlify/primitives/commit/c3fba211f99b8e072d902e823e87325a7aa7af92)) - -## [10.4.4](https://github.com/netlify/primitives/compare/blobs-v10.4.3...blobs-v10.4.4) (2025-12-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/otel bumped from ^5.1.0 to ^5.1.1 - -## [10.4.3](https://github.com/netlify/primitives/compare/blobs-v10.4.2...blobs-v10.4.3) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.2 to 4.3.3 - * @netlify/otel bumped from ^5.0.1 to ^5.1.0 - -## [10.4.2](https://github.com/netlify/primitives/compare/blobs-v10.4.1...blobs-v10.4.2) (2025-12-03) - - -### Bug Fixes - -* allow active spans to be passed in as an option ([#544](https://github.com/netlify/primitives/issues/544)) ([ba74c4a](https://github.com/netlify/primitives/commit/ba74c4ab5fa2ab97e216ff59f2e1a8eff0405d4c)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/otel bumped from ^5.0.0 to ^5.0.1 - -## [10.4.1](https://github.com/netlify/primitives/compare/blobs-v10.4.0...blobs-v10.4.1) (2025-11-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/otel bumped from ^4.3.2 to ^5.0.0 - -## [10.4.0](https://github.com/netlify/primitives/compare/blobs-v10.3.3...blobs-v10.4.0) (2025-11-14) - - -### Features - -* delete Blobs stores in batches ([#532](https://github.com/netlify/primitives/issues/532)) ([640b529](https://github.com/netlify/primitives/commit/640b529bbf9ff42e6eecd70412ea2f6dc1678ccd)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.1 to 4.3.2 - -## [10.3.3](https://github.com/netlify/primitives/compare/blobs-v10.3.2...blobs-v10.3.3) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.0 to 4.3.1 - -## [10.3.2](https://github.com/netlify/primitives/compare/blobs-v10.3.1...blobs-v10.3.2) (2025-11-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.2.0 to 2.2.1 - -## [10.3.1](https://github.com/netlify/primitives/compare/blobs-v10.3.0...blobs-v10.3.1) (2025-10-29) - - -### Bug Fixes - -* instrument content-length in .get and .getWithMetadata ([#507](https://github.com/netlify/primitives/issues/507)) ([a2424f4](https://github.com/netlify/primitives/commit/a2424f49147c156d57120d773bf69ff3a0ab6447)) - -## [10.3.0](https://github.com/netlify/primitives/compare/blobs-v10.2.1...blobs-v10.3.0) (2025-10-27) - - -### Features - -* add `deleteAll` method to Blobs ([#503](https://github.com/netlify/primitives/issues/503)) ([6ad0891](https://github.com/netlify/primitives/commit/6ad0891e84b87b5e659655de786a109dfac64198)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/otel bumped from ^4.3.1 to ^4.3.2 - -## [10.2.1](https://github.com/netlify/primitives/compare/blobs-v10.2.0...blobs-v10.2.1) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/otel bumped from ^4.3.0 to ^4.3.1 - -## [10.2.0](https://github.com/netlify/primitives/compare/blobs-v10.1.0...blobs-v10.2.0) (2025-10-22) - - -### Features - -* add instrumentation to @netlify/blobs ([#384](https://github.com/netlify/primitives/issues/384)) ([9fe3782](https://github.com/netlify/primitives/commit/9fe3782bebeaf73f4265ea5eeb761abe9e657e09)) - -## [10.1.0](https://github.com/netlify/primitives/compare/blobs-v10.0.11...blobs-v10.1.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.2.0 to 4.3.0 - * @netlify/runtime-utils bumped from 2.1.0 to 2.2.0 - -## [10.0.11](https://github.com/netlify/primitives/compare/blobs-v10.0.10...blobs-v10.0.11) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.3 to 4.2.0 - -## [10.0.10](https://github.com/netlify/primitives/compare/blobs-v10.0.9...blobs-v10.0.10) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.2 to 4.1.3 - -## [10.0.9](https://github.com/netlify/primitives/compare/blobs-v10.0.8...blobs-v10.0.9) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.1 to 4.1.2 - -## [10.0.8](https://github.com/netlify/primitives/compare/blobs-v10.0.7...blobs-v10.0.8) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.0 to 4.1.1 - -## [10.0.7](https://github.com/netlify/primitives/compare/blobs-v10.0.6...blobs-v10.0.7) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.0.0 to 4.1.0 - -## [10.0.6](https://github.com/netlify/primitives/compare/blobs-v10.0.5...blobs-v10.0.6) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.3.0 to 4.0.0 - -## [10.0.5](https://github.com/netlify/primitives/compare/blobs-v10.0.4...blobs-v10.0.5) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.2.2 to 3.3.0 - -## [10.0.4](https://github.com/netlify/primitives/compare/blobs-v10.0.3...blobs-v10.0.4) (2025-07-07) - - -### Bug Fixes - -* apply fixes required for Vite plugin in Astro ([#332](https://github.com/netlify/primitives/issues/332)) ([fb8588e](https://github.com/netlify/primitives/commit/fb8588ee2731c40ee2c33997c026bc86542c71d0)) - -## [10.0.3](https://github.com/netlify/primitives/compare/blobs-v10.0.2...blobs-v10.0.3) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.2.1 to 3.2.2 - -## [10.0.2](https://github.com/netlify/primitives/compare/blobs-v10.0.1...blobs-v10.0.2) (2025-06-26) - - -### Bug Fixes - -* **blobs:** Encode blob key parts before saving to disk on windows ([#316](https://github.com/netlify/primitives/issues/316)) ([f6ee4ef](https://github.com/netlify/primitives/commit/f6ee4ef4d3911672ea0a2604886d20e2be6896eb)) - -## [10.0.1](https://github.com/netlify/primitives/compare/blobs-v10.0.0...blobs-v10.0.1) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.2.0 to 3.2.1 - -## [10.0.0](https://github.com/netlify/primitives/compare/blobs-v9.1.6...blobs-v10.0.0) (2025-06-11) - - -### ⚠ BREAKING CHANGES - -* add support for conditional writes ([#303](https://github.com/netlify/primitives/issues/303)) - -### Features - -* add support for conditional writes ([#303](https://github.com/netlify/primitives/issues/303)) ([de3295f](https://github.com/netlify/primitives/commit/de3295fa6d3f93d2bd76f959805a3cccfc3af5e7)) -* add support for conditional writes to `BlobsServer` ([#306](https://github.com/netlify/primitives/issues/306)) ([dad55a3](https://github.com/netlify/primitives/commit/dad55a35dadf36d17c026d8635c1c599892d423f)) - -## [9.1.6](https://github.com/netlify/primitives/compare/blobs-v9.1.5...blobs-v9.1.6) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.1.1 to 3.2.0 - -## [9.1.5](https://github.com/netlify/primitives/compare/blobs-v9.1.4...blobs-v9.1.5) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.1.0 to 3.1.1 - -## [9.1.4](https://github.com/netlify/primitives/compare/blobs-v9.1.3...blobs-v9.1.4) (2025-06-02) - - -### Bug Fixes - -* ensure valid 18.14.0+ dependencies ([#254](https://github.com/netlify/primitives/issues/254)) ([09dd0d8](https://github.com/netlify/primitives/commit/09dd0d8e1ab0c028eee8715b05307d8961b28463)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.0.0 to 3.1.0 - * @netlify/runtime-utils bumped from 2.0.0 to 2.1.0 - -## [9.1.3](https://github.com/netlify/primitives/compare/blobs-v9.1.2...blobs-v9.1.3) (2025-05-28) - - -### Bug Fixes - -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 2.2.0 to 3.0.0 - * @netlify/runtime-utils bumped from 1.3.1 to 2.0.0 - -## [9.1.2](https://github.com/netlify/primitives/compare/blobs-v9.1.1...blobs-v9.1.2) (2025-05-23) - - -### Bug Fixes - -* pass through server port when configured ([#184](https://github.com/netlify/primitives/issues/184)) ([ed092cf](https://github.com/netlify/primitives/commit/ed092cf14f75b4d4b3110924c103a57570a5b6ab)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 2.1.1 to 2.2.0 - * devDependencies - * @netlify/types bumped from 1.1.1 to 1.2.0 - -## [9.1.1](https://github.com/netlify/primitives/compare/blobs-v9.1.0...blobs-v9.1.1) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 2.1.0 to 2.1.1 - * @netlify/runtime-utils bumped from 1.3.0 to 1.3.1 - * devDependencies - * @netlify/types bumped from 1.1.0 to 1.1.1 - -## [9.1.0](https://github.com/netlify/primitives/compare/blobs-v9.0.1...blobs-v9.1.0) (2025-05-07) - - -### Features - -* add separate package for types ([#175](https://github.com/netlify/primitives/issues/175)) ([bb70188](https://github.com/netlify/primitives/commit/bb7018856ebda7a52ccff291cb306478e2853468)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 1.2.0 to 1.3.0 - * devDependencies - * @netlify/types bumped from 1.0.0 to 1.1.0 - -## [9.0.1](https://github.com/netlify/primitives/compare/blobs-v9.0.0...blobs-v9.0.1) (2025-05-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 2.0.0 to 2.1.0 - * @netlify/runtime-utils bumped from 1.1.0 to 1.2.0 - -## [9.0.0](https://github.com/netlify/primitives/compare/blobs-v8.2.0...blobs-v9.0.0) (2025-05-02) - - -### ⚠ BREAKING CHANGES - -* The `BlobsServer` class now only exports the `start()` and `stop()` methods. This class is not part of the Netlify Blobs client, and it's mostly used internally by Netlify tooling and by some users for integration tests — if you're just using the methods listed in https://docs.netlify.com/blobs/overview/#api-reference, this change does not apply to you and you can safely upgrade. - -### Features - -* add `runtime` and `runtime-utils` packages ([#150](https://github.com/netlify/primitives/issues/150)) ([be2cbf0](https://github.com/netlify/primitives/commit/be2cbf05cd3b73a795b54f94b7f51dacbcf6ef34)) -* add `start` entry point ([#154](https://github.com/netlify/primitives/issues/154)) ([b23c607](https://github.com/netlify/primitives/commit/b23c607ed3aa5e76279efa773b8c6c4d0dee972c)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 1.1.0 to 2.0.0 - * @netlify/runtime-utils bumped from 1.0.0 to 1.1.0 - -## [8.2.0](https://github.com/netlify/primitives/compare/blobs-v8.1.2...blobs-v8.2.0) (2025-04-16) - - -### Features - -* move primitives into monorepo ([#101](https://github.com/netlify/primitives/issues/101)) ([93b72b1](https://github.com/netlify/primitives/commit/93b72b1364022e45cbd87814dc6aa235f1e1c83e)) - -## [8.1.0](https://github.com/netlify/blobs/compare/v8.0.1...v8.1.0) (2024-10-11) - - -### Features - -* **types:** export deploy factory options types ([#196](https://github.com/netlify/blobs/issues/196)) ([29893cb](https://github.com/netlify/blobs/commit/29893cb00f4052f5171f7551711f31d495342cd8)) - - -### Bug Fixes - -* add more actionable info for missing primaryRegion ([#195](https://github.com/netlify/blobs/issues/195)) ([dd517dc](https://github.com/netlify/blobs/commit/dd517dcf74f1649adadbf7c652e924fcdf065e24)) - -## [8.0.1](https://github.com/netlify/blobs/compare/v8.0.0...v8.0.1) (2024-08-19) - - -### Bug Fixes - -* 404ing list results should return empty iterators, not throw ([#189](https://github.com/netlify/blobs/issues/189)) ([1da860d](https://github.com/netlify/blobs/commit/1da860dcc54cd33dddddcd8a78ea2f68a1cf523e)) - -## [8.0.0](https://github.com/netlify/blobs/compare/v7.4.0...v8.0.0) (2024-07-03) - - -### ⚠ BREAKING CHANGES - -* add region parameter ([#183](https://github.com/netlify/blobs/issues/183)) - -### Features - -* add region parameter ([#183](https://github.com/netlify/blobs/issues/183)) ([03187bb](https://github.com/netlify/blobs/commit/03187bb2b5b0a8d6ce1e823f811f168b05635886)) - -## [7.4.0](https://github.com/netlify/blobs/compare/v7.3.0...v7.4.0) (2024-07-01) - - -### Features - -* support named deploy-scoped stores ([#181](https://github.com/netlify/blobs/issues/181)) ([7b24ef8](https://github.com/netlify/blobs/commit/7b24ef82756f53be89cc22c9ce8dbe1bd66468dc)) - -## [7.3.0](https://github.com/netlify/blobs/compare/v7.2.0...v7.3.0) (2024-04-03) - - -### Features - -* add details to error message ([#167](https://github.com/netlify/blobs/issues/167)) ([7367241](https://github.com/netlify/blobs/commit/7367241451dab9be423aa0ca16dae51e827e0f57)) -* add request ID to error messages ([#165](https://github.com/netlify/blobs/issues/165)) ([b560051](https://github.com/netlify/blobs/commit/b5600511faa9503478662c68699996f708eb7b43)) -* handle `region:` prefix in local server ([#164](https://github.com/netlify/blobs/issues/164)) ([fe7d899](https://github.com/netlify/blobs/commit/fe7d89953f369fbe90c911c527d118b655b30b3c)) - -## [7.2.0](https://github.com/netlify/blobs/compare/v7.1.0...v7.2.0) (2024-04-01) - - -### Features - -* add `url` to server's `onRequest` callback ([#162](https://github.com/netlify/blobs/issues/162)) ([89f5ce4](https://github.com/netlify/blobs/commit/89f5ce4c270d018cf3475faa9920e46ff8cf8860)) -* export `setEnvironmentContext()` ([#160](https://github.com/netlify/blobs/issues/160)) ([90a0412](https://github.com/netlify/blobs/commit/90a0412a2d2b7b7f5113460ca00610dd40c01f76)) - -## [7.1.0](https://github.com/netlify/blobs/compare/v7.0.1...v7.1.0) (2024-04-01) - - -### Features - -* add experimental support for region selection ([#158](https://github.com/netlify/blobs/issues/158)) ([6734751](https://github.com/netlify/blobs/commit/673475135a98c4e4b0b98d7a5cc5b26ed813d16c)) - -## [7.0.1](https://github.com/netlify/blobs/compare/v7.0.0...v7.0.1) (2024-03-08) - - -### Bug Fixes - -* include connectLambda in dist ([#156](https://github.com/netlify/blobs/issues/156)) ([f7963b8](https://github.com/netlify/blobs/commit/f7963b8af00d6ca1e42650116c8cc27618996fd5)) - -## [7.0.0](https://github.com/netlify/blobs/compare/v6.5.0...v7.0.0) (2024-03-06) - - -### ⚠ BREAKING CHANGES - -* move server to sub-module export ([#155](https://github.com/netlify/blobs/issues/155)) -* add `listStores` method ([#149](https://github.com/netlify/blobs/issues/149)) - -### Features - -* add `listStores` method ([#149](https://github.com/netlify/blobs/issues/149)) ([3d0a386](https://github.com/netlify/blobs/commit/3d0a386f4ad6a5fe4a19c4e8b8bbef73ddb557a2)) -* allow internal access to legacy stores ([#152](https://github.com/netlify/blobs/issues/152)) ([1b712fe](https://github.com/netlify/blobs/commit/1b712fe52be74e0286bad6bb8d5972ea6a45b4ba)) -* move server to sub-module export ([#155](https://github.com/netlify/blobs/issues/155)) ([4bcfeff](https://github.com/netlify/blobs/commit/4bcfeff5288e1bf0934730bb4c40f3e38ba51892)) -* remove usage of Node built-ins ([#154](https://github.com/netlify/blobs/issues/154)) ([3148833](https://github.com/netlify/blobs/commit/3148833e6e87472fe3252127862b0a8e87e349d6)) -* respect `accept` header in server ([#153](https://github.com/netlify/blobs/issues/153)) ([8259e5e](https://github.com/netlify/blobs/commit/8259e5e7c7b96b9d9db9ff5e8e126f3b6b137d53)) -* support listing stores in local server ([#151](https://github.com/netlify/blobs/issues/151)) ([8820cc8](https://github.com/netlify/blobs/commit/8820cc81322ad1ea29d4b7c3061e57560e26ef02)) -* use `accept` header for signed URL ([#150](https://github.com/netlify/blobs/issues/150)) ([713e2be](https://github.com/netlify/blobs/commit/713e2bef0e105685ccb39604f5fc9c51df85865d)) -* use new API endpoints ([#147](https://github.com/netlify/blobs/issues/147)) ([5ad27eb](https://github.com/netlify/blobs/commit/5ad27ebd6da7dba6264eb2fc5db16bc8aca5d7ba)) - -## [6.5.0](https://github.com/netlify/blobs/compare/v6.4.2...v6.5.0) (2024-02-08) - - -### Features - -* add `consistency` configuration property ([#143](https://github.com/netlify/blobs/issues/143)) ([febd736](https://github.com/netlify/blobs/commit/febd736b6e4f7760f9b09f663348cce7c478335e)) - -## [6.4.2](https://github.com/netlify/blobs/compare/v6.4.1...v6.4.2) (2024-01-15) - - -### Bug Fixes - -* simplify streaming of server writes ([#137](https://github.com/netlify/blobs/issues/137)) ([ae5bdf9](https://github.com/netlify/blobs/commit/ae5bdf9637a6bf1a8eaa08aabdd7ada77b63c7e0)) - -## [6.4.1](https://github.com/netlify/blobs/compare/v6.4.0...v6.4.1) (2024-01-11) - - -### Bug Fixes - -* disallow empty key ([#134](https://github.com/netlify/blobs/issues/134)) ([a8b4a23](https://github.com/netlify/blobs/commit/a8b4a23b8414dceb8cc623e511f623ab72cd06ad)) - -## [6.4.0](https://github.com/netlify/blobs/compare/v6.3.1...v6.4.0) (2024-01-09) - - -### Features - -* add `connectLambda` method ([#128](https://github.com/netlify/blobs/issues/128)) ([d1061b4](https://github.com/netlify/blobs/commit/d1061b4e559865557f1ebc758e09a4ac35ade209)) - - -### Bug Fixes - -* copy temp file to prevent `EXDEV: cross-device link not permitted` ([#132](https://github.com/netlify/blobs/issues/132)) ([61b4ee6](https://github.com/netlify/blobs/commit/61b4ee668381dbf7e83179f93cd42a20f412b892)) - -## [6.3.1](https://github.com/netlify/blobs/compare/v6.3.0...v6.3.1) (2023-11-24) - - -### Bug Fixes - -* handle deploy-scoped stores on Windows ([#119](https://github.com/netlify/blobs/issues/119)) ([e96286d](https://github.com/netlify/blobs/commit/e96286d5d0182e99bc7ec2a6f440bf44f1cb347b)) - -## [6.3.0](https://github.com/netlify/blobs/compare/v6.2.0...v6.3.0) (2023-11-16) - - -### Features - -* add `onRequest` callback to server ([#116](https://github.com/netlify/blobs/issues/116)) ([35629fd](https://github.com/netlify/blobs/commit/35629fd81a434be24d2248516593dcbe1fbdccb7)) - - -### Bug Fixes - -* stop logging metadata not found error ([#114](https://github.com/netlify/blobs/issues/114)) ([0fb9ab6](https://github.com/netlify/blobs/commit/0fb9ab650b7bdfcb7b25c4a0ff706f8e20e44ad8)) - -## [6.2.0](https://github.com/netlify/blobs/compare/v6.1.0...v6.2.0) (2023-11-14) - - -### Features - -* export Store types ([#110](https://github.com/netlify/blobs/issues/110)) ([f04eaa5](https://github.com/netlify/blobs/commit/f04eaa566ef2ebc95328d1d54d4e8222e7b6eb5d)) - - -### Bug Fixes - -* fix metadata in local server ([#112](https://github.com/netlify/blobs/issues/112)) ([9646519](https://github.com/netlify/blobs/commit/96465198a790c2c3acf9b4569cc05928126ee0be)) - -## [6.1.0](https://github.com/netlify/blobs/compare/v6.0.1...v6.1.0) (2023-11-14) - - -### Features - -* support API access in local server ([#108](https://github.com/netlify/blobs/issues/108)) ([bea8874](https://github.com/netlify/blobs/commit/bea88742cdd868ef797ef88bf63fec778307d504)) -* support HEAD requests in local server ([#109](https://github.com/netlify/blobs/issues/109)) ([25ff62c](https://github.com/netlify/blobs/commit/25ff62c054c3fe6f223abd8523ae1af8d76295f3)) - - -### Bug Fixes - -* update repo url in package.json ([#106](https://github.com/netlify/blobs/issues/106)) ([84e4e58](https://github.com/netlify/blobs/commit/84e4e58d06dd4d890e10a1e41285fbc567194ae5)) - -## [6.0.1](https://github.com/netlify/blobs/compare/v6.0.0...v6.0.1) (2023-11-13) - - -### Bug Fixes - -* successful delete returns 204 ([#104](https://github.com/netlify/blobs/issues/104)) ([da0ea31](https://github.com/netlify/blobs/commit/da0ea3145489d2cb93fdeb32be6db33af6049869)) - -## [6.0.0](https://github.com/netlify/blobs/compare/v5.0.0...v6.0.0) (2023-11-10) - - -### ⚠ BREAKING CHANGES - -* return `AsyncIterator` for `list()` ([#102](https://github.com/netlify/blobs/issues/102)) - -### Features - -* return `AsyncIterator` for `list()` ([#102](https://github.com/netlify/blobs/issues/102)) ([f951513](https://github.com/netlify/blobs/commit/f951513a33d0009e863752e95d801486c410c4d7)) - -## [5.0.0](https://github.com/netlify/blobs/compare/v4.2.0...v5.0.0) (2023-11-09) - - -### ⚠ BREAKING CHANGES - -* remove `fresh` property from metadata result ([#99](https://github.com/netlify/blobs/issues/99)) -* return boolean from `delete()` ([#98](https://github.com/netlify/blobs/issues/98)) -* disallow setting an object as a stream ([#96](https://github.com/netlify/blobs/issues/96)) - -### Features - -* disallow setting an object as a stream ([#96](https://github.com/netlify/blobs/issues/96)) ([1c8f668](https://github.com/netlify/blobs/commit/1c8f668e27210c92a564efb45a3ae6bc7a0c518b)) -* remove `fresh` property from metadata result ([#99](https://github.com/netlify/blobs/issues/99)) ([a0f337a](https://github.com/netlify/blobs/commit/a0f337a81a30c19804737da6ea62f67dd015ca6c)) -* remove return value of `delete()` ([#100](https://github.com/netlify/blobs/issues/100)) ([b0c607b](https://github.com/netlify/blobs/commit/b0c607b1c4742f2f4d32b709c1df5ee4cb14d383)) -* return boolean from `delete()` ([#98](https://github.com/netlify/blobs/issues/98)) ([a566287](https://github.com/netlify/blobs/commit/a566287619a97a3ce146768225284fecc0910be2)) - -## [4.2.0](https://github.com/netlify/blobs/compare/v4.1.0...v4.2.0) (2023-11-07) - - -### Features - -* add `getMetadata` method ([#90](https://github.com/netlify/blobs/issues/90)) ([0327476](https://github.com/netlify/blobs/commit/03274763dc0afc9fdbe3981685f8eba1882bae4a)) - - -### Bug Fixes - -* delete status code checking ([#93](https://github.com/netlify/blobs/issues/93)) ([ea3d754](https://github.com/netlify/blobs/commit/ea3d754fb918b25490c6b924806a3bf8ae378120)) -* internal vs external metadata headers ([#92](https://github.com/netlify/blobs/issues/92)) ([de41f9e](https://github.com/netlify/blobs/commit/de41f9e6e59a50426338f504270a6b37aa8e3904)) - -## [4.1.0](https://github.com/netlify/blobs/compare/v4.0.0...v4.1.0) (2023-11-02) - - -### Features - -* load context from global variable ([#87](https://github.com/netlify/blobs/issues/87)) ([cbb5c3d](https://github.com/netlify/blobs/commit/cbb5c3d3fb92d2680865831926d11af8a9ac2103)) - -## [4.0.0](https://github.com/netlify/blobs/compare/v3.3.0...v4.0.0) (2023-10-26) - - -### ⚠ BREAKING CHANGES - -* validate keys and store names ([#80](https://github.com/netlify/blobs/issues/80)) - -### Features - -* add `list()` method ([#82](https://github.com/netlify/blobs/issues/82)) ([00db5ff](https://github.com/netlify/blobs/commit/00db5ff2cfb1e1780eadd4f1605f76f6519f65d2)) -* support `list()` in local server ([#83](https://github.com/netlify/blobs/issues/83)) ([9fc8456](https://github.com/netlify/blobs/commit/9fc845604fc20189a18fff5add075d542fbddc8e)) -* update validation rules ([#84](https://github.com/netlify/blobs/issues/84)) ([7218bb5](https://github.com/netlify/blobs/commit/7218bb5865770f7a83967613c378d4b7bed9df3c)) -* validate keys and store names ([#80](https://github.com/netlify/blobs/issues/80)) ([af867f8](https://github.com/netlify/blobs/commit/af867f87225f2c1e10192d3a4403b76d49c6cb56)) - -## [3.3.0](https://github.com/netlify/blobs/compare/v3.2.0...v3.3.0) (2023-10-23) - - -### Features - -* add local server ([#75](https://github.com/netlify/blobs/issues/75)) ([dc209d7](https://github.com/netlify/blobs/commit/dc209d715ca87d3b774784fde3cf02ce0e3b0faf)) -* add support for conditional requests ([#76](https://github.com/netlify/blobs/issues/76)) ([82df6ad](https://github.com/netlify/blobs/commit/82df6ad0889ea29fd6191133c8a319e7e458ab7d)) -* encode store name + check for `fetch` ([#73](https://github.com/netlify/blobs/issues/73)) ([0cb0b36](https://github.com/netlify/blobs/commit/0cb0b3654b164e327e9602ad229bfdd69f0cab45)) - -## [3.2.0](https://github.com/netlify/blobs/compare/v3.1.0...v3.2.0) (2023-10-19) - - -### Features - -* add support for arbitrary metadata ([#70](https://github.com/netlify/blobs/issues/70)) ([9b2a4df](https://github.com/netlify/blobs/commit/9b2a4dfe2adbb028c5cbfbe814e53e010a58be19)) - - -### Bug Fixes - -* couple of small fixes ([#72](https://github.com/netlify/blobs/issues/72)) ([edadf1c](https://github.com/netlify/blobs/commit/edadf1c6288ae0c55e48cc196e2476e3ef95cc0c)) - -## [3.1.0](https://github.com/netlify/blobs/compare/v3.0.0...v3.1.0) (2023-10-18) - - -### Features - -* add `getDeployStore` method ([#68](https://github.com/netlify/blobs/issues/68)) ([5135f3d](https://github.com/netlify/blobs/commit/5135f3d3dfaf55c48c51e8b115ab64c8728e73aa)) - -## [3.0.0](https://github.com/netlify/blobs/compare/v2.2.0...v3.0.0) (2023-10-17) - - -### ⚠ BREAKING CHANGES - -* add `getStore` method ([#58](https://github.com/netlify/blobs/issues/58)) - -### Features - -* add `getStore` method ([#58](https://github.com/netlify/blobs/issues/58)) ([6507e87](https://github.com/netlify/blobs/commit/6507e87cdebe110b6e5145c7c69f3c1a16b066ee)) - -## [2.2.0](https://github.com/netlify/blobs/compare/v2.1.1...v2.2.0) (2023-10-13) - - -### Features - -* add package.json to export map ([#64](https://github.com/netlify/blobs/issues/64)) ([3ea080e](https://github.com/netlify/blobs/commit/3ea080e9cdde95f14b8d372181be78b208727d0b)) - -## [2.1.1](https://github.com/netlify/blobs/compare/v2.1.0...v2.1.1) (2023-10-13) - - -### Bug Fixes - -* adjust export map to be actually importable ([#62](https://github.com/netlify/blobs/issues/62)) ([1bedfde](https://github.com/netlify/blobs/commit/1bedfde6c5ddb368b5789bc1766f7918eac19a8f)) - -## [2.1.0](https://github.com/netlify/blobs/compare/v2.0.0...v2.1.0) (2023-10-11) - - -### Features - -* export commonjs and esm from package ([#59](https://github.com/netlify/blobs/issues/59)) ([38b9c81](https://github.com/netlify/blobs/commit/38b9c81c280a2bc3b7a348103d94b98fd44f67e9)) - -## [2.0.0](https://github.com/netlify/blobs/compare/v1.6.1...v2.0.0) (2023-09-25) - - -### ⚠ BREAKING CHANGES - -* use URI-encoded keys ([#50](https://github.com/netlify/blobs/issues/50)) - -### Features - -* use URI-encoded keys ([#50](https://github.com/netlify/blobs/issues/50)) ([fd8e1c6](https://github.com/netlify/blobs/commit/fd8e1c6b0f30714e0e0649a22b0b615bc48dbabe)) - -## [1.6.1](https://github.com/netlify/blobs/compare/v1.6.0...v1.6.1) (2023-09-21) - - -### Bug Fixes - -* workaround for a cloudfront issue where it throws on a 403 ([c0fd160](https://github.com/netlify/blobs/commit/c0fd160d49c95205b577b031e3b3aee622e003af)) - -## [1.6.0](https://github.com/netlify/blobs/compare/v1.5.0...v1.6.0) (2023-07-31) - - -### Features - -* add `setFiles()` method ([#28](https://github.com/netlify/blobs/issues/28)) ([fd769de](https://github.com/netlify/blobs/commit/fd769dec65a215bf3de74dcf279ab2484e4f3a70)) - - -### Bug Fixes - -* **deps:** update dependency esbuild to v0.18.17 ([ad0d7e3](https://github.com/netlify/blobs/commit/ad0d7e3b2757dabad1c1e43e2f9a912317b72d8f)) - -## [1.5.0](https://github.com/netlify/blobs/compare/v1.4.0...v1.5.0) (2023-07-27) - - -### Features - -* add `setFile()` method ([#26](https://github.com/netlify/blobs/issues/26)) ([b8dc848](https://github.com/netlify/blobs/commit/b8dc848aa74adc3c8d37314a0b6c00a4e2c0e28a)) -* add retry logic ([#27](https://github.com/netlify/blobs/issues/27)) ([c824f0d](https://github.com/netlify/blobs/commit/c824f0d6db06b87bed9e9509ca0301d72d307b67)) -* build with esbuild ([#22](https://github.com/netlify/blobs/issues/22)) ([23c6576](https://github.com/netlify/blobs/commit/23c6576dd336c0d87fbc32608c30fbcbd625139f)) -* update `get` signature ([#23](https://github.com/netlify/blobs/issues/23)) ([e817d59](https://github.com/netlify/blobs/commit/e817d590c1bea56925147571aa1506988fee9905)) - -## [1.4.0](https://github.com/netlify/blobs/compare/v1.3.0...v1.4.0) (2023-07-20) - - -### Features - -* support TTL in `setJSON` method ([#17](https://github.com/netlify/blobs/issues/17)) ([392c9e1](https://github.com/netlify/blobs/commit/392c9e1cb00ae32622d32e36c06475706a9bcdf0)) - -## [1.3.0](https://github.com/netlify/blobs/compare/v1.2.0...v1.3.0) (2023-07-19) - - -### Features - -* throw error on missing config properties ([#15](https://github.com/netlify/blobs/issues/15)) ([10f30a8](https://github.com/netlify/blobs/commit/10f30a89ee3c8614b3a7f8a06a4a4672b9c83937)) - -## [1.2.0](https://github.com/netlify/blobs/compare/v1.1.0...v1.2.0) (2023-07-18) - - -### Miscellaneous Chores - -* release 1.2.0 ([88173ae](https://github.com/netlify/blobs/commit/88173aeaba04cc90c3a9b9c47fc4fbc7e2f2a99c)) - -## [1.1.0](https://github.com/netlify/blobs/compare/v1.0.0...v1.1.0) (2023-07-18) - - -### Features - -* throw when API returns an error code ([#12](https://github.com/netlify/blobs/issues/12)) ([a6573b2](https://github.com/netlify/blobs/commit/a6573b2acb218e9bb12cdde3b1a83d64214aa864)) - -## 1.0.0 (2023-07-18) - - -### Features - -* return `null` on 404 ([614e214](https://github.com/netlify/blobs/commit/614e21463f55c13a30462f3c575acdfa0a5ba299)) -* update `get` signature ([33b774c](https://github.com/netlify/blobs/commit/33b774c49aadfbc99391d96b357c27e69a4a4e93)) -* various small updates ([#10](https://github.com/netlify/blobs/issues/10)) ([30e9d4b](https://github.com/netlify/blobs/commit/30e9d4b999b559cccb342db5a511ef1f54a5aadd)) - - -### Bug Fixes - -* fix linting problems ([4cceed2](https://github.com/netlify/blobs/commit/4cceed26784deac5865b1c9f2234b549f0c613d7)) diff --git a/packages/blobs/CODE_OF_CONDUCT.md b/packages/blobs/CODE_OF_CONDUCT.md deleted file mode 100644 index fad7632..0000000 --- a/packages/blobs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,60 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making -participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, -disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take -appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, -issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any -contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the -project or its community. Examples of representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed representative at an online or offline -event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at -david@netlify.com. All complaints will be reviewed and investigated and will result in a response that is deemed -necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to -the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent -repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at -[http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/packages/blobs/CONTRIBUTING.md b/packages/blobs/CONTRIBUTING.md deleted file mode 100644 index 5dfd0c0..0000000 --- a/packages/blobs/CONTRIBUTING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributions - -🎉 Thanks for considering contributing to this project! 🎉 - -These guidelines will help you send a pull request. - -Please note that this project is not intended to be used outside my own projects so new features are unlikely to be -accepted. - -If you're submitting an issue instead, please skip this document. - -If your pull request is related to a typo or the documentation being unclear, please click on the relevant page's `Edit` -button (pencil icon) and directly suggest a correction instead. - -This project was made with ❤️. The simplest way to give back is by starring and sharing it online. - -Everyone is welcome regardless of personal background. We enforce a [Code of conduct](CODE_OF_CONDUCT.md) in order to -promote a positive and inclusive environment. - -# Development process - -First fork and clone the repository. If you're not sure how to do this, please watch -[these videos](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). - -Run: - -```bash -npm install -``` - -Make sure everything is correctly setup with: - -```bash -npm test -``` - -After submitting the pull request, please make sure the Continuous Integration checks are passing. - -## Releasing - -1. Merge the release PR -2. Switch to the default branch `git checkout main` -3. Pull latest changes `git pull` -4. Publish the package `npm publish` diff --git a/packages/blobs/LICENSE b/packages/blobs/LICENSE deleted file mode 100644 index 182fc3f..0000000 --- a/packages/blobs/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2022 Netlify - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/blobs/README.md b/packages/blobs/README.md deleted file mode 100644 index 985d8a7..0000000 --- a/packages/blobs/README.md +++ /dev/null @@ -1,448 +0,0 @@ -[![Build](https://github.com/netlify/primitives/workflows/Build/badge.svg)](https://github.com/netlify/primitives/actions) -[![Node](https://img.shields.io/node/v/@netlify/blobs.svg?logo=node.js)](https://www.npmjs.com/package/@netlify/blobs) - -# @netlify/blobs - -A TypeScript client for Netlify Blobs. - -## Installation - -You can install `@netlify/blobs` via npm: - -```shell -npm install @netlify/blobs -``` - -### Requirements - -- Deno 1.30 and above or Node.js 16.0.0 and above - -## Usage - -To start reading and writing data, you must first get a reference to a store using the `getStore` method. - -This method takes an options object that lets you configure the store for different access modes. - -### Environment-based configuration - -Rather than explicitly passing the configuration context to the `getStore` method, it can be read from the execution -environment. This is particularly useful for setups where the configuration data is held by one system and the data -needs to be accessed in another system, with no direct communication between the two. - -To do this, the system that holds the configuration data should set a global variable called `netlifyBlobsContext` or an -environment variable called `NETLIFY_BLOBS_CONTEXT` with a Base64-encoded, JSON-stringified representation of an object -with the following properties: - -- `apiURL` (optional) or `edgeURL`: URL of the Netlify API (for [API access](#api-access)) or the edge endpoint (for - [Edge access](#edge-access)) -- `token`: Access token for the corresponding access mode -- `siteID`: ID of the Netlify site - -This data is automatically populated by Netlify in the execution environment for both serverless and edge functions. - -With this in place, the `getStore` method can be called just with the store name. No configuration object is required, -since it'll be read from the environment. - -```ts -import { getStore } from '@netlify/blobs' - -const store = getStore('my-store') - -console.log(await store.get('my-key')) -``` - -#### Lambda compatibility mode - -The environment is not configured automatically when running functions in the -[Lambda compatibility mode](https://docs.netlify.com/functions/lambda-compatibility). To use Netlify Blobs, you must -initialize the environment manually by calling the `connectLambda` method with the Lambda event as a parameter. - -You should call this method immediately before calling `getStore` or `getDeployStore`. - -```ts -import { connectLambda, getStore } from '@netlify/blobs' - -export const handler = async (event) => { - connectLambda(event) - - const store = getStore('my-store') - const value = await store.get('my-key') - - return { - statusCode: 200, - body: value, - } -} -``` - -### API access - -You can interact with the blob store through the [Netlify API](https://docs.netlify.com/api/get-started). This is the -recommended method if you're looking for a strong-consistency way of accessing data, where latency is not mission -critical (since requests will always go to a non-distributed origin). - -Create a store for API access by calling `getStore` with the following parameters: - -- `name` (string): Name of the store -- `siteID` (string): ID of the Netlify site -- `token` (string): [Personal access token](https://docs.netlify.com/api/get-started/#authentication) to access the - Netlify API -- `apiURL` (string): URL of the Netlify API (optional, defaults to `https://api.netlify.com`) - -```ts -import { getStore } from '@netlify/blobs' - -const store = getStore({ - name: 'my-store', - siteID: 'MY_SITE_ID', - token: 'MY_TOKEN', -}) - -console.log(await store.get('some-key')) -``` - -### Edge access - -You can also interact with the blob store using a distributed network that caches entries at the edge. This is the -recommended method if you're looking for fast reads across multiple locations, knowing that reads will be -eventually-consistent with a drift of up to 60 seconds. - -Create a store for edge access by calling `getStore` with the following parameters: - -- `name` (string): Name of the store -- `siteID` (string): ID of the Netlify site -- `token` (string): Access token to the edge endpoint -- `edgeURL` (string): URL of the edge endpoint - -```ts -import { Buffer } from 'node:buffer' - -import { getStore } from '@netlify/blobs' - -// Serverless function using the Lambda compatibility mode -export const handler = async (event) => { - const rawData = Buffer.from(event.blobs, 'base64') - const data = JSON.parse(rawData.toString('ascii')) - const store = getStore({ - edgeURL: data.url, - name: 'my-store', - token: data.token, - siteID: 'MY_SITE_ID', - }) - const item = await store.get('some-key') - - return { - statusCode: 200, - body: item, - } -} -``` - -### Deploy scope - -By default, stores exist at the site level, which means that data can be read and written across different deploys and -deploy contexts. Users are responsible for managing that data, since the platform doesn't have enough information to -know whether an item is still relevant or safe to delete. - -But sometimes it's useful to have data pegged to a specific deploy, and shift to the platform the responsibility of -managing that data — keep it as long as the deploy is around, and wipe it if the deploy is deleted. - -You can opt-in to this behavior by creating the store using the `getDeployStore` method. - -```ts -import { assert } from 'node:assert' - -import { getDeployStore } from '@netlify/blobs' - -// Using API access -const store1 = getDeployStore({ - deployID: 'MY_DEPLOY_ID', - token: 'MY_API_TOKEN', -}) - -await store1.set('my-key', 'my value') - -// Using environment-based configuration -const store2 = getDeployStore() - -assert.equal(await store2.get('my-key'), 'my value') -``` - -### Custom `fetch` - -The client uses [the web platform `fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make HTTP -calls. By default, it will use any globally-defined instance of `fetch`, but you can choose to provide your own. - -You can do this by supplying a `fetch` property to the `getStore` method. - -```ts -import { fetch } from 'whatwg-fetch' - -import { getStore } from '@netlify/blobs' - -const store = getStore({ - fetch, - name: 'my-store', -}) - -console.log(await store.get('my-key')) -``` - -## Store API reference - -### `get(key: string, { type?: string }): Promise` - -Retrieves an object with the given key. - -Depending on the most convenient format for you to access the value, you may choose to supply a `type` property as a -second parameter, with one of the following values: - -- `arrayBuffer`: Returns the entry as an - [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) -- `blob`: Returns the entry as a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) -- `json`: Parses the entry as JSON and returns the resulting object -- `stream`: Returns the entry as a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) -- `text` (default): Returns the entry as a string of plain text - -If an object with the given key is not found, `null` is returned. - -```javascript -const entry = await store.get('some-key', { type: 'json' }) - -console.log(entry) -``` - -### `getWithMetadata(key: string, { etag?: string, type?: string }): Promise<{ data: any, etag: string, metadata: object }>` - -Retrieves an object with the given key, the [ETag value](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) -for the entry, and any metadata that has been stored with the entry. - -Depending on the most convenient format for you to access the value, you may choose to supply a `type` property as a -second parameter, with one of the following values: - -- `arrayBuffer`: Returns the entry as an - [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) -- `blob`: Returns the entry as a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) -- `json`: Parses the entry as JSON and returns the resulting object -- `stream`: Returns the entry as a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) -- `text` (default): Returns the entry as a string of plain text - -If an object with the given key is not found, `null` is returned. - -```javascript -const blob = await store.getWithMetadata('some-key', { type: 'json' }) - -console.log(blob.data, blob.etag, blob.metadata) -``` - -The `etag` input parameter lets you implement conditional requests, where the blob is only returned if it differs from a -version you have previously obtained. - -```javascript -// Mock implementation of a system for locally persisting blobs and their etags -const cachedETag = getFromMockCache('my-key') - -// Get entry from the blob store only if its ETag is different from the one you -// have locally, which means the entry has changed since you last obtained it -const { data, etag } = await store.getWithMetadata('some-key', { etag: cachedETag }) - -if (etag === cachedETag) { - // `data` is `null` because the local blob is fresh -} else { - // `data` contains the new blob, store it locally alongside the new ETag - writeInMockCache('my-key', data, etag) -} -``` - -### `getMetadata(key: string, { etag?: string, type?: string }): Promise<{ etag: string, metadata: object }>` - -Retrieves any metadata associated with a given key and its -[ETag value](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag). - -If an object with the given key is not found, `null` is returned. - -This method can be used to check whether a key exists without having to actually retrieve it and transfer a -potentially-large blob. - -```javascript -const blob = await store.getMetadata('some-key') - -console.log(blob.etag, blob.metadata) -``` - -### `set(key: string, value: ArrayBuffer | Blob | string, { metadata?: object }): Promise` - -Creates an object with the given key and value. - -If an entry with the given key already exists, its value is overwritten. - -```javascript -await store.set('some-key', 'This is a string value') -``` - -### `setJSON(key: string, value: any, { metadata?: object }): Promise` - -Convenience method for creating a JSON-serialized object with the given key. - -If an entry with the given key already exists, its value is overwritten. - -```javascript -await store.setJSON('some-key', { - foo: 'bar', -}) -``` - -### `delete(key: string): Promise` - -Deletes an object with the given key, if one exists. The return value is always `undefined`, regardless of whether or -not there was an object to delete. - -```javascript -await store.delete('my-key') -``` - -### `list(options?: { directories?: boolean, paginate?: boolean. prefix?: string }): Promise<{ blobs: BlobResult[], directories: string[] }> | AsyncIterable<{ blobs: BlobResult[], directories: string[] }>` - -Returns a list of blobs in a given store. - -```javascript -const { blobs } = await store.list() - -// [ { etag: 'etag1', key: 'some-key' }, { etag: 'etag2', key: 'another-key' } ] -console.log(blobs) -``` - -To filter down the entries that should be returned, an optional `prefix` parameter can be supplied. When used, only the -entries whose key starts with that prefix are returned. - -```javascript -const { blobs } = await store.list({ prefix: 'some' }) - -// [ { etag: 'etag1', key: 'some-key' } ] -console.log(blobs) -``` - -Optionally, you can choose to group blobs together under a common prefix and then browse them hierarchically when -listing a store, just like grouping files in a directory. To do this, use the `/` character in your keys to group them -into directories. - -Take the following list of keys as an example: - -``` -cats/garfield.jpg -cats/tom.jpg -mice/jerry.jpg -mice/mickey.jpg -pink-panther.jpg -``` - -By default, calling `store.list()` will return all five keys. - -```javascript -const { blobs } = await store.list() - -// [ -// { etag: "etag1", key: "cats/garfield.jpg" }, -// { etag: "etag2", key: "cats/tom.jpg" }, -// { etag: "etag3", key: "mice/jerry.jpg" }, -// { etag: "etag4", key: "mice/mickey.jpg" }, -// { etag: "etag5", key: "pink-panther.jpg" }, -// ] -console.log(blobs) -``` - -But if you want to list entries hierarchically, use the `directories` parameter. - -```javascript -const { blobs, directories } = await store.list({ directories: true }) - -// [ { etag: "etag1", key: "pink-panther.jpg" } ] -console.log(blobs) - -// [ "cats", "mice" ] -console.log(directories) -``` - -To drill down into a directory and get a list of its items, you can use the directory name as the `prefix` value. - -```javascript -const { blobs, directories } = await store.list({ directories: true, prefix: 'cats/' }) - -// [ { etag: "etag1", key: "cats/garfield.jpg" }, { etag: "etag2", key: "cats/tom.jpg" } ] -console.log(blobs) - -// [ ] -console.log(directories) -``` - -Note that we're only interested in entries under the `cats` directory, which is why we're using a trailing slash. -Without it, other keys like `catsuit` would also match. - -For performance reasons, the server groups results into pages of up to 1,000 entries. By default, the `list()` method -automatically retrieves all pages, meaning you'll always get the full list of results. - -If you'd like to handle this pagination manually, you can supply the `paginate` parameter, which makes `list()` return -an [`AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator). - -```javascript -const blobs = [] - -for await (const entry of store.list({ paginate: true })) { - blobs.push(...entry.blobs) -} - -// [ -// { etag: "etag1", key: "cats/garfield.jpg" }, -// { etag: "etag2", key: "cats/tom.jpg" }, -// { etag: "etag3", key: "mice/jerry.jpg" }, -// { etag: "etag4", key: "mice/mickey.jpg" }, -// { etag: "etag5", key: "pink-panther.jpg" }, -// ] -console.log(blobs) -``` - -## Server API reference - -We provide a Node.js server that implements the Netlify Blobs server interface backed by the local filesystem. This is -useful if you want to write automated tests that involve the Netlify Blobs API without interacting with a live store. - -The `BlobsServer` export lets you construct and initialize a server. You can then use its address to initialize a store. - -```ts -import { BlobsServer, getStore } from '@netlify/blobs' - -// Choose any token for protecting your local server from -// extraneous requests -const token = 'some-token' - -// Create a server by providing a local directory where all -// blobs and metadata should be persisted -const server = new BlobsServer({ - directory: '/path/to/blobs/directory', - port: 1234, - token, -}) - -await server.start() - -// Get a store and provide the address of the local server -const store = getStore({ - edgeURL: 'http://localhost:1234', - name: 'my-store', - token, -}) - -await store.set('my-key', 'This is a local blob') - -console.log(await store.get('my-key')) -``` - -## Contributing - -Contributions are welcome! If you encounter any issues or have suggestions for improvements, please open an issue or -submit a pull request on the [GitHub repository](https://github.com/example/netlify-blobs). - -## License - -Netlify Blobs is open-source software licensed under the -[MIT license](https://github.com/example/netlify-blobs/blob/main/LICENSE). diff --git a/packages/blobs/netlify.toml b/packages/blobs/netlify.toml deleted file mode 100644 index 01cc9b0a..0000000 --- a/packages/blobs/netlify.toml +++ /dev/null @@ -1,13 +0,0 @@ -[build] -command = "" -publish = "src" - -[[headers]] -for = "/*.js" -[headers.values] -Content-Type = "application/javascript; charset=utf-8" - -[[headers]] -for = "/*.ts" -[headers.values] -Content-Type = "application/typescript; charset=utf-8" diff --git a/packages/blobs/package.json b/packages/blobs/package.json deleted file mode 100644 index 9d19349..0000000 --- a/packages/blobs/package.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "@netlify/blobs", - "version": "10.7.9", - "description": "TypeScript client for Netlify Blobs", - "type": "module", - "engines": { - "node": "^14.16.0 || >=16.0.0" - }, - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json", - "./server": { - "require": { - "types": "./dist/server.d.cts", - "default": "./dist/server.cjs" - }, - "import": { - "types": "./dist/server.d.ts", - "default": "./dist/server.js" - }, - "default": { - "types": "./dist/server.d.ts", - "default": "./dist/server.js" - } - } - }, - "files": [ - "dist/**/*", - "server.d.ts" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "test": "run-s build test:ci", - "test:dev": "run-s build test:dev:*", - "test:ci": "run-s build test:ci:*", - "test:dev:vitest": "vitest", - "test:dev:vitest:watch": "vitest watch", - "test:ci:vitest": "vitest run", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/blobs" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "directories": { - "test": "test" - }, - "devDependencies": { - "@types/node": "^18.19.110", - "node-fetch": "^3.3.1", - "npm-run-all2": "^8.0.4", - "semver": "^7.5.3", - "tmp-promise": "^3.0.3", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/otel": "^6.0.3", - "@netlify/runtime-utils": "2.3.0" - } -} diff --git a/packages/blobs/server.d.ts b/packages/blobs/server.d.ts deleted file mode 100644 index 71dbdae..0000000 --- a/packages/blobs/server.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/server.d.ts' diff --git a/packages/blobs/src/backend/delete_store.ts b/packages/blobs/src/backend/delete_store.ts deleted file mode 100644 index bd889f2..0000000 --- a/packages/blobs/src/backend/delete_store.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface DeleteStoreResponse { - blobs_deleted: number - has_more: boolean -} diff --git a/packages/blobs/src/backend/list.ts b/packages/blobs/src/backend/list.ts deleted file mode 100644 index 17c14e6..0000000 --- a/packages/blobs/src/backend/list.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface ListResponse { - blobs?: ListResponseBlob[] - directories?: string[] - next_cursor?: string -} - -export interface ListResponseBlob { - etag: string - last_modified: string - size: number - key: string -} diff --git a/packages/blobs/src/backend/list_stores.ts b/packages/blobs/src/backend/list_stores.ts deleted file mode 100644 index 721c0a3..0000000 --- a/packages/blobs/src/backend/list_stores.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ListStoresResponse { - stores: string[] - next_cursor?: string -} diff --git a/packages/blobs/src/client.ts b/packages/blobs/src/client.ts deleted file mode 100644 index 9271ad5..0000000 --- a/packages/blobs/src/client.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { BlobsConsistencyError, ConsistencyMode } from './consistency.ts' -import { EnvironmentContext, getEnvironmentContext, MissingBlobsEnvironmentError } from './environment.ts' -import { encodeMetadata, Metadata, METADATA_HEADER_EXTERNAL, METADATA_HEADER_INTERNAL } from './metadata.ts' -import { InvalidBlobsRegionError, isValidRegion } from './region.ts' -import { fetchAndRetry } from './retry.ts' -import { BlobInput, Fetcher, HTTPMethod } from './types.ts' -import { BlobsInternalError } from './util.ts' - -export const SIGNED_URL_ACCEPT_HEADER = 'application/json;type=signed-url' - -export type Conditions = { onlyIfNew?: boolean } | { onlyIfMatch?: string } - -interface MakeStoreRequestOptions { - body?: BlobInput | null - conditions?: Conditions - consistency?: ConsistencyMode - headers?: Record - key?: string - metadata?: Metadata - method: HTTPMethod - parameters?: Record - storeName?: string -} - -export interface ClientOptions { - apiURL?: string - consistency?: ConsistencyMode - edgeURL?: string - fetch?: Fetcher - siteID: string - token: string - uncachedEdgeURL?: string -} - -interface InternalClientOptions extends ClientOptions { - region?: string -} - -interface GetFinalRequestOptions { - consistency?: ConsistencyMode - key: string | undefined - metadata?: Metadata - method: string - parameters?: Record - storeName?: string -} - -export class Client { - private apiURL?: string - private consistency: ConsistencyMode - private edgeURL?: string - private fetch: Fetcher - private region?: string - private siteID: string - private token: string - private uncachedEdgeURL?: string - - constructor({ apiURL, consistency, edgeURL, fetch, region, siteID, token, uncachedEdgeURL }: InternalClientOptions) { - this.apiURL = apiURL - this.consistency = consistency ?? 'eventual' - this.edgeURL = edgeURL - this.fetch = fetch ?? globalThis.fetch - this.region = region - this.siteID = siteID - this.token = token - this.uncachedEdgeURL = uncachedEdgeURL - - if (!this.fetch) { - throw new Error( - 'Netlify Blobs could not find a `fetch` client in the global scope. You can either update your runtime to a version that includes `fetch` (like Node.js 18.0.0 or above), or you can supply your own implementation using the `fetch` property.', - ) - } - } - - private async getFinalRequest({ - consistency: opConsistency, - key, - metadata, - method, - parameters = {}, - storeName, - }: GetFinalRequestOptions) { - const encodedMetadata = encodeMetadata(metadata) - const consistency = opConsistency ?? this.consistency - - let urlPath = `/${this.siteID}` - - if (storeName) { - urlPath += `/${storeName}` - } - - if (key) { - urlPath += `/${key}` - } - - if (this.edgeURL) { - if (consistency === 'strong' && !this.uncachedEdgeURL) { - throw new BlobsConsistencyError() - } - - const headers: Record = { - authorization: `Bearer ${this.token}`, - } - - if (encodedMetadata) { - headers[METADATA_HEADER_INTERNAL] = encodedMetadata - } - - if (this.region) { - urlPath = `/region:${this.region}${urlPath}` - } - - const url = new URL(urlPath, consistency === 'strong' ? this.uncachedEdgeURL : this.edgeURL) - - for (const key in parameters) { - url.searchParams.set(key, parameters[key]) - } - - return { - headers, - url: url.toString(), - } - } - - const apiHeaders: Record = { authorization: `Bearer ${this.token}` } - const url = new URL(`/api/v1/blobs${urlPath}`, this.apiURL ?? 'https://api.netlify.com') - - for (const key in parameters) { - url.searchParams.set(key, parameters[key]) - } - - if (this.region) { - url.searchParams.set('region', this.region) - } - - // If there is no store name, we're listing stores. If there's no key, - // we're listing blobs. Both operations are implemented directly in the - // Netlify API. - if (storeName === undefined || key === undefined) { - return { - headers: apiHeaders, - url: url.toString(), - } - } - - if (encodedMetadata) { - apiHeaders[METADATA_HEADER_EXTERNAL] = encodedMetadata - } - - // HEAD and DELETE requests are implemented directly in the Netlify API. - if (method === HTTPMethod.HEAD || method === HTTPMethod.DELETE) { - return { - headers: apiHeaders, - url: url.toString(), - } - } - - const res = await this.fetch(url.toString(), { - headers: { ...apiHeaders, accept: SIGNED_URL_ACCEPT_HEADER }, - method, - }) - - if (res.status !== 200) { - throw new BlobsInternalError(res) - } - - const { url: signedURL } = await res.json() - const userHeaders = encodedMetadata ? { [METADATA_HEADER_INTERNAL]: encodedMetadata } : undefined - - return { - headers: userHeaders, - url: signedURL, - } - } - - async makeRequest({ - body, - conditions = {}, - consistency, - headers: extraHeaders, - key, - metadata, - method, - parameters, - storeName, - }: MakeStoreRequestOptions) { - const { headers: baseHeaders = {}, url } = await this.getFinalRequest({ - consistency, - key, - metadata, - method, - parameters, - storeName, - }) - const headers: Record = { - ...baseHeaders, - ...extraHeaders, - } - - if (method === HTTPMethod.PUT) { - headers['cache-control'] = 'max-age=0, stale-while-revalidate=60' - } - - if ('onlyIfMatch' in conditions && conditions.onlyIfMatch) { - headers['if-match'] = conditions.onlyIfMatch - } else if ('onlyIfNew' in conditions && conditions.onlyIfNew) { - headers['if-none-match'] = '*' - } - - const options: RequestInit = { - body, - headers, - method, - } - - if (body instanceof ReadableStream) { - // @ts-expect-error Part of the spec, but not typed: - // https://fetch.spec.whatwg.org/#enumdef-requestduplex - options.duplex = 'half' - } - - return fetchAndRetry(this.fetch, url, options) - } -} - -/** - * Merges a set of options supplied by the user when getting a reference to a - * store with a context object found in the environment. - * - * @param options User-supplied options - * @param contextOverride Context to be used instead of the environment object - */ -export const getClientOptions = ( - options: Partial, - contextOverride?: EnvironmentContext, -): InternalClientOptions => { - const context = contextOverride ?? getEnvironmentContext() - const siteID = context.siteID ?? options.siteID - const token = context.token ?? options.token - - if (!siteID || !token) { - throw new MissingBlobsEnvironmentError(['siteID', 'token']) - } - - if (options.region !== undefined && !isValidRegion(options.region)) { - throw new InvalidBlobsRegionError(options.region) - } - - const clientOptions: InternalClientOptions = { - apiURL: context.apiURL ?? options.apiURL, - consistency: options.consistency, - edgeURL: context.edgeURL ?? options.edgeURL, - fetch: options.fetch, - region: options.region, - siteID, - token, - uncachedEdgeURL: context.uncachedEdgeURL ?? options.uncachedEdgeURL, - } - - return clientOptions -} diff --git a/packages/blobs/src/consistency.test.ts b/packages/blobs/src/consistency.test.ts deleted file mode 100644 index 0c5eafa..0000000 --- a/packages/blobs/src/consistency.test.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { Buffer } from 'node:buffer' -import { env, version as nodeVersion } from 'node:process' - -import { MockFetch } from '@netlify/dev-utils' -import semver from 'semver' -import { describe, test, expect, beforeAll, afterEach } from 'vitest' - -import { base64Encode } from '../test/util.js' - -import { getDeployStore, getStore } from './main.js' - -const deployID = '6527dfab35be400008332a1d' -const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' -const key = '54321' -const value = 'some value' -const edgeToken = 'some other token' -const edgeURL = 'https://edge.netlify' -const uncachedEdgeURL = 'https://uncached.edge.netlify' - -beforeAll(async () => { - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.fetch = nodeFetch.default - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Request = nodeFetch.Request - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Response = nodeFetch.Response - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Headers = nodeFetch.Headers - } -}) - -afterEach(() => { - delete env.NETLIFY_BLOBS_CONTEXT - delete globalThis.netlifyBlobsContext -}) - -describe('Consistency configuration', () => { - test('Respects the consistency mode supplied in the operation methods', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .head({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { headers }), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value, { headers }), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const context = { - edgeURL, - siteID, - token: edgeToken, - uncachedEdgeURL, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const blobs = getStore('production') - - const data = await blobs.get(key, { consistency: 'strong' }) - expect(data).toBe(value) - - const meta = await blobs.getMetadata(key, { consistency: 'strong' }) - expect(meta?.etag).toBe(headers.etag) - expect(meta?.metadata).toEqual(mockMetadata) - - const dataWithMeta = await blobs.getWithMetadata(key, { consistency: 'strong' }) - expect(dataWithMeta?.data).toBe(value) - expect(dataWithMeta?.etag).toBe(headers.etag) - expect(dataWithMeta?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Respects the consistency mode supplied in the `getStore()` constructor', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .head({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { headers }), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value, { headers }), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - consistency: 'strong', - edgeURL, - name: 'production', - token: edgeToken, - siteID, - uncachedEdgeURL, - }) - - const data = await blobs.get(key) - expect(data).toBe(value) - - const meta = await blobs.getMetadata(key) - expect(meta?.etag).toBe(headers.etag) - expect(meta?.metadata).toEqual(mockMetadata) - - const dataWithMeta = await blobs.getWithMetadata(key) - expect(dataWithMeta?.data).toBe(value) - expect(dataWithMeta?.etag).toBe(headers.etag) - expect(dataWithMeta?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Respects the consistency mode supplied in the `getDeployStore()` constructor', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const mockRegion = 'us-east-1' - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${uncachedEdgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .head({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { headers }), - url: `${uncachedEdgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value, { headers }), - url: `${uncachedEdgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - const blobs = getDeployStore({ - consistency: 'strong', - edgeURL, - deployID, - region: mockRegion, - token: edgeToken, - siteID, - uncachedEdgeURL, - }) - - const data = await blobs.get(key) - expect(data).toBe(value) - - const meta = await blobs.getMetadata(key) - expect(meta?.etag).toBe(headers.etag) - expect(meta?.metadata).toEqual(mockMetadata) - - const dataWithMeta = await blobs.getWithMetadata(key) - expect(dataWithMeta?.data).toBe(value) - expect(dataWithMeta?.etag).toBe(headers.etag) - expect(dataWithMeta?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('The consistency mode from the operation methods takes precedence over the store configuration', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`, - }) - .head({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { headers }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value, { headers }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - consistency: 'strong', - edgeURL, - name: 'production', - token: edgeToken, - siteID, - uncachedEdgeURL, - }) - - const data = await blobs.get(key) - expect(data).toBe(value) - - const meta = await blobs.getMetadata(key, { consistency: 'eventual' }) - expect(meta?.etag).toBe(headers.etag) - expect(meta?.metadata).toEqual(mockMetadata) - - const dataWithMeta = await blobs.getWithMetadata(key, { consistency: 'eventual' }) - expect(dataWithMeta?.data).toBe(value) - expect(dataWithMeta?.etag).toBe(headers.etag) - expect(dataWithMeta?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when strong consistency is used and no `uncachedEdgeURL` property has been defined', async () => { - const context = { - edgeURL, - siteID, - token: edgeToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const store = getStore('productin') - - await expect(store.get('my-key', { consistency: 'strong' })).rejects.toThrowError( - "Netlify Blobs has failed to perform a read using strong consistency because the environment has not been configured with a 'uncachedEdgeURL' property", - ) - }) -}) diff --git a/packages/blobs/src/consistency.ts b/packages/blobs/src/consistency.ts deleted file mode 100644 index c4c41f3..0000000 --- a/packages/blobs/src/consistency.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type ConsistencyMode = 'eventual' | 'strong' - -export class BlobsConsistencyError extends Error { - constructor() { - super( - `Netlify Blobs has failed to perform a read using strong consistency because the environment has not been configured with a 'uncachedEdgeURL' property`, - ) - - this.name = 'BlobsConsistencyError' - } -} diff --git a/packages/blobs/src/environment.ts b/packages/blobs/src/environment.ts deleted file mode 100644 index 29083e5..0000000 --- a/packages/blobs/src/environment.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { base64Decode, base64Encode, getEnvironment } from '@netlify/runtime-utils' - -declare global { - // Using `var` so that the declaration is hoisted in such a way that we can - // reference it before it's initialized. - - var netlifyBlobsContext: unknown -} - -/** - * The context object that we expect in the environment. - */ -export interface EnvironmentContext { - apiURL?: string - deployID?: string - edgeURL?: string - primaryRegion?: string - siteID?: string - token?: string - uncachedEdgeURL?: string -} - -export const getEnvironmentContext = (): EnvironmentContext => { - const context = globalThis.netlifyBlobsContext || getEnvironment().get('NETLIFY_BLOBS_CONTEXT') - - if (typeof context !== 'string' || !context) { - return {} - } - - const data = base64Decode(context) - - try { - return JSON.parse(data) as EnvironmentContext - } catch { - // no-op - } - - return {} -} - -export const setEnvironmentContext = (context: EnvironmentContext) => { - const encodedContext = base64Encode(JSON.stringify(context)) - - getEnvironment().set('NETLIFY_BLOBS_CONTEXT', encodedContext) -} - -export class MissingBlobsEnvironmentError extends Error { - constructor(requiredProperties: string[]) { - super( - `The environment has not been configured to use Netlify Blobs. To use it manually, supply the following properties when creating a store: ${requiredProperties.join( - ', ', - )}`, - ) - - this.name = 'MissingBlobsEnvironmentError' - } -} diff --git a/packages/blobs/src/headers.ts b/packages/blobs/src/headers.ts deleted file mode 100644 index 5222ca2..0000000 --- a/packages/blobs/src/headers.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const NF_ERROR = 'x-nf-error' -export const NF_REQUEST_ID = 'x-nf-request-id' diff --git a/packages/blobs/src/lambda_compat.test.ts b/packages/blobs/src/lambda_compat.test.ts deleted file mode 100644 index 63cd098..0000000 --- a/packages/blobs/src/lambda_compat.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { env, version as nodeVersion } from 'node:process' - -import { MockFetch } from '@netlify/dev-utils' -import semver from 'semver' -import { describe, test, expect, beforeAll, afterEach } from 'vitest' - -import { base64Encode, streamToString } from '../test/util.js' - -import { connectLambda } from './lambda_compat.js' -import { getStore } from './main.js' - -beforeAll(async () => { - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.fetch = nodeFetch.default - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Request = nodeFetch.Request - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Response = nodeFetch.Response - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Headers = nodeFetch.Headers - } -}) - -afterEach(() => { - delete env.NETLIFY_BLOBS_CONTEXT -}) - -const deployID = '6527dfab35be400008332a1d' -const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' -const key = '54321' -const value = 'some value' -const edgeToken = 'some other token' -const edgeURL = 'https://edge.netlify' - -describe('With edge credentials', () => { - test('Loads the credentials set via the `connectLambda` method', async () => { - const mockLambdaEvent = { - blobs: base64Encode({ token: edgeToken, url: edgeURL }), - headers: { - 'x-nf-deploy-id': deployID, - 'x-nf-site-id': siteID, - }, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - connectLambda(mockLambdaEvent) - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const string = await blobs.get(key) - expect(string).toBe(value) - - const stream = await blobs.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) -}) diff --git a/packages/blobs/src/lambda_compat.ts b/packages/blobs/src/lambda_compat.ts deleted file mode 100644 index 9efbff3..0000000 --- a/packages/blobs/src/lambda_compat.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { base64Decode } from '@netlify/runtime-utils' - -import { EnvironmentContext, setEnvironmentContext } from './environment.ts' -import type { LambdaEvent } from './types.ts' - -interface BlobsEventData { - token: string - url: string -} - -export const connectLambda = (event: LambdaEvent) => { - const rawData = base64Decode(event.blobs) - const data = JSON.parse(rawData) as BlobsEventData - const environmentContext: EnvironmentContext = { - deployID: event.headers['x-nf-deploy-id'], - edgeURL: data.url, - siteID: event.headers['x-nf-site-id'], - token: data.token, - } - - setEnvironmentContext(environmentContext) -} diff --git a/packages/blobs/src/list.test.ts b/packages/blobs/src/list.test.ts deleted file mode 100644 index ad56b2d..0000000 --- a/packages/blobs/src/list.test.ts +++ /dev/null @@ -1,812 +0,0 @@ -import { env, version as nodeVersion } from 'node:process' - -import { MockFetch } from '@netlify/dev-utils' -import semver from 'semver' -import { describe, test, expect, beforeAll, afterEach } from 'vitest' - -import { getStore } from './main.js' -import type { ListResult } from './store.js' - -beforeAll(async () => { - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.fetch = nodeFetch.default - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Request = nodeFetch.Request - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Response = nodeFetch.Response - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Headers = nodeFetch.Headers - } -}) - -afterEach(() => { - delete env.NETLIFY_BLOBS_CONTEXT -}) - -const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' -const storeName = 'mystore' -const apiToken = 'some token' -const edgeToken = 'some other token' -const edgeURL = 'https://edge.netlify' - -describe('list', () => { - describe('With API credentials', () => { - test('Lists blobs and handles pagination by default', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - next_cursor: 'cursor_1', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag3', - key: 'key3', - size: 3, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag4', - key: 'key4', - size: 4, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - next_cursor: 'cursor_2', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag5', - key: 'key5', - size: 5, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?cursor=cursor_2`, - }) - .inject() - - const store = getStore({ - name: 'mystore', - token: apiToken, - siteID, - }) - - const { blobs } = await store.list() - - expect(blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - { etag: 'etag3', key: 'key3' }, - { etag: 'etag4', key: 'key4' }, - { etag: 'etag5', key: 'key5' }, - ]) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a `directories` parameter', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: ['dir1'], - next_cursor: 'cursor_1', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?directories=true`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag3', - key: 'key3', - size: 3, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag4', - key: 'key4', - size: 4, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: ['dir2'], - next_cursor: 'cursor_2', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?directories=true&cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag5', - key: 'key5', - size: 5, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: ['dir3'], - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?directories=true&cursor=cursor_2`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag6', - key: 'key6', - size: 6, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?prefix=dir2%2F&directories=true`, - }) - .inject() - - const store = getStore({ - name: 'mystore', - token: apiToken, - siteID, - }) - - const root = await store.list({ directories: true }) - - expect(root.blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - { etag: 'etag3', key: 'key3' }, - { etag: 'etag4', key: 'key4' }, - { etag: 'etag5', key: 'key5' }, - ]) - - expect(root.directories).toEqual(['dir1', 'dir2', 'dir3']) - - const directory = await store.list({ directories: true, prefix: `dir2/` }) - - expect(directory.blobs).toEqual([{ etag: 'etag6', key: 'key6' }]) - expect(directory.directories).toEqual([]) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a `prefix` property', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'group/key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'group/key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?prefix=group%2F`, - }) - .inject() - - const store = getStore({ - name: 'mystore', - token: apiToken, - siteID, - }) - - const { blobs } = await store.list({ - prefix: 'group/', - }) - - expect(blobs).toEqual([ - { etag: 'etag1', key: 'group/key1' }, - { etag: 'etag2', key: 'group/key2' }, - ]) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns an `AsyncIterator` if `paginate: true`', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - next_cursor: 'cursor_2', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag3', - key: 'key3', - size: 3, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?cursor=cursor_2`, - }) - .inject() - - const store = getStore({ - name: 'mystore', - token: apiToken, - siteID, - }) - const result: ListResult = { - blobs: [], - directories: [], - } - - for await (const entry of store.list({ paginate: true })) { - result.blobs.push(...entry.blobs) - result.directories.push(...entry.directories) - } - - expect(result.blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - { etag: 'etag3', key: 'key3' }, - ]) - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - describe('With edge credentials', () => { - test('Lists blobs and handles pagination by default', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - next_cursor: 'cursor_1', - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag3', - key: 'key3', - size: 3, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag4', - key: 'key4', - size: 4, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - next_cursor: 'cursor_2', - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag5', - key: 'key5', - size: 5, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_2`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag6', - key: 'key6', - size: 6, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?prefix=dir2%2F`, - }) - .inject() - - const store = getStore({ - edgeURL, - name: storeName, - token: edgeToken, - siteID, - }) - - const root = await store.list() - - expect(root.blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - { etag: 'etag3', key: 'key3' }, - { etag: 'etag4', key: 'key4' }, - { etag: 'etag5', key: 'key5' }, - ]) - - expect(root.directories).toEqual([]) - - const directory = await store.list({ prefix: 'dir2/' }) - - expect(directory.blobs).toEqual([{ etag: 'etag6', key: 'key6' }]) - expect(directory.directories).toEqual([]) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a `directories` parameter', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: ['dir1'], - next_cursor: 'cursor_1', - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?directories=true`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag3', - key: 'key3', - size: 3, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag4', - key: 'key4', - size: 4, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: ['dir2'], - next_cursor: 'cursor_2', - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?directories=true&cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag5', - key: 'key5', - size: 5, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: ['dir3'], - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?directories=true&cursor=cursor_2`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag6', - key: 'key6', - size: 6, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?prefix=dir2%2F&directories=true`, - }) - .inject() - - const store = getStore({ - edgeURL, - name: storeName, - token: edgeToken, - siteID, - }) - - const root = await store.list({ directories: true }) - - expect(root.blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - { etag: 'etag3', key: 'key3' }, - { etag: 'etag4', key: 'key4' }, - { etag: 'etag5', key: 'key5' }, - ]) - - expect(root.directories).toEqual(['dir1', 'dir2', 'dir3']) - - const directory = await store.list({ directories: true, prefix: 'dir2/' }) - - expect(directory.blobs).toEqual([{ etag: 'etag6', key: 'key6' }]) - expect(directory.directories).toEqual([]) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a `prefix` property', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'group/key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'group/key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?prefix=group%2F`, - }) - .inject() - - const store = getStore({ - edgeURL, - name: storeName, - token: edgeToken, - siteID, - }) - - const { blobs } = await store.list({ - prefix: 'group/', - }) - - expect(blobs).toEqual([ - { etag: 'etag1', key: 'group/key1' }, - { etag: 'etag2', key: 'group/key2' }, - ]) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns an `AsyncIterator` if `paginate: true`', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - next_cursor: 'cursor_2', - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag3', - key: 'key3', - size: 3, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag4', - key: 'key4', - size: 4, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - next_cursor: 'cursor_3', - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_2`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag5', - key: 'key5', - size: 5, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - }), - ), - url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_3`, - }) - .inject() - - const store = getStore({ - edgeURL, - name: storeName, - token: edgeToken, - siteID, - }) - const result: ListResult = { - blobs: [], - directories: [], - } - - for await (const entry of store.list({ paginate: true })) { - result.blobs.push(...entry.blobs) - result.directories.push(...entry.directories) - } - - expect(result.blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - { etag: 'etag3', key: 'key3' }, - { etag: 'etag4', key: 'key4' }, - { etag: 'etag5', key: 'key5' }, - ]) - expect(result.directories).toEqual([]) - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - test('Uses the uncached edge URL if `consistency: "strong"`', async () => { - const uncachedEdgeURL = 'https://uncached-edge.netlify' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - blobs: [ - { - etag: 'etag1', - key: 'key1', - size: 1, - last_modified: '2023-07-18T12:59:06Z', - }, - { - etag: 'etag2', - key: 'key2', - size: 2, - last_modified: '2023-07-18T12:59:06Z', - }, - ], - directories: [], - }), - ), - url: `${uncachedEdgeURL}/${siteID}/site:${storeName}`, - }) - .inject() - - const store = getStore({ - consistency: 'strong', - edgeURL, - name: storeName, - token: edgeToken, - siteID, - uncachedEdgeURL, - }) - - const { blobs, directories } = await store.list() - - expect(blobs).toEqual([ - { etag: 'etag1', key: 'key1' }, - { etag: 'etag2', key: 'key2' }, - ]) - expect(directories).toEqual([]) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Handles missing content automatic pagination', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response('', { status: 404 }), - url: `${edgeURL}/${siteID}/site:${storeName}?prefix=group%2F`, - }) - .inject() - - const store = getStore({ - edgeURL, - name: storeName, - token: edgeToken, - siteID, - }) - - const { blobs } = await store.list({ - prefix: 'group/', - }) - - expect(blobs).toEqual([]) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Handles missing content manual pagination', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response('', { status: 404 }), - url: `${edgeURL}/${siteID}/site:${storeName}`, - }) - .inject() - - const store = getStore({ - edgeURL, - name: storeName, - token: edgeToken, - siteID, - }) - const result: ListResult = { - blobs: [], - directories: [], - } - - for await (const entry of store.list({ paginate: true })) { - result.blobs.push(...entry.blobs) - result.directories.push(...entry.directories) - } - - expect(result.blobs).toEqual([]) - expect(result.directories).toEqual([]) - expect(mockStore.fulfilled).toBeTruthy() - }) -}) diff --git a/packages/blobs/src/main.test.ts b/packages/blobs/src/main.test.ts deleted file mode 100644 index 2004694..0000000 --- a/packages/blobs/src/main.test.ts +++ /dev/null @@ -1,2421 +0,0 @@ -import { Buffer } from 'node:buffer' -import { env, version as nodeVersion } from 'node:process' - -import { MockFetch } from '@netlify/dev-utils' -import { base64Decode } from '@netlify/runtime-utils' -import semver from 'semver' -import { describe, test, expect, beforeAll, afterEach } from 'vitest' - -import { base64Encode, streamToString } from '../test/util.js' - -import { MissingBlobsEnvironmentError } from './environment.js' -import { NF_ERROR, NF_REQUEST_ID } from './headers.js' -import { getDeployStore, getStore, setEnvironmentContext } from './main.js' - -beforeAll(async () => { - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.fetch = nodeFetch.default - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Request = nodeFetch.Request - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Response = nodeFetch.Response - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Headers = nodeFetch.Headers - } -}) - -afterEach(() => { - delete env.NETLIFY_BLOBS_CONTEXT - delete globalThis.netlifyBlobsContext -}) - -const deployID = '6527dfab35be400008332a1d' -const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' -const key = '54321' -const complexKey = 'artist/song' -const value = 'some value' -const apiToken = 'some token' -const signedURL = 'https://signed.url/123456789' -const edgeToken = 'some other token' -const edgeURL = 'https://edge.netlify' - -describe('get', () => { - describe('With API credentials', () => { - test('Reads from the blob store', async () => { - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${complexKey}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const string = await blobs.get(key) - expect(string).toBe(value) - - const stream = await blobs.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - const string2 = await blobs.get(complexKey) - expect(string2).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `null` when the pre-signed URL returns a 404', async () => { - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response('Something went wrong', { status: 404 }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - expect(await blobs.get(key)).toBeNull() - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the API returns a non-200 status code', async () => { - const mockRequestID = '123456789' - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(null, { headers: { [NF_REQUEST_ID]: mockRequestID }, status: 401 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code, ID: ${mockRequestID})`, - ) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when a pre-signed URL returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response('Something went wrong', { status: 401 }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Reads from a store with a legacy namespace', async () => { - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/oldie/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/oldie/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/oldie/${complexKey}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'netlify-internal/legacy-namespace/oldie', - token: apiToken, - siteID, - }) - - const string = await blobs.get(key) - expect(string).toBe(value) - - const stream = await blobs.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - const string2 = await blobs.get(complexKey) - expect(string2).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a string name and an options object as separate parameters', async () => { - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const blobs = getStore('production', { - token: apiToken, - siteID, - }) - - const string = await blobs.get(key) - expect(string).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - describe('Conditional writes', () => { - test('Returns `modified: false` when `onlyIfNew` is true and key exists', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - headers: { 'if-none-match': '*' }, - response: new Response(null, { status: 412 }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfNew: true, - }) - - expect(result.modified).toBe(false) - expect(result.etag).toBeUndefined() - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `modified: true` when `onlyIfNew` is true and key does not exist', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - headers: { 'if-none-match': '*' }, - response: new Response(null, { status: 201, headers: { etag: '"123"' } }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfNew: true, - }) - - expect(result.modified).toBe(true) - expect(result.etag).toBe('"123"') - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `modified: false` when `onlyIfMatch` does not match', async () => { - const etag = 'etag-123' - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - headers: { 'if-match': etag }, - response: new Response(null, { status: 412 }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfMatch: etag, - }) - - expect(result.modified).toBe(false) - expect(result.etag).toBeUndefined() - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `modified: true` when `onlyIfMatch` matches', async () => { - const etag = 'etag-123' - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - headers: { 'if-match': etag }, - response: new Response(null, { status: 200, headers: { etag: '"123"' } }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfMatch: etag, - }) - - expect(result.modified).toBe(true) - expect(result.etag).toBe('"123"') - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - }) - - describe('With edge credentials', () => { - test('Reads from the blob store', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const string = await blobs.get(key) - expect(string).toBe(value) - - const stream = await blobs.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `null` when the edge URL returns a 404', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { status: 404 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - expect(await blobs.get(key)).toBeNull() - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a string name and an options object', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore('production', { - edgeURL, - token: edgeToken, - siteID, - }) - - const string = await blobs.get(key) - expect(string).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when an edge URL returns a non-200 status code', async () => { - const errorDetails = 'Failed to decode token: Token expired' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { headers: { [NF_ERROR]: errorDetails }, status: 401 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await expect(blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error (${errorDetails})`, - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - describe('Conditional writes', () => { - test('Returns `modified: false` when `onlyIfNew` is true and key exists', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${edgeToken}`, 'if-none-match': '*' }, - response: new Response(null, { status: 412 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfNew: true, - }) - - expect(result.modified).toBe(false) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `modified: true` when `onlyIfNew` is true and key does not exist', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${edgeToken}`, 'if-none-match': '*' }, - response: new Response(null, { status: 201, headers: { etag: '"123"' } }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfNew: true, - }) - - expect(result.modified).toBe(true) - expect(result.etag).toBe('"123"') - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `modified: false` when `onlyIfMatch` does not match', async () => { - const etag = 'etag-123' - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${edgeToken}`, 'if-match': etag }, - response: new Response(null, { status: 412 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfMatch: etag, - }) - - expect(result.modified).toBe(false) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `modified: true` when `onlyIfMatch` matches', async () => { - const etag = 'etag-123' - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${edgeToken}`, 'if-match': etag }, - response: new Response(null, { status: 200, headers: { etag: '"123"' } }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const result = await blobs.set(key, value, { - onlyIfMatch: etag, - }) - - expect(result.modified).toBe(true) - expect(result.etag).toBe('"123"') - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws an error when both `onlyIfNew` and `onlyIfMatch` are provided', async () => { - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect( - blobs.set(key, value, { - onlyIfNew: true, - - // @ts-expect-error Testing runtime validation - onlyIfMatch: '"123"', - }), - ).rejects.toThrow( - `The 'onlyIfMatch' and 'onlyIfNew' options are mutually exclusive. Using 'onlyIfMatch' will make the write succeed only if there is an entry for the key with the given content, while 'onlyIfNew' will make the write succeed only if there is no entry for the key.`, - ) - }) - - test('Throws an error when `onlyIfMatch` is not a string', async () => { - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect( - blobs.set(key, value, { - // @ts-expect-error Testing runtime validation - onlyIfMatch: 123, - }), - ).rejects.toThrow(`The 'onlyIfMatch' property expects a string representing an ETag.`) - }) - - test('Throws an error when `onlyIfNew` is not a boolean', async () => { - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect( - blobs.set(key, value, { - // @ts-expect-error Testing runtime validation - onlyIfNew: 'yes', - }), - ).rejects.toThrow( - `The 'onlyIfNew' property expects a boolean indicating whether the write should fail if an entry for the key already exists.`, - ) - }) - }) - - describe('Loads credentials from the environment', () => { - test('From the `NETLIFY_BLOBS_CONTEXT` environment variable', async () => { - const tokens = ['some-token-1', 'another-token-2'] - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${tokens[0]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${tokens[0]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${tokens[1]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${tokens[1]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .inject() - - for (let index = 0; index <= 1; index++) { - const context = { - edgeURL, - siteID, - token: tokens[index], - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const store = getStore('images') - - const string = await store.get(key) - expect(string).toBe(value) - - const stream = await store.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - } - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('From the `netlifyBlobsContext` global variable', async () => { - const tokens = ['some-token-1', 'another-token-2'] - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${tokens[0]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${tokens[0]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${tokens[1]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${tokens[1]}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - .inject() - - for (let index = 0; index <= 1; index++) { - const context1 = { - edgeURL, - siteID, - token: 'not-the-right-token', - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context1)).toString('base64') - - const context2 = { - edgeURL, - siteID, - token: tokens[index], - } - - globalThis.netlifyBlobsContext = Buffer.from(JSON.stringify(context2)).toString('base64') - - const store = getStore('images') - - const string = await store.get(key) - expect(string).toBe(value) - - const stream = await store.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - } - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - }) -}) - -describe('getMetadata', () => { - describe('With API credentials', () => { - test('Reads from the blob store and returns the etag and the metadata object', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .head({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { headers }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const entry = await blobs.getMetadata(key) - expect(entry?.etag).toBe(headers.etag) - expect(entry?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `null` when the API returns a 404', async () => { - const mockStore = new MockFetch() - .head({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 404 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - expect(await blobs.getMetadata(key)).toBeNull() - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the metadata object cannot be parsed', async () => { - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(`{"name": "Netlify", "cool`)}`, - } - const mockStore = new MockFetch() - .head({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { headers }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.getMetadata(key)).rejects.toThrowError( - 'An internal error occurred while trying to retrieve the metadata for an entry. Please try updating to the latest version of the Netlify Blobs client.', - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - describe('With edge credentials', () => { - test('Reads from the blob store and returns the etag and the metadata object', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const headers = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .head({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { headers }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const entry = await blobs.getMetadata(key) - expect(entry?.etag).toBe(headers.etag) - expect(entry?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) -}) - -describe('getWithMetadata', () => { - describe('With API credentials', () => { - test('Reads from the blob store and returns the etag and the metadata object', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const responseHeaders = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response(value, { headers: responseHeaders }), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response(value, { headers: responseHeaders }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const entry1 = await blobs.getWithMetadata(key) - expect(entry1?.data).toBe(value) - expect(entry1?.etag).toBe(responseHeaders.etag) - expect(entry1?.metadata).toEqual(mockMetadata) - - const entry2 = await blobs.getWithMetadata(key, { type: 'stream' }) - expect(await streamToString(entry2?.data as unknown as NodeJS.ReadableStream)).toBe(value) - expect(entry2?.etag).toBe(responseHeaders.etag) - expect(entry2?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns `null` when the pre-signed URL returns a 404', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response('Something went wrong', { status: 404 }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - expect(await blobs.getWithMetadata(key)).toBeNull() - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the metadata object cannot be parsed', async () => { - const responseHeaders = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(`{"name": "Netlify", "cool`)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - response: new Response(value, { headers: responseHeaders }), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.getWithMetadata(key)).rejects.toThrowError( - 'An internal error occurred while trying to retrieve the metadata for an entry. Please try updating to the latest version of the Netlify Blobs client.', - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Supports conditional requests', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const etags = { - right: '"therightetag"', - wrong: '"thewrongetag"', - } - const metadataHeaders = { - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: `${signedURL}b` })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - headers: { 'if-none-match': etags.wrong }, - response: new Response(value, { headers: { ...metadataHeaders, etag: etags.right }, status: 200 }), - url: `${signedURL}b`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: `${signedURL}a` })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .get({ - headers: { 'if-none-match': etags.right }, - response: new Response(null, { headers: { ...metadataHeaders, etag: etags.right }, status: 304 }), - url: `${signedURL}a`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const staleEntry = await blobs.getWithMetadata(key, { etag: etags.wrong }) - expect(staleEntry?.data).toBe(value) - expect(staleEntry?.etag).toBe(etags.right) - expect(staleEntry?.metadata).toEqual(mockMetadata) - - const freshEntry = await blobs.getWithMetadata(key, { etag: etags.right, type: 'text' }) - expect(freshEntry?.data).toBe(null) - expect(freshEntry?.etag).toBe(etags.right) - expect(freshEntry?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - describe('With edge credentials', () => { - test('Reads from the blob store and returns the etag and the metadata object', async () => { - const mockMetadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const responseHeaders = { - etag: '123456789', - 'x-amz-meta-user': `b64;${base64Encode(mockMetadata)}`, - } - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value, { headers: responseHeaders }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(value, { headers: responseHeaders }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const entry1 = await blobs.getWithMetadata(key) - expect(entry1?.data).toBe(value) - expect(entry1?.etag).toBe(responseHeaders.etag) - expect(entry1?.metadata).toEqual(mockMetadata) - - const entry2 = await blobs.getWithMetadata(key, { type: 'stream' }) - expect(await streamToString(entry2?.data as unknown as NodeJS.ReadableStream)).toBe(value) - expect(entry2?.etag).toBe(responseHeaders.etag) - expect(entry2?.metadata).toEqual(mockMetadata) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) -}) - -describe('set', () => { - describe('With API credentials', () => { - test('Writes to the blob store', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null), - url: signedURL, - }) - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${complexKey}`, - }) - .put({ - body: value, - headers: { 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await blobs.set(key, value) - await blobs.set(complexKey, value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a `metadata` parameter', async () => { - const metadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const encodedMetadata = `b64;${Buffer.from(JSON.stringify(metadata)).toString('base64')}` - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}`, 'netlify-blobs-metadata': encodedMetadata }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { - 'cache-control': 'max-age=0, stale-while-revalidate=60', - 'x-amz-meta-user': encodedMetadata, - }, - response: new Response(null), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await blobs.set(key, value, { metadata }) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the API returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 401 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.set(key, 'value')).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the key fails validation', async () => { - const mockStore = new MockFetch().inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.set('', 'value')).rejects.toThrowError('Blob key must not be empty.') - await expect(blobs.set('/key', 'value')).rejects.toThrowError('Blob key must not start with forward slash (/).') - await expect(blobs.set('a'.repeat(801), 'value')).rejects.toThrowError( - 'Blob key must be a sequence of Unicode characters whose UTF-8 encoding is at most 600 bytes long.', - ) - }) - - test('Retries failed operations', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { - 'cache-control': 'max-age=0, stale-while-revalidate=60', - }, - response: new Response(null, { status: 500 }), - url: signedURL, - }) - .put({ - body: value, - headers: { - 'cache-control': 'max-age=0, stale-while-revalidate=60', - }, - response: new Error('Some network problem'), - url: signedURL, - }) - .put({ - body: value, - headers: { - 'cache-control': 'max-age=0, stale-while-revalidate=60', - }, - response: new Response(null, { headers: { 'X-RateLimit-Reset': '10' }, status: 429 }), - url: signedURL, - }) - .put({ - body: value, - headers: { - 'cache-control': 'max-age=0, stale-while-revalidate=60', - }, - response: new Response(null), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await blobs.set(key, value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - describe('With edge credentials', () => { - test('Writes to the blob store', async () => { - const mockStore = new MockFetch() - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null), - url: `${edgeURL}/${siteID}/site:production/${complexKey}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await blobs.set(key, value) - await blobs.set(complexKey, value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the edge URL returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null, { status: 401 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await expect(blobs.set(key, value)).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Retries failed operations', async () => { - const mockStore = new MockFetch() - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null, { status: 500 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Error('Some network problem'), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null, { headers: { 'X-RateLimit-Reset': '10' }, status: 429 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .put({ - body: value, - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await blobs.set(key, value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) -}) - -describe('setJSON', () => { - describe('With API credentials', () => { - test('Writes to the blob store', async () => { - const mockStore = new MockFetch() - .put({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .put({ - body: JSON.stringify({ value }), - headers: { - 'cache-control': 'max-age=0, stale-while-revalidate=60', - }, - response: new Response(null), - url: signedURL, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await blobs.setJSON(key, { value }) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - describe('With edge credentials', () => { - test('Writes to the blob store', async () => { - const mockStore = new MockFetch() - .put({ - body: JSON.stringify({ value }), - headers: { authorization: `Bearer ${edgeToken}`, 'cache-control': 'max-age=0, stale-while-revalidate=60' }, - response: new Response(null), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await blobs.setJSON(key, { value }) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Accepts a `metadata` parameter', async () => { - const metadata = { - name: 'Netlify', - cool: true, - functions: ['edge', 'serverless'], - } - const encodedMetadata = `b64;${Buffer.from(JSON.stringify(metadata)).toString('base64')}` - const mockStore = new MockFetch() - .put({ - body: JSON.stringify({ value }), - headers: { - authorization: `Bearer ${edgeToken}`, - 'cache-control': 'max-age=0, stale-while-revalidate=60', - 'x-amz-meta-user': encodedMetadata, - }, - response: new Response(null), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await blobs.setJSON(key, { value }, { metadata }) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the `metadata` parameter is above the size limit', async () => { - const metadata = { - name: 'Netlify'.repeat(1000), - } - const mockStore = new MockFetch().inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await expect(blobs.setJSON(key, { value }, { metadata })).rejects.toThrowError( - 'Metadata object exceeds the maximum size', - ) - }) - }) -}) - -describe('delete', () => { - describe('With API credentials', () => { - test('Deletes from the blob store', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 204 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 204 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${complexKey}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await blobs.delete(key) - await blobs.delete(complexKey) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Does not throw when the blob does not exist', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 404 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await blobs.delete(key) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the API returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 401 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.delete(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - describe('With edge credentials', () => { - test('Deletes from the blob store', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { status: 204 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await blobs.delete(key) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Does not throw when the blob does not exist', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { status: 404 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await blobs.delete(key) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws when the edge URL returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { status: 401 }), - url: `${edgeURL}/${siteID}/site:production/${key}`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await expect(blobs.delete(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) -}) - -describe('deleteAll', () => { - describe('With API credentials', () => { - test('Deletes all blobs from the store', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: Response.json({ blobs_deleted: 3, has_more: false }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - const res = await blobs.deleteAll() - - expect(mockStore.fulfilled).toBeTruthy() - expect(res.deletedBlobs).toBe(3) - }) - - test('Throws when the API returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(null, { status: 401 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production`, - }) - .inject() - - const blobs = getStore({ - name: 'production', - token: apiToken, - siteID, - }) - - await expect(blobs.deleteAll()).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Works with legacy namespaced stores', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${apiToken}` }, - response: Response.json({ blobs_deleted: 3, has_more: false }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/oldie`, - }) - .inject() - - const blobs = getStore({ - name: 'netlify-internal/legacy-namespace/oldie', - token: apiToken, - siteID, - }) - - const res = await blobs.deleteAll() - - expect(mockStore.fulfilled).toBeTruthy() - expect(res.deletedBlobs).toBe(3) - }) - }) - - describe('With edge credentials', () => { - test('Deletes all blobs from the store', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: Response.json({ blobs_deleted: 3, has_more: false }), - url: `${edgeURL}/${siteID}/site:production`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const res = await blobs.deleteAll() - - expect(mockStore.fulfilled).toBeTruthy() - expect(res.deletedBlobs).toBe(3) - }) - - test('Throws when the edge URL returns a non-200 status code', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { status: 401 }), - url: `${edgeURL}/${siteID}/site:production`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - await expect(blobs.deleteAll()).rejects.toThrowError( - `Netlify Blobs has generated an internal error (401 status code)`, - ) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Handles paginated deletion with multiple batches', async () => { - const mockStore = new MockFetch() - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: Response.json({ blobs_deleted: 100, has_more: true }), - url: `${edgeURL}/${siteID}/site:production`, - }) - .delete({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: Response.json({ blobs_deleted: 50, has_more: false }), - url: `${edgeURL}/${siteID}/site:production`, - }) - .inject() - - const blobs = getStore({ - edgeURL, - name: 'production', - token: edgeToken, - siteID, - }) - - const res = await blobs.deleteAll() - - expect(mockStore.fulfilled).toBeTruthy() - expect(res.deletedBlobs).toBe(150) - }) - }) -}) - -describe('Deploy scope', () => { - test('Returns a deploy-scoped store if the `deployID` parameter is supplied and the environment context is present', async () => { - const mockToken = 'some-token' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - const context = { - edgeURL, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getStore({ deployID }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns a deploy-scoped store if the `deployID` parameter is supplied and the environment context is not present', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const deployStore = getStore({ deployID, siteID, token: apiToken }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns a deploy-scoped store if the `getDeployStore` method is called and the environment context is present', async () => { - const mockToken = 'some-token' - const mockRegion = 'us-east-2' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - const context = { - deployID, - edgeURL, - primaryRegion: mockRegion, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore() - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns a deploy-scoped store if the `getDeployStore` method is called and the environment context is not present', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=auto`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=auto`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const deployStore = getDeployStore({ deployID, siteID, token: apiToken }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns a named deploy-scoped store if `getDeployStore` receives a string parameter', async () => { - const mockRegion = 'us-east-1' - const mockToken = 'some-token' - const mockStoreName = 'my-store' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}:${mockStoreName}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}:${mockStoreName}/${key}`, - }) - .inject() - - const context = { - deployID, - edgeURL, - primaryRegion: mockRegion, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore(mockStoreName) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns a named deploy-scoped store if `getDeployStore` receives an object with a `name` property', async () => { - const mockRegion = 'us-east-1' - const mockToken = 'some-token' - const mockStoreName = 'my-store' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}:${mockStoreName}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}:${mockStoreName}/${key}`, - }) - .inject() - - const context = { - deployID, - edgeURL, - primaryRegion: mockRegion, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore({ name: mockStoreName }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Returns a named deploy-scoped store if `getDeployStore` receives a string name and an options object', async () => { - const mockStoreName = 'my-store' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}:${mockStoreName}/${key}?region=auto`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const deployStore = getDeployStore(mockStoreName, { deployID, siteID, token: apiToken }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws if the deploy ID fails validation', async () => { - const mockRegion = 'us-east-2' - const mockToken = 'some-token' - const mockStore = new MockFetch().inject() - const longDeployID = 'd'.repeat(80) - - expect(() => getDeployStore({ deployID: 'deploy/ID', siteID, region: mockRegion, token: apiToken })).toThrowError( - `'deploy/ID' is not a valid Netlify deploy ID`, - ) - expect(() => getStore({ deployID: 'deploy/ID', siteID, token: apiToken })).toThrowError( - `'deploy/ID' is not a valid Netlify deploy ID`, - ) - expect(() => getStore({ deployID: longDeployID, siteID, token: apiToken })).toThrowError( - `'${longDeployID}' is not a valid Netlify deploy ID`, - ) - - const context = { - deployID: 'uhoh!', - edgeURL, - primaryRegion: mockRegion, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - expect(() => getDeployStore()).toThrowError(`'uhoh!' is not a valid Netlify deploy ID`) - }) -}) - -describe('Custom `fetch`', () => { - test('Uses a custom implementation of `fetch` if the `fetch` parameter is supplied', async () => { - globalThis.fetch = () => { - throw new Error('I should not be called') - } - - const mockToken = 'some-token' - const mockStore = new MockFetch().get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/${siteID}/site:images/${key}`, - }) - const context = { - edgeURL, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const store = getStore({ fetch: mockStore.fetch, name: 'images' }) - - const string = await store.get(key) - expect(string).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) -}) - -describe(`getStore`, () => { - test('Throws when the instance is missing required configuration properties', async () => { - const { fetch } = new MockFetch() - - globalThis.fetch = fetch - - expect(() => getStore('production')).toThrowError(MissingBlobsEnvironmentError) - expect(() => - getStore({ - name: 'production', - token: apiToken, - siteID: '', - }), - ).toThrowError(MissingBlobsEnvironmentError) - }) - - test('Throws when the name of the store is not provided', async () => { - const { fetch } = new MockFetch() - - globalThis.fetch = fetch - - // @ts-expect-error Ignoring types, which expect an argument - expect(() => getStore()).toThrowError( - 'The `getStore` method requires the name of the store as a string or as the `name` property of an options object', - ) - - expect(() => - getStore({ - token: apiToken, - siteID, - }), - ).toThrowError( - 'The `getStore` method requires the name of the store as a string or as the `name` property of an options object', - ) - }) - - test('Throws when the name of the store fails validation', async () => { - const { fetch } = new MockFetch() - - globalThis.fetch = fetch - - expect(() => - getStore({ - name: 'some/store', - token: apiToken, - siteID, - }), - ).toThrowError(`Store name must not contain forward slashes (/).`) - - expect(() => - getStore({ - name: 'a'.repeat(70), - token: apiToken, - siteID, - }), - ).toThrowError(`Store name must be a sequence of Unicode characters whose UTF-8 encoding is at most 64 bytes long.`) - - const context = { - siteID, - token: apiToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - expect(() => getStore('some/store')).toThrowError('Store name must not contain forward slashes (/).') - }) - - test('Throws when there is no `fetch` implementation available', async () => { - // @ts-expect-error Assigning a value that doesn't match the type. - globalThis.fetch = undefined - - const context = { - siteID, - token: apiToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - expect(() => getStore('production')).toThrowError( - 'Netlify Blobs could not find a `fetch` client in the global scope. You can either update your runtime to a version that includes `fetch` (like Node.js 18.0.0 or above), or you can supply your own implementation using the `fetch` property.', - ) - }) - - test('Uses explicit siteID and token from options instead of context values', async () => { - const contextSiteID = 'context-site-id' - const contextToken = 'context-token' - const explicitSiteID = 'explicit-site-id' - const explicitToken = 'explicit-token' - - const mockStore = new MockFetch() - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${explicitToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${explicitSiteID}/site:production/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${explicitToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${explicitSiteID}/site:production/${key}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const context = { - siteID: contextSiteID, - token: contextToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const store1 = getStore({ - name: 'production', - siteID: explicitSiteID, - token: explicitToken, - }) - expect(await store1.get(key)).toBe(value) - - const store2 = getStore('production', { - siteID: explicitSiteID, - token: explicitToken, - }) - expect(await store2.get(key)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) -}) - -describe('Region configuration in deploy-scoped stores', () => { - describe('Without a `region` option', () => { - test('The client sends a `region=auto` parameter to API calls', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=auto`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=auto`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const deployStore = getDeployStore({ deployID, siteID, token: apiToken }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('The client sends the region configured in the context to edge calls', async () => { - const mockRegion = 'us-east-2' - const mockToken = 'some-token' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - const context = { - edgeURL, - deployID, - siteID, - primaryRegion: mockRegion, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore() - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Throws an error if using the edge URL and no region is configured in the context', async () => { - const mockRegion = 'us-east-2' - const mockToken = 'some-token' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - expect(() => getDeployStore({ deployID, edgeURL, siteID, token: mockToken })).toThrowError() - expect(mockStore.fulfilled).toBeFalsy() - }) - }) - - describe('With a `region` option', () => { - test('The client sends that region to API calls', async () => { - const mockRegion = 'us-east-1' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=${mockRegion}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=${mockRegion}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const context = { - deployID, - siteID, - token: apiToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore({ region: mockRegion }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('The client sends that region to API calls, even if a different region is present in the context', async () => { - const mockRegion = 'us-east-1' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=${mockRegion}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=${mockRegion}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const context = { - deployID, - siteID, - primaryRegion: 'us-east-2', - token: apiToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore({ region: mockRegion }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('The client throws an error if the region supplied is not supported', async () => { - const mockRegion = 'us-east-1' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=${mockRegion}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ url: signedURL })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}?region=${mockRegion}`, - }) - .get({ - response: new Response(value), - url: signedURL, - }) - .inject() - - const context = { - deployID, - siteID, - primaryRegion: 'us-east-2', - token: apiToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - // @ts-expect-error Knowingly supplying an invalid value to `region`. - expect(() => getDeployStore({ deployID, edgeURL, siteID, region: 'eu-west-1' })).toThrowError() - expect(mockStore.fulfilled).toBeFalsy() - }) - - test('The client sends that region to edge calls', async () => { - const mockRegion = 'us-east-2' - const mockToken = 'some-token' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - const context = { - deployID, - edgeURL, - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore({ region: mockRegion }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('The client sends that region to edge calls, even if a different region is set in the context', async () => { - const mockRegion = 'us-east-2' - const mockToken = 'some-token' - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .get({ - headers: { authorization: `Bearer ${mockToken}` }, - response: new Response(value), - url: `${edgeURL}/region:${mockRegion}/${siteID}/deploy:${deployID}/${key}`, - }) - .inject() - - const context = { - deployID, - edgeURL, - primaryRegion: 'us-east-1', - siteID, - token: mockToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const deployStore = getDeployStore({ region: mockRegion }) - - const string = await deployStore.get(key) - expect(string).toBe(value) - - const stream = await deployStore.get(key, { type: 'stream' }) - expect(await streamToString(stream as unknown as NodeJS.ReadableStream)).toBe(value) - - expect(mockStore.fulfilled).toBeTruthy() - }) - }) -}) - -describe('setEnvironmentContext', () => { - test('Injects the context object into the environment', () => { - expect(env.NETLIFY_BLOBS_CONTEXT).toBeUndefined() - - setEnvironmentContext({ - deployID, - primaryRegion: 'us-east-1', - siteID, - token: apiToken, - }) - - expect(env.NETLIFY_BLOBS_CONTEXT).toBeTypeOf('string') - - const context = JSON.parse(base64Decode(env.NETLIFY_BLOBS_CONTEXT as string)) - - expect(context.deployID).toBe(deployID) - expect(context.primaryRegion).toBe('us-east-1') - expect(context.siteID).toBe(siteID) - expect(context.token).toBe(apiToken) - }) -}) diff --git a/packages/blobs/src/main.ts b/packages/blobs/src/main.ts deleted file mode 100644 index 667e736..0000000 --- a/packages/blobs/src/main.ts +++ /dev/null @@ -1,15 +0,0 @@ -export { type EnvironmentContext, setEnvironmentContext } from './environment.ts' -export { connectLambda } from './lambda_compat.ts' -export { getDeployStore, getStore, type GetStoreOptions, type GetDeployStoreOptions } from './store_factory.ts' -export { listStores } from './store_list.ts' -export type { - Store, - StoreOptions, - GetWithMetadataOptions, - GetWithMetadataResult, - ListOptions, - ListResultBlob, - SetOptions, - BlobResponseType, - DeleteStoreResult, -} from './store.ts' diff --git a/packages/blobs/src/metadata.ts b/packages/blobs/src/metadata.ts deleted file mode 100644 index eac065a..0000000 --- a/packages/blobs/src/metadata.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { base64Decode, base64Encode } from '@netlify/runtime-utils' - -export type Metadata = Record - -const BASE64_PREFIX = 'b64;' -export const METADATA_HEADER_INTERNAL = 'x-amz-meta-user' -export const METADATA_HEADER_EXTERNAL = 'netlify-blobs-metadata' -const METADATA_MAX_SIZE = 2 * 1024 - -export const encodeMetadata = (metadata?: Metadata) => { - if (!metadata) { - return null - } - - const encodedObject = base64Encode(JSON.stringify(metadata)) - const payload = `b64;${encodedObject}` - - if (METADATA_HEADER_EXTERNAL.length + payload.length > METADATA_MAX_SIZE) { - throw new Error('Metadata object exceeds the maximum size') - } - - return payload -} - -export const decodeMetadata = (header: string | null): Metadata => { - if (!header?.startsWith(BASE64_PREFIX)) { - return {} - } - - const encodedData = header.slice(BASE64_PREFIX.length) - const decodedData = base64Decode(encodedData) - const metadata = JSON.parse(decodedData) - - return metadata -} - -export const getMetadataFromResponse = (response: Response) => { - if (!response.headers) { - return {} - } - - // If metadata is coming from the API, it will be under the external header. - // If it's coming from the edge, it will be under the internal header. - const value = response.headers.get(METADATA_HEADER_EXTERNAL) || response.headers.get(METADATA_HEADER_INTERNAL) - - try { - return decodeMetadata(value) - } catch { - throw new Error( - 'An internal error occurred while trying to retrieve the metadata for an entry. Please try updating to the latest version of the Netlify Blobs client.', - ) - } -} diff --git a/packages/blobs/src/region.ts b/packages/blobs/src/region.ts deleted file mode 100644 index 14a7bcb..0000000 --- a/packages/blobs/src/region.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const REGION_AUTO = 'auto' - -const regions = { - 'us-east-1': true, - 'us-east-2': true, - 'eu-central-1': true, - 'ap-southeast-1': true, - 'ap-southeast-2': true, -} - -export type Region = keyof typeof regions - -export const isValidRegion = (input: string): input is Region => Object.keys(regions).includes(input) - -export class InvalidBlobsRegionError extends Error { - constructor(region: string) { - super( - `${region} is not a supported Netlify Blobs region. Supported values are: ${Object.keys(regions).join(', ')}.`, - ) - - this.name = 'InvalidBlobsRegionError' - } -} diff --git a/packages/blobs/src/retry.ts b/packages/blobs/src/retry.ts deleted file mode 100644 index 174aa03..0000000 --- a/packages/blobs/src/retry.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { getEnvironment } from '@netlify/runtime-utils' - -import type { Fetcher } from './types.ts' - -const DEFAULT_RETRY_DELAY = getEnvironment().get('NODE_ENV') === 'test' ? 1 : 5000 -const MIN_RETRY_DELAY = 1000 -const MAX_RETRY = 5 -const RATE_LIMIT_HEADER = 'X-RateLimit-Reset' - -export const fetchAndRetry = async ( - fetch: Fetcher, - url: string, - options: RequestInit, - attemptsLeft = MAX_RETRY, -): ReturnType => { - try { - const res = await fetch(url, options) - - if (attemptsLeft > 0 && (res.status === 429 || res.status >= 500)) { - const delay = getDelay(res.headers.get(RATE_LIMIT_HEADER)) - - await sleep(delay) - - return fetchAndRetry(fetch, url, options, attemptsLeft - 1) - } - - return res - } catch (error) { - if (attemptsLeft === 0) { - throw error - } - - const delay = getDelay() - - await sleep(delay) - - return fetchAndRetry(fetch, url, options, attemptsLeft - 1) - } -} - -const getDelay = (rateLimitReset?: string | null) => { - if (!rateLimitReset) { - return DEFAULT_RETRY_DELAY - } - - return Math.max(Number(rateLimitReset) * 1000 - Date.now(), MIN_RETRY_DELAY) -} - -const sleep = (ms: number) => - new Promise((resolve) => { - setTimeout(resolve, ms) - }) diff --git a/packages/blobs/src/server.test.ts b/packages/blobs/src/server.test.ts deleted file mode 100644 index 2d0196c..0000000 --- a/packages/blobs/src/server.test.ts +++ /dev/null @@ -1,606 +0,0 @@ -import { Buffer } from 'node:buffer' -import { promises as fs } from 'node:fs' -import { env, version as nodeVersion } from 'node:process' - -import semver from 'semver' -import tmp from 'tmp-promise' -import { test, expect, beforeAll, afterEach } from 'vitest' - -import { getDeployStore, getStore, listStores } from './main.js' -import { BlobsServer } from './server.js' - -beforeAll(async () => { - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.fetch = nodeFetch.default - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Request = nodeFetch.Request - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Response = nodeFetch.Response - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Headers = nodeFetch.Headers - } -}) - -afterEach(() => { - delete env.NETLIFY_BLOBS_CONTEXT -}) - -const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' -const token = 'my-very-secret-token' - -test('Reads and writes from the file system', async () => { - const metadata = { - features: { - blobs: true, - functions: true, - }, - name: 'Netlify', - } - - // Store #1: Edge access - const server1Ops: { type: string; url: string }[] = [] - const directory1 = await tmp.dir() - const server1 = new BlobsServer({ - directory: directory1.path, - onRequest: ({ type, url }) => server1Ops.push({ type, url }), - token, - }) - - const { port: port1 } = await server1.start() - const store1 = getStore({ - edgeURL: `http://localhost:${port1}`, - name: 'mystore1', - token, - siteID, - }) - - // Store #2: API access - const directory2 = await tmp.dir() - const server2 = new BlobsServer({ - directory: directory2.path, - token, - }) - const { port: port2 } = await server2.start() - const store2 = getStore({ - apiURL: `http://localhost:${port2}`, - name: 'mystore2', - token, - siteID, - }) - - for (const store of [store1, store2]) { - const list1 = await store.list() - expect(list1.blobs).toEqual([]) - expect(list1.directories).toEqual([]) - - await store.set('simple-key', 'value 1') - expect(await store.get('simple-key')).toBe('value 1') - - await store.set('simple-key', 'value 2', { metadata }) - expect(await store.get('simple-key')).toBe('value 2') - - const list2 = await store.list() - expect(list2.blobs.length).toBe(1) - expect(list2.blobs[0].key).toBe('simple-key') - expect(list2.directories).toEqual([]) - - await store.set('parent/child', 'value 3') - expect(await store.get('parent/child')).toBe('value 3') - expect(await store.get('parent')).toBe(null) - - const entry = await store.getWithMetadata('simple-key') - expect(entry?.metadata).toEqual(metadata) - - const entryMetadata = await store.getMetadata('simple-key') - expect(entryMetadata?.metadata).toEqual(metadata) - - const childEntryMetdata = await store.getMetadata('parent/child') - expect(childEntryMetdata?.metadata).toEqual({}) - - expect(await store.getWithMetadata('does-not-exist')).toBe(null) - expect(await store.getMetadata('does-not-exist')).toBe(null) - - await store.delete('simple-key') - expect(await store.get('simple-key')).toBe(null) - expect(await store.getMetadata('simple-key')).toBe(null) - expect(await store.getWithMetadata('simple-key')).toBe(null) - - const list3 = await store.list() - expect(list3.blobs.length).toBe(1) - expect(list3.blobs[0].key).toBe('parent/child') - expect(list3.directories).toEqual([]) - } - - const urls = server1Ops.map(({ url }) => url) - - expect(urls.every((url) => url.startsWith(`/${siteID}/`))).toBeTruthy() - - const operations = server1Ops.map(({ type }) => type) - - expect(operations).toEqual([ - 'list', - 'set', - 'get', - 'set', - 'get', - 'list', - 'set', - 'get', - 'get', - 'get', - 'getMetadata', - 'getMetadata', - 'get', - 'getMetadata', - 'delete', - 'get', - 'getMetadata', - 'get', - 'list', - ]) - - await server1.stop() - await fs.rm(directory1.path, { force: true, recursive: true }) - - await server2.stop() - await fs.rm(directory2.path, { force: true, recursive: true }) -}) - -test('Works with weird keys -- valid blob keys, tricky in filesystems', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - const store = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'store', - token, - siteID, - }) - - // valid as keys and store names - const pipes = 'valid|key' - const question = 'key?' - const glob = '*hehe*' - const con = 'CON' - const emoji = '🐰' - const angles = '<>' - // valid only as keys - const slashes = 'a///b' - const namespace = 'name:space' - for (const key of [pipes, question, glob, con, angles, emoji, slashes, namespace]) { - try { - await store.set(key, 'value') - expect(await store.get(key)).toBe('value') - } catch (error) { - console.warn(`couldn't set valid key of "${key}"`) - throw error - } - } - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('Separates keys from different stores', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - - const store1 = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'mystore1', - token, - siteID, - }) - const store2 = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'mystore2', - token, - siteID, - }) - const key = 'my-key' - - await store1.set(key, 'value 1 for store 1') - await store2.set(key, 'value 1 for store 2') - - expect(await store1.get(key)).toBe('value 1 for store 1') - expect(await store2.get(key)).toBe('value 1 for store 2') - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('If a token is set, rejects any requests with an invalid `authorization` header', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - const blobs = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'mystore', - token: 'another token', - siteID, - }) - - await expect(blobs.get('some-key')).rejects.toThrowError( - 'Netlify Blobs has generated an internal error (403 status code)', - ) - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('Lists entries', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - const blobs = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'mystore', - token, - siteID, - }) - const songs: Record = { - 'coldplay/parachutes/shiver': "I'll always be waiting for you", - 'coldplay/parachutes/spies': 'And the spies came out of the water', - 'coldplay/parachutes/trouble': 'And I:I never meant to cause you trouble', - 'coldplay/a-rush-of-blood-to-the-head/politik': 'Give me heart and give me soul', - 'coldplay/a-rush-of-blood-to-the-head/in-my-place': 'How long must you wait for it?', - 'coldplay/a-rush-of-blood-to-the-head/the-scientist': 'Questions of science, science and progress', - 'phoenix/united/too-young': "Oh rainfalls and hard times coming they won't leave me tonight", - 'phoenix/united/party-time': 'Summertime is gone', - 'phoenix/ti-amo/j-boy': 'Something in the middle of the side of the store', - 'phoenix/ti-amo/fleur-de-lys': 'No rest till I get to you, no rest till I get to you', - } - - for (const title in songs) { - await blobs.set(title, songs[title]) - } - - const allSongs = await blobs.list() - - for (const title in songs) { - const match = allSongs.blobs.find((blob) => blob.key === title) - - expect(match).toBeTruthy() - } - - const coldplaySongs = await blobs.list({ prefix: 'coldplay/' }) - - for (const title in songs) { - if (!title.startsWith('coldplay/')) { - continue - } - - const match = coldplaySongs.blobs.find((blob) => blob.key === title) - - expect(match).toBeTruthy() - } - - const parachutesSongs = await blobs.list({ prefix: 'coldplay/parachutes/' }) - - for (const title in songs) { - if (!title.startsWith('coldplay/parachutes/')) { - continue - } - - const match = parachutesSongs.blobs.find((blob) => blob.key === title) - - expect(match).toBeTruthy() - } - - const fooFightersSongs = await blobs.list({ prefix: 'foo-fighters/' }) - - expect(fooFightersSongs.blobs).toEqual([]) - - const artists = await blobs.list({ directories: true }) - - expect(artists.blobs).toEqual([]) - expect(artists.directories).toEqual(['coldplay', 'phoenix']) - - const coldplayAlbums = await blobs.list({ directories: true, prefix: 'coldplay/' }) - - expect(coldplayAlbums.blobs).toEqual([]) - expect(coldplayAlbums.directories).toEqual(['coldplay/a-rush-of-blood-to-the-head', 'coldplay/parachutes']) - - const parachutesSongs2 = await blobs.list({ directories: true, prefix: 'coldplay/parachutes/' }) - - for (const title in songs) { - if (!title.startsWith('coldplay/parachutes/')) { - continue - } - - const match = parachutesSongs2.blobs.find((blob) => blob.key === title) - - expect(match).toBeTruthy() - } - - expect(parachutesSongs2.directories).toEqual([]) -}) - -test('Works with a deploy-scoped store', async () => { - const deployID = '655f77a1b48f470008e5879a' - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - - const store = getDeployStore({ - deployID, - edgeURL: `http://localhost:${port}`, - region: 'us-east-1', - token, - siteID, - }) - const key = 'my-key' - - await store.set(key, 'value 1 for store 1') - - expect(await store.get(key)).toBe('value 1 for store 1') - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('Lists site stores', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - - const store1 = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'coldplay', - token, - siteID, - }) - - await store1.set('parachutes/shiver', "I'll always be waiting for you") - await store1.set('parachutes/spies', 'And the spies came out of the water') - await store1.set('parachutes/trouble', 'And I:I never meant to cause you trouble') - await store1.set('a-rush-of-blood-to-the-head/politik', 'Give me heart and give me soul') - await store1.set('a-rush-of-blood-to-the-head/in-my-place', 'How long must you wait for it?') - await store1.set('a-rush-of-blood-to-the-head/the-scientist', 'Questions of science, science and progress') - - const store2 = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'phoenix', - token, - siteID, - }) - - await store2.set('united/too-young', "Oh rainfalls and hard times coming they won't leave me tonight") - await store2.set('united/party-time', 'Summertime is gone') - await store2.set('ti-amo/j-boy', 'Something in the middle of the side of the store') - await store2.set('ti-amo/fleur-de-lys', 'No rest till I get to you, no rest till I get to you') - - const store3 = getDeployStore({ - deployID: '655f77a1b48f470008e5879a', - edgeURL: `http://localhost:${port}`, - region: 'us-east-1', - token, - siteID, - }) - - await store3.set('not-a-song', "I'm a deploy, not a song") - - const { stores } = await listStores({ - edgeURL: `http://localhost:${port}`, - token, - siteID, - }) - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) - - expect(stores).toStrictEqual(['coldplay', 'phoenix']) -}) - -test('Returns a signed URL or the blob directly based on the request parameters', async () => { - const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' - const token = 'some token' - const value = 'value 1' - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - - const { port } = await server.start() - const store = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'my-store', - token, - siteID, - }) - - await store.set('key-1', value) - - // When reading through a legacy API endpoint, we should get a signed URL. - const res1 = await fetch(`http://localhost:${port}/api/v1/sites/${siteID}/blobs/key-1?context=site:my-store`, { - headers: { - authorization: `Bearer ${token}`, - }, - }) - const { url: url1 } = await res1.json() - const data1 = await fetch(url1) - - expect(await data1.text()).toBe(value) - - // When reading through a new API endpoint, we should get the blob data by - // default. - const res2 = await fetch(`http://localhost:${port}/api/v1/blobs/${siteID}/site:my-store/key-1`, { - headers: { - authorization: `Bearer ${token}`, - }, - }) - expect(await res2.text()).toBe(value) - - // When reading through a new API endpoint and requesting a signed URL, we - // should get one. - const res3 = await fetch(`http://localhost:${port}/api/v1/blobs/${siteID}/site:my-store/key-1`, { - headers: { - accept: 'application/json;type=signed-url', - authorization: `Bearer ${token}`, - }, - }) - const { url: url3 } = await res3.json() - const data3 = await fetch(url3) - - expect(await data3.text()).toBe(value) - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('Accepts deploy-scoped stores with the region defined in the context', async () => { - const deployID = '655f77a1b48f470008e5879a' - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - - const context = { - deployID, - edgeURL: `http://localhost:${port}`, - primaryRegion: 'us-east-1', - siteID, - token, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const store = getDeployStore() - const key = 'my-key' - const value = 'hello from a deploy store' - - await store.set(key, value) - - expect(await store.get(key)).toBe(value) - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('Handles conditional writes', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - const deployID = '655f77a1b48f470008e5879a' - const key = 'conditional-key' - const value1 = 'value 1' - const value2 = 'value 2' - const value3 = 'value 3' - - const context = { - deployID, - edgeURL: `http://localhost:${port}`, - primaryRegion: 'us-east-1', - siteID, - token, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const store1 = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'my-store', - token, - siteID, - }) - - const res1 = await store1.set(key, value1, { onlyIfNew: true }) - - expect(res1.modified).toBe(true) - expect(await store1.get(key)).toBe(value1) - - const res2 = await store1.set(key, value2, { onlyIfNew: true }) - - expect(res2.modified).toBe(false) - expect(await store1.get(key)).toBe(value1) - - const res3 = await store1.set(key, value3, { onlyIfMatch: `"wrong-etag"` }) - expect(res3.modified).toBe(false) - expect(await store1.get(key)).toBe(value1) - - const res4 = await store1.set(key, value3, { onlyIfMatch: res1.etag }) - expect(res4.modified).toBe(true) - expect(await store1.get(key)).toBe(value3) - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) - -test('Deletes all blobs from a store', async () => { - const directory = await tmp.dir() - const server = new BlobsServer({ - directory: directory.path, - token, - }) - const { port } = await server.start() - const store = getStore({ - edgeURL: `http://localhost:${port}`, - name: 'my-store', - token, - siteID, - }) - - const metadata = { - name: 'test-metadata', - } - - // Add multiple blobs to the store - await store.set('key1', 'value 1') - await store.set('key2', 'value 2', { metadata }) - await store.set('parent/child', 'value 3') - await store.set('parent/another/nested', 'value 4') - - // Verify blobs exist - const list1 = await store.list() - expect(list1.blobs.length).toBe(4) - - // Verify metadata exists - const entry = await store.getMetadata('key2') - expect(entry?.metadata).toEqual(metadata) - - const deleteResult1 = await store.deleteAll() - expect(deleteResult1.deletedBlobs).toBe(4) - - const list2 = await store.list() - expect(list2.blobs.length).toBe(0) - - const deleteResult2 = await store.deleteAll() - expect(deleteResult2.deletedBlobs).toBe(0) - - expect(await store.get('key1')).toBe(null) - expect(await store.get('key2')).toBe(null) - expect(await store.get('parent/child')).toBe(null) - expect(await store.get('parent/another/nested')).toBe(null) - expect(await store.getMetadata('key2')).toBe(null) - - await server.stop() - await fs.rm(directory.path, { force: true, recursive: true }) -}) diff --git a/packages/blobs/src/server.ts b/packages/blobs/src/server.ts deleted file mode 100644 index 0e56ab4..0000000 --- a/packages/blobs/src/server.ts +++ /dev/null @@ -1,648 +0,0 @@ -import { createHmac } from 'node:crypto' -import { createReadStream, promises as fs } from 'node:fs' -import { dirname, join, relative, resolve, sep } from 'node:path' - -import { HTTPServer } from '@netlify/dev-utils' - -import { ListResponse } from './backend/list.ts' -import { SIGNED_URL_ACCEPT_HEADER } from './client.ts' -import { decodeMetadata, encodeMetadata, METADATA_HEADER_INTERNAL } from './metadata.ts' -import { HTTPMethod } from './types.ts' -import { decodeName, encodeName, isNodeError, Logger } from './util.ts' - -const API_URL_PATH = /\/api\/v1\/blobs\/(?[^/]+)\/(?[^/]+)\/?(?[^?]*)/ -const LEGACY_API_URL_PATH = /\/api\/v1\/sites\/(?[^/]+)\/blobs\/?(?[^?]*)/ -const LEGACY_DEFAULT_STORE = 'production' -const REGION_PREFIX = 'region:' - -export enum Operation { - DELETE = 'delete', - GET = 'get', - GET_METADATA = 'getMetadata', - LIST = 'list', - SET = 'set', -} - -export type OnRequestCallback = (parameters: { type: Operation; url: string }) => void - -interface BlobsServerOptions { - /** - * Whether debug-level information should be logged, such as internal errors - * or information about incoming requests. - */ - debug?: boolean - - /** - * Base directory to read and write files from. - */ - directory: string - - /** - * Function to log messages. Defaults to `console.log`. - */ - logger?: Logger - - /** - * Callback function to be called on every request. - */ - onRequest?: OnRequestCallback - - /** - * Port to run the server on. Defaults to a random port. - */ - port?: number - - /** - * Static authentication token that should be present in all requests. If not - * supplied, no authentication check is performed. - */ - token?: string -} - -export class BlobsServer { - private address: string - private debug: boolean - private directory: string - private logger: Logger - private onRequest?: OnRequestCallback - private port?: number - private server?: InstanceType - private token?: string - private tokenHash: string - - constructor({ debug, directory, logger, onRequest, port, token }: BlobsServerOptions) { - this.address = '' - this.port = port - this.debug = debug === true - this.directory = directory - this.logger = logger ?? console.log - this.onRequest = onRequest - this.token = token - this.tokenHash = createHmac('sha256', Math.random.toString()) - .update(token ?? Math.random.toString()) - .digest('hex') - } - - private dispatchOnRequestEvent(type: Operation, input: string | URL) { - if (!this.onRequest) { - return - } - - const url = new URL(input) - - this.onRequest({ type, url: url.pathname + url.search }) - } - - private async delete(req: Request): Promise { - const apiMatch = this.parseAPIRequest(req) - - if (apiMatch?.useSignedURL) { - return Response.json({ url: apiMatch.url.toString() }) - } - - const url = new URL(apiMatch?.url ?? req.url ?? '', this.address) - const { dataPath, key, metadataPath, rootPath } = this.getLocalPaths(url) - - if (!dataPath || !rootPath) { - return new Response(null, { status: 400 }) - } - - // If there's no key, we're deleting all blobs from the store. - if (!key) { - return this.deleteAll(rootPath) - } - - // Try to delete the metadata file, if one exists. - try { - await fs.rm(metadataPath, { force: true, recursive: true }) - } catch { - // no-op - } - - // Delete the data file. - try { - await fs.rm(dataPath, { force: true, recursive: true }) - } catch (error: unknown) { - // An `ENOENT` error means we have tried to delete a key that doesn't - // exist, which shouldn't be treated as an error. - if (!isNodeError(error) || error.code !== 'ENOENT') { - return new Response(null, { status: 500 }) - } - } - - return new Response(null, { status: 204 }) - } - - private async deleteAll(rootPath: string): Promise { - let blobsDeleted = 0 - - try { - // Count the number of blobs before deleting. - try { - const countResult: ListResponse = { - blobs: [], - directories: [], - } - - await BlobsServer.walk({ - directories: false, - path: rootPath, - prefix: '', - rootPath, - result: countResult, - }) - - blobsDeleted = countResult.blobs?.length ?? 0 - } catch (error: unknown) { - // If the directory doesn't exist, there are no blobs to delete. - if (!isNodeError(error) || error.code !== 'ENOENT') { - throw error - } - } - - // Delete all data files in the store. - await fs.rm(rootPath, { force: true, recursive: true }) - - // Extract site ID and store name from rootPath to delete metadata. - const pathParts = rootPath.split(sep) - const storeName = pathParts[pathParts.length - 1] - const siteID = pathParts[pathParts.length - 2] - const metadataStorePath = resolve(this.directory, 'metadata', siteID, storeName) - - // Delete all metadata files in the store. - await fs.rm(metadataStorePath, { force: true, recursive: true }) - } catch (error: unknown) { - // An `ENOENT` error means the store doesn't exist, which is acceptable. - if (!isNodeError(error) || error.code !== 'ENOENT') { - this.logDebug('Error when deleting store:', error) - - return new Response(null, { status: 500 }) - } - } - - return Response.json({ blobs_deleted: blobsDeleted, has_more: false }) - } - - private async get(req: Request): Promise { - const apiMatch = this.parseAPIRequest(req) - const url = apiMatch?.url ?? new URL(req.url ?? '', this.address) - - if (apiMatch?.key && apiMatch?.useSignedURL) { - return Response.json({ url: apiMatch.url.toString() }) - } - - const { dataPath, key, metadataPath, rootPath } = this.getLocalPaths(apiMatch?.url ?? url) - - // If there's no root path, the request is invalid. - if (!rootPath) { - return new Response(null, { status: 400 }) - } - - // If there's no data or metadata paths, it means we're listing stores. - if (!dataPath || !metadataPath) { - return this.listStores(rootPath, url.searchParams.get('prefix') ?? '') - } - - // If there is no key in the URL, it means we're listing blobs. - if (!key) { - return this.listBlobs({ dataPath, metadataPath, rootPath, req, url }) - } - - this.dispatchOnRequestEvent(Operation.GET, url) - - const headers: Record = {} - - try { - const rawData = await fs.readFile(metadataPath, 'utf8') - const metadata = JSON.parse(rawData) - const encodedMetadata = encodeMetadata(metadata) - - if (encodedMetadata) { - headers[METADATA_HEADER_INTERNAL] = encodedMetadata - } - } catch (error) { - if (!isNodeError(error) || error.code !== 'ENOENT') { - this.logDebug('Could not read metadata file:', error) - } - } - - try { - const fileStream = createReadStream(dataPath) - const chunks: Buffer[] = [] - - for await (const chunk of fileStream) { - chunks.push(Buffer.from(chunk)) - } - - const buffer = Buffer.concat(chunks) - - return new Response(buffer, { headers }) - } catch (error) { - if (isNodeError(error) && (error.code === 'EISDIR' || error.code === 'ENOENT')) { - return new Response(null, { status: 404 }) - } - - this.logDebug('Error when reading data:', error) - - return new Response(null, { status: 500 }) - } - } - - private async head(req: Request): Promise { - const url = this.parseAPIRequest(req)?.url ?? new URL(req.url ?? '', this.address) - const { dataPath, key, metadataPath } = this.getLocalPaths(url) - - if (!dataPath || !metadataPath || !key) { - return new Response(null, { status: 400 }) - } - - try { - const rawData = await fs.readFile(metadataPath, 'utf8') - const metadata = JSON.parse(rawData) - const encodedMetadata = encodeMetadata(metadata) - - return new Response(null, { - headers: { - [METADATA_HEADER_INTERNAL]: encodedMetadata ?? '', - }, - }) - } catch (error) { - if (isNodeError(error) && (error.code === 'ENOENT' || error.code === 'ISDIR')) { - return new Response(null, { status: 404 }) - } - - this.logDebug('Could not read metadata file:', error) - - return new Response(null, { status: 500 }) - } - } - - private async listBlobs(options: { - dataPath: string - metadataPath: string - rootPath: string - req: Request - url: URL - }): Promise { - const { dataPath, rootPath, url } = options - const directories = url.searchParams.get('directories') === 'true' - const prefix = url.searchParams.get('prefix') ?? '' - const result: ListResponse = { - blobs: [], - directories: [], - } - - this.dispatchOnRequestEvent(Operation.LIST, url) - - try { - await BlobsServer.walk({ directories, path: dataPath, prefix, rootPath, result }) - } catch (error) { - // If the directory is not found, it just means there are no entries on - // the store, so that shouldn't be treated as an error. - if (!isNodeError(error) || error.code !== 'ENOENT') { - this.logDebug('Could not perform list:', error) - - return new Response(null, { status: 500 }) - } - } - - return Response.json(result) - } - - private async listStores(rootPath: string, prefix: string): Promise { - try { - const allStores = await fs.readdir(rootPath) - const filteredStores = allStores.map(decodeName).filter((store) => store.startsWith(prefix)) - - return Response.json({ stores: filteredStores }) - } catch (error) { - this.logDebug('Could not list stores:', error) - - return new Response(null, { status: 500 }) - } - } - - private logDebug(...message: unknown[]) { - if (!this.debug) { - return - } - - this.logger('[Netlify Blobs server]', ...message) - } - - private async put(req: Request): Promise { - const apiMatch = this.parseAPIRequest(req) - if (apiMatch) { - return Response.json({ url: apiMatch.url.toString() }) - } - - const url = new URL(req.url ?? '', this.address) - const { dataPath, key, metadataPath } = this.getLocalPaths(url) - - if (!dataPath || !key || !metadataPath) { - return new Response(null, { status: 400 }) - } - - // Check conditional write headers. - const ifMatch = req.headers.get('if-match') - const ifNoneMatch = req.headers.get('if-none-match') - - try { - let fileExists = false - try { - await fs.access(dataPath) - - fileExists = true - } catch {} - - const currentEtag = fileExists ? await BlobsServer.generateETag(dataPath) : undefined - - if (ifNoneMatch === '*' && fileExists) { - return new Response(null, { status: 412 }) - } - - if (ifMatch && (!fileExists || ifMatch !== currentEtag)) { - return new Response(null, { status: 412 }) - } - - const metadataHeader = req.headers.get(METADATA_HEADER_INTERNAL) - const metadata = decodeMetadata(metadataHeader) - - // We can't have multiple requests writing to the same file, which could - // happen if multiple clients try to write to the same key at the same - // time. To prevent this, we write to a temporary file first and then - // atomically move it to its final destination. - const tempPath = join(dirname(dataPath), `.${Math.random().toString(36).slice(2)}`) - const body = await req.arrayBuffer() - await fs.mkdir(dirname(dataPath), { recursive: true }) - await fs.writeFile(tempPath, Buffer.from(body)) - await fs.rename(tempPath, dataPath) - - if (metadata) { - await fs.mkdir(dirname(metadataPath), { recursive: true }) - await fs.writeFile(metadataPath, JSON.stringify(metadata)) - } - - const newEtag = await BlobsServer.generateETag(dataPath) - - return new Response(null, { - status: 200, - headers: { - etag: newEtag, - }, - }) - } catch (error) { - if (isNodeError(error)) { - this.logDebug('Error when writing data:', error) - } - return new Response(null, { status: 500 }) - } - } - - /** - * Parses the URL and returns the filesystem paths where entries and metadata - * should be stored. - */ - private getLocalPaths(url?: URL) { - if (!url) { - return {} - } - - let parts = url.pathname.split('/').slice(1) - - if (parts[0].startsWith(REGION_PREFIX)) { - parts = parts.slice(1) - } - - const [siteID, rawStoreName, ...rawKey] = parts - - if (!siteID) { - return {} - } - - const rootPath = resolve(this.directory, 'entries', siteID) - - if (!rawStoreName) { - return { rootPath } - } - - const key = rawKey.map(encodeName) - - const storeName = encodeName(rawStoreName) - const storePath = resolve(rootPath, storeName) - const dataPath = resolve(storePath, ...key) - const metadataPath = resolve(this.directory, 'metadata', siteID, storeName, ...key) - - return { dataPath, key: key.join('/'), metadataPath, rootPath: storePath } - } - - /** - * Helper method to generate an ETag for a file based on its path and last modified time. - */ - private static async generateETag(filePath: string): Promise { - try { - const stats = await fs.stat(filePath) - const hash = createHmac('sha256', stats.mtime.toISOString()).update(filePath).digest('hex') - - return `"${hash}"` - } catch { - return '' - } - } - - private async handleRequest(req: Request): Promise { - if (!req.url || !this.validateAccess(req)) { - return new Response(null, { status: 403 }) - } - - switch (req.method?.toLowerCase()) { - case HTTPMethod.DELETE: { - this.dispatchOnRequestEvent(Operation.DELETE, req.url) - - return this.delete(req) - } - - case HTTPMethod.GET: { - return this.get(req) - } - - case HTTPMethod.PUT: { - this.dispatchOnRequestEvent(Operation.SET, req.url) - - return this.put(req) - } - - case HTTPMethod.HEAD: { - this.dispatchOnRequestEvent(Operation.GET_METADATA, req.url) - - return this.head(req) - } - - default: - return new Response(null, { status: 405 }) - } - } - - /** - * Tries to parse a URL as being an API request and returns the different - * components, such as the store name, site ID, key, and signed URL. - */ - private parseAPIRequest(req: Request) { - if (!req.url) { - return null - } - - const apiURLMatch = API_URL_PATH.exec(req.url) - - if (apiURLMatch) { - const key = apiURLMatch.groups?.key - const siteID = apiURLMatch.groups?.site_id as string - const storeName = apiURLMatch.groups?.store_name as string - const urlPath = [siteID, storeName, key].filter(Boolean) as string[] - const url = new URL(`/${urlPath.join('/')}?signature=${this.tokenHash}`, this.address) - - return { - key, - siteID, - storeName, - url, - useSignedURL: req.headers.get('accept') === SIGNED_URL_ACCEPT_HEADER, - } - } - - const legacyAPIURLMatch = LEGACY_API_URL_PATH.exec(req.url) - - if (legacyAPIURLMatch) { - const fullURL = new URL(req.url, this.address) - const storeName = fullURL.searchParams.get('context') ?? LEGACY_DEFAULT_STORE - const key = legacyAPIURLMatch.groups?.key - const siteID = legacyAPIURLMatch.groups?.site_id as string - const urlPath = [siteID, storeName, key].filter(Boolean) as string[] - const url = new URL(`/${urlPath.join('/')}?signature=${this.tokenHash}`, this.address) - - return { - key, - siteID, - storeName, - url, - useSignedURL: true, - } - } - - return null - } - - private validateAccess(req: Request) { - if (!this.token) { - return true - } - - const authorization = req.headers.get('authorization') || '' - - if (authorization.toLowerCase().startsWith('bearer ') && authorization.slice('bearer '.length) === this.token) { - return true - } - - if (!req.url) { - return false - } - - const url = new URL(req.url, this.address) - const signature = url.searchParams.get('signature') - - if (signature === this.tokenHash) { - return true - } - - return false - } - - /** - * Traverses a path and collects both blobs and directories into a `result` - * object, taking into account the `directories` and `prefix` parameters. - */ - private static async walk(options: { - directories: boolean - path: string - prefix: string - result: ListResponse - rootPath: string - }) { - const { directories, path, prefix, result, rootPath } = options - const entries = await fs.readdir(path) - - for (const entry of entries) { - const entryPath = join(path, entry) - const stat = await fs.stat(entryPath) - - let key = relative(rootPath, entryPath) - - // Normalize keys to use `/` as delimiter regardless of OS. - if (sep !== '/') { - key = key.split(sep).join('/') - } - - // To match the key against the prefix, we start by creating a "mask", - // which consists of the subset of the key up to the length of the - // prefix. - const mask = key.slice(0, prefix.length) - - // There is a match if the mask matches the prefix. - const isMatch = prefix.startsWith(mask) - - if (!isMatch) { - continue - } - - // If the entry is a file, add it to the `blobs` bucket. - if (!stat.isDirectory()) { - // Generate a deterministic ETag based on file path and last modified time. - const etag = await this.generateETag(entryPath) - - result.blobs?.push({ - etag, - key, - last_modified: stat.mtime.toISOString(), - size: stat.size, - }) - - continue - } - - // The entry is a directory. We push it to the `directories` bucket only - // if the `directories` parameter is enabled and we're at the same level - // as the prefix. For example, if the prefix is `animals/cats/` and the - // key we're processing is `animals`, we don't want to push it to the - // `directories` bucket. We want to traverse it. - if (directories && key.startsWith(prefix)) { - result.directories?.push(key) - - continue - } - - // Call this method recursively with the directory as the starting point. - await BlobsServer.walk({ directories, path: entryPath, prefix, rootPath, result }) - } - } - - async start(): Promise<{ address: string; family: string; port: number }> { - await fs.mkdir(this.directory, { recursive: true }) - - const server = new HTTPServer((req: Request) => this.handleRequest(req)) - const address = await server.start(this.port ?? 0) - const port = Number.parseInt(new URL(address).port) - - this.address = address - this.server = server - - return { - address, - family: 'ipv4', - port, - } - } - - async stop() { - return this.server?.stop() - } -} diff --git a/packages/blobs/src/store.ts b/packages/blobs/src/store.ts deleted file mode 100644 index f3dcec9..0000000 --- a/packages/blobs/src/store.ts +++ /dev/null @@ -1,685 +0,0 @@ -import type { Span } from '@netlify/otel/opentelemetry' -import type { DeleteStoreResponse } from './backend/delete_store.ts' -import type { ListResponse, ListResponseBlob } from './backend/list.ts' -import { Client, type Conditions } from './client.ts' -import type { ConsistencyMode } from './consistency.ts' -import { getMetadataFromResponse, Metadata } from './metadata.ts' -import { BlobInput, HTTPMethod } from './types.ts' -import { BlobsInternalError, collectIterator, withSpan } from './util.ts' - -export const DEPLOY_STORE_PREFIX = 'deploy:' -export const LEGACY_STORE_INTERNAL_PREFIX = 'netlify-internal/legacy-namespace/' -export const SITE_STORE_PREFIX = 'site:' - -const STATUS_OK = 200 -const STATUS_PRE_CONDITION_FAILED = 412 - -interface BaseStoreOptions { - client: Client - consistency?: ConsistencyMode -} - -interface DeployStoreOptions extends BaseStoreOptions { - deployID: string - name?: string -} - -interface NamedStoreOptions extends BaseStoreOptions { - name: string -} - -export type StoreOptions = DeployStoreOptions | NamedStoreOptions - -export interface GetOptions { - consistency?: ConsistencyMode -} - -export interface GetMetadataOptions { - consistency?: ConsistencyMode -} - -export interface GetWithMetadataOptions { - consistency?: ConsistencyMode - etag?: string -} - -export interface GetWithMetadataResult { - etag?: string - metadata: Metadata -} - -export interface ListResult { - blobs: ListResultBlob[] - directories: string[] -} - -export interface ListResultBlob { - etag: string - key: string -} - -export interface ListOptions { - directories?: boolean - paginate?: boolean - prefix?: string -} - -export interface TracingOptions { - span?: Span -} - -export interface DeleteStoreResult { - deletedBlobs: number -} - -interface BaseSetOptions { - /** - * Arbitrary metadata object to associate with an entry. Must be seralizable - * to JSON. - */ - metadata?: Metadata -} - -type CreateOnlyOptions = { - onlyIfMatch?: never - - /** - * If true, the operation will only succeed if the key does not already exist - * in the store. If the key exists, the operation will return with - * `modified: false`. - */ - onlyIfNew?: boolean -} - -type UpdateOnlyOptions = { - /** - * If specified, the operation will only succeed if the entry already exists - * in the store and its current ETag matches this value. If it doesn't match, - * the operation will return with `modified: false`. - */ - onlyIfMatch?: string - - onlyIfNew?: never -} - -export type SetOptions = BaseSetOptions & (CreateOnlyOptions | UpdateOnlyOptions) - -export type WriteResult = { - /** - * The ETag of the entry after the write operation. It's only present if the - * operation actually resulted in a modified entry. - */ - etag?: string - - /** - * A boolean indicating whether the operation has resulted in a modified - * entry. A conditional `set` on a key that already exists will return - * an object with `modified` set to false. - */ - modified: boolean -} - -export type BlobResponseType = 'arrayBuffer' | 'blob' | 'json' | 'stream' | 'text' - -export class Store { - private client: Client - private name: string - - constructor(options: StoreOptions) { - this.client = options.client - - if ('deployID' in options) { - Store.validateDeployID(options.deployID) - - let name = DEPLOY_STORE_PREFIX + options.deployID - - if (options.name) { - name += `:${options.name}` - } - - this.name = name - } else if (options.name.startsWith(LEGACY_STORE_INTERNAL_PREFIX)) { - const storeName = options.name.slice(LEGACY_STORE_INTERNAL_PREFIX.length) - - Store.validateStoreName(storeName) - - this.name = storeName - } else { - Store.validateStoreName(options.name) - - this.name = SITE_STORE_PREFIX + options.name - } - } - - async delete(key: string) { - const res = await this.client.makeRequest({ key, method: HTTPMethod.DELETE, storeName: this.name }) - - if (![200, 204, 404].includes(res.status)) { - throw new BlobsInternalError(res) - } - } - - async deleteAll(): Promise { - let totalDeletedBlobs = 0 - let hasMore = true - - while (hasMore) { - const res = await this.client.makeRequest({ method: HTTPMethod.DELETE, storeName: this.name }) - - if (res.status !== 200) { - throw new BlobsInternalError(res) - } - - const data = (await res.json()) as DeleteStoreResponse - - if (typeof data.blobs_deleted !== 'number') { - throw new BlobsInternalError(res) - } - - totalDeletedBlobs += data.blobs_deleted - hasMore = typeof data.has_more === 'boolean' && data.has_more - } - - return { - deletedBlobs: totalDeletedBlobs, - } - } - - async get(key: string, options?: GetOptions & TracingOptions & { type?: 'arrayBuffer' }): Promise - async get(key: string, options?: GetOptions & TracingOptions & { type?: 'blob' }): Promise - async get(key: string, options?: GetOptions & TracingOptions & { type?: 'json' }): Promise - async get(key: string, options?: GetOptions & TracingOptions & { type?: 'stream' }): Promise - async get(key: string, options?: GetOptions & TracingOptions & { type?: 'text' }): Promise - async get(key: string, options?: GetOptions & TracingOptions): Promise - async get( - key: string, - options?: GetOptions & TracingOptions & { type?: BlobResponseType }, - ): Promise { - return withSpan(options?.span, 'blobs.get', async (span) => { - const { consistency, type } = options ?? {} - - span?.setAttributes({ - 'blobs.store': this.name, - 'blobs.key': key, - 'blobs.type': type, - 'blobs.method': 'GET', - 'blobs.consistency': consistency, - }) - - const res = await this.client.makeRequest({ - consistency, - key, - method: HTTPMethod.GET, - storeName: this.name, - }) - - span?.setAttributes({ - 'blobs.response.body.size': res.headers.get('content-length') ?? undefined, - 'blobs.response.status': res.status, - }) - - if (res.status === 404) { - return null - } - - if (res.status !== 200) { - throw new BlobsInternalError(res) - } - - if (type === undefined || type === 'text') { - return res.text() - } - - if (type === 'arrayBuffer') { - return res.arrayBuffer() - } - - if (type === 'blob') { - return res.blob() - } - - if (type === 'json') { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return res.json() - } - - if (type === 'stream') { - return res.body - } - - throw new BlobsInternalError(res) - }) - } - - async getMetadata(key: string, options: GetMetadataOptions & TracingOptions = {}) { - return withSpan(options?.span, 'blobs.getMetadata', async (span) => { - span?.setAttributes({ - 'blobs.store': this.name, - 'blobs.key': key, - 'blobs.method': 'HEAD', - 'blobs.consistency': options.consistency, - }) - - const res = await this.client.makeRequest({ - consistency: options.consistency, - key, - method: HTTPMethod.HEAD, - storeName: this.name, - }) - - span?.setAttributes({ - 'blobs.response.status': res.status, - }) - - if (res.status === 404) { - return null - } - - if (res.status !== 200 && res.status !== 304) { - throw new BlobsInternalError(res) - } - - const etag = res?.headers.get('etag') ?? undefined - const metadata = getMetadataFromResponse(res) - const result = { - etag, - metadata, - } - - return result - }) - } - - async getWithMetadata( - key: string, - options?: GetWithMetadataOptions & TracingOptions, - ): Promise<({ data: string } & GetWithMetadataResult) | null> - - async getWithMetadata( - key: string, - options: { type: 'arrayBuffer' } & GetWithMetadataOptions & TracingOptions, - ): Promise<{ data: ArrayBuffer } & GetWithMetadataResult> - - async getWithMetadata( - key: string, - options: { type: 'blob' } & GetWithMetadataOptions & TracingOptions, - ): Promise<({ data: Blob } & GetWithMetadataResult) | null> - - async getWithMetadata( - key: string, - options: { type: 'json' } & GetWithMetadataOptions & TracingOptions, - ): Promise<({ data: any } & GetWithMetadataResult) | null> - - async getWithMetadata( - key: string, - options: { type: 'stream' } & GetWithMetadataOptions & TracingOptions, - ): Promise<({ data: ReadableStream } & GetWithMetadataResult) | null> - - async getWithMetadata( - key: string, - options: { type: 'text' } & GetWithMetadataOptions & TracingOptions, - ): Promise<({ data: string } & GetWithMetadataResult) | null> - - async getWithMetadata( - key: string, - options?: { type: BlobResponseType } & GetWithMetadataOptions & TracingOptions, - ): Promise< - | ({ - data: ArrayBuffer | Blob | ReadableStream | string | null - } & GetWithMetadataResult) - | null - > { - return withSpan(options?.span, 'blobs.getWithMetadata', async (span) => { - const { consistency, etag: requestETag, type } = options ?? {} - const headers = requestETag ? { 'if-none-match': requestETag } : undefined - - span?.setAttributes({ - 'blobs.store': this.name, - 'blobs.key': key, - 'blobs.method': 'GET', - 'blobs.consistency': options?.consistency, - 'blobs.type': type, - 'blobs.request.etag': requestETag, - }) - - const res = await this.client.makeRequest({ - consistency, - headers, - key, - method: HTTPMethod.GET, - storeName: this.name, - }) - const responseETag = res?.headers.get('etag') ?? undefined - - span?.setAttributes({ - 'blobs.response.body.size': res.headers.get('content-length') ?? undefined, - 'blobs.response.etag': responseETag, - 'blobs.response.status': res.status, - }) - - if (res.status === 404) { - return null - } - - if (res.status !== 200 && res.status !== 304) { - throw new BlobsInternalError(res) - } - - const metadata = getMetadataFromResponse(res) - const result: GetWithMetadataResult = { - etag: responseETag, - metadata, - } - - if (res.status === 304 && requestETag) { - return { data: null, ...result } - } - - if (type === undefined || type === 'text') { - return { data: await res.text(), ...result } - } - - if (type === 'arrayBuffer') { - return { data: await res.arrayBuffer(), ...result } - } - - if (type === 'blob') { - return { data: await res.blob(), ...result } - } - - if (type === 'json') { - return { data: await res.json(), ...result } - } - - if (type === 'stream') { - return { data: res.body, ...result } - } - - throw new Error(`Invalid 'type' property: ${type}. Expected: arrayBuffer, blob, json, stream, or text.`) - }) - } - - list(options: ListOptions & TracingOptions & { paginate: true }): AsyncIterable - list(options?: ListOptions & TracingOptions & { paginate?: false }): Promise - list(options: ListOptions & TracingOptions = {}): Promise | AsyncIterable { - return withSpan(options.span, 'blobs.list', (span) => { - span?.setAttributes({ - 'blobs.store': this.name, - 'blobs.method': 'GET', - 'blobs.list.paginate': options.paginate ?? false, - }) - - const iterator = this.getListIterator(options) - - if (options.paginate) { - return iterator - } - - // We can't use `async/await` here because that would make the signature - // incompatible with one of the overloads. - return collectIterator(iterator).then((items) => - items.reduce( - (acc, item) => ({ - blobs: [...acc.blobs, ...item.blobs], - directories: [...acc.directories, ...item.directories], - }), - { blobs: [], directories: [] }, - ), - ) - }) - } - - async set(key: string, data: BlobInput, options: SetOptions & TracingOptions = {}): Promise { - return withSpan(options.span, 'blobs.set', async (span) => { - span?.setAttributes({ - 'blobs.store': this.name, - 'blobs.key': key, - 'blobs.method': 'PUT', - 'blobs.data.size': typeof data == 'string' ? data.length : data instanceof Blob ? data.size : data.byteLength, - 'blobs.data.type': typeof data == 'string' ? 'string' : data instanceof Blob ? 'blob' : 'arrayBuffer', - 'blobs.atomic': Boolean(options.onlyIfMatch ?? options.onlyIfNew), - }) - - Store.validateKey(key) - - const conditions = Store.getConditions(options) - const res = await this.client.makeRequest({ - conditions, - body: data, - key, - metadata: options.metadata, - method: HTTPMethod.PUT, - storeName: this.name, - }) - - const etag = res.headers.get('etag') ?? '' - - span?.setAttributes({ - 'blobs.response.etag': etag, - 'blobs.response.status': res.status, - }) - - if (conditions) { - return res.status === STATUS_PRE_CONDITION_FAILED ? { modified: false } : { etag, modified: true } - } - - if (res.status === STATUS_OK) { - return { - etag, - modified: true, - } - } - - throw new BlobsInternalError(res) - }) - } - - async setJSON(key: string, data: unknown, options: SetOptions & TracingOptions = {}): Promise { - return withSpan(options.span, 'blobs.setJSON', async (span) => { - span?.setAttributes({ - 'blobs.store': this.name, - 'blobs.key': key, - 'blobs.method': 'PUT', - 'blobs.data.type': 'json', - }) - Store.validateKey(key) - - const conditions = Store.getConditions(options) - const payload = JSON.stringify(data) - const headers = { - 'content-type': 'application/json', - } - - const res = await this.client.makeRequest({ - ...conditions, - body: payload, - headers, - key, - metadata: options.metadata, - method: HTTPMethod.PUT, - storeName: this.name, - }) - - const etag = res.headers.get('etag') ?? '' - span?.setAttributes({ - 'blobs.response.etag': etag, - 'blobs.response.status': res.status, - }) - - if (conditions) { - return res.status === STATUS_PRE_CONDITION_FAILED ? { modified: false } : { etag, modified: true } - } - - if (res.status === STATUS_OK) { - return { - etag, - modified: true, - } - } - - throw new BlobsInternalError(res) - }) - } - - private static formatListResultBlob(result: ListResponseBlob): ListResultBlob | null { - if (!result.key) { - return null - } - - return { - etag: result.etag, - key: result.key, - } - } - - private static getConditions(options: SetOptions): Conditions | undefined { - if ('onlyIfMatch' in options && 'onlyIfNew' in options) { - throw new Error( - `The 'onlyIfMatch' and 'onlyIfNew' options are mutually exclusive. Using 'onlyIfMatch' will make the write succeed only if there is an entry for the key with the given content, while 'onlyIfNew' will make the write succeed only if there is no entry for the key.`, - ) - } - - if ('onlyIfMatch' in options && options.onlyIfMatch) { - if (typeof options.onlyIfMatch !== 'string') { - throw new Error(`The 'onlyIfMatch' property expects a string representing an ETag.`) - } - - return { - onlyIfMatch: options.onlyIfMatch, - } - } - - if ('onlyIfNew' in options && options.onlyIfNew) { - if (typeof options.onlyIfNew !== 'boolean') { - throw new Error( - `The 'onlyIfNew' property expects a boolean indicating whether the write should fail if an entry for the key already exists.`, - ) - } - - return { - onlyIfNew: true, - } - } - } - - private static validateKey(key: string) { - if (key === '') { - throw new Error('Blob key must not be empty.') - } - - if (key.startsWith('/') || key.startsWith('%2F')) { - throw new Error('Blob key must not start with forward slash (/).') - } - - if (new TextEncoder().encode(key).length > 600) { - throw new Error( - 'Blob key must be a sequence of Unicode characters whose UTF-8 encoding is at most 600 bytes long.', - ) - } - } - - private static validateDeployID(deployID: string) { - // We could be stricter here and require a length of 24 characters, but the - // CLI currently uses a deploy of `0` when running Netlify Dev, since there - // is no actual deploy at that point. Let's go with a more loose validation - // logic here until we update the CLI. - if (!/^\w{1,24}$/.test(deployID)) { - throw new Error(`'${deployID}' is not a valid Netlify deploy ID.`) - } - } - - private static validateStoreName(name: string) { - if (name.includes('/') || name.includes('%2F')) { - throw new Error('Store name must not contain forward slashes (/).') - } - - if (new TextEncoder().encode(name).length > 64) { - throw new Error( - 'Store name must be a sequence of Unicode characters whose UTF-8 encoding is at most 64 bytes long.', - ) - } - } - - private getListIterator(options?: ListOptions & TracingOptions): AsyncIterable { - const { client, name: storeName } = this - const parameters: Record = {} - - if (options?.prefix) { - parameters.prefix = options.prefix - } - - if (options?.directories) { - parameters.directories = 'true' - } - - return { - [Symbol.asyncIterator]() { - let currentCursor: string | null = null - let done = false - - return { - async next() { - return withSpan(options?.span, 'blobs.list.next', async (span) => { - span?.setAttributes({ - 'blobs.store': storeName, - 'blobs.method': 'GET', - 'blobs.list.paginate': options?.paginate ?? false, - 'blobs.list.done': done, - 'blobs.list.cursor': currentCursor ?? undefined, - }) - if (done) { - return { done: true, value: undefined } as const - } - - const nextParameters = { ...parameters } - - if (currentCursor !== null) { - nextParameters.cursor = currentCursor - } - - const res = await client.makeRequest({ - method: HTTPMethod.GET, - parameters: nextParameters, - storeName, - }) - - span?.setAttributes({ - 'blobs.response.status': res.status, - }) - - let blobs: ListResponseBlob[] = [] - let directories: string[] = [] - - if (![200, 204, 404].includes(res.status)) { - throw new BlobsInternalError(res) - } - - if (res.status === 404) { - done = true - } else { - const page = (await res.json()) as ListResponse - - if (page.next_cursor) { - currentCursor = page.next_cursor - } else { - done = true - } - - blobs = (page.blobs ?? []).map(Store.formatListResultBlob).filter(Boolean) as ListResponseBlob[] - directories = page.directories ?? [] - } - - return { - done: false, - value: { - blobs, - directories, - }, - } - }) - }, - } - }, - } - } -} diff --git a/packages/blobs/src/store_factory.ts b/packages/blobs/src/store_factory.ts deleted file mode 100644 index be4368a..0000000 --- a/packages/blobs/src/store_factory.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Client, ClientOptions, getClientOptions } from './client.ts' -import { getEnvironmentContext, MissingBlobsEnvironmentError } from './environment.ts' -import { Region, REGION_AUTO } from './region.ts' -import { Store } from './store.ts' - -export interface GetDeployStoreOptions extends Partial { - deployID?: string - name?: string - region?: Region -} - -/** - * Gets a reference to a deploy-scoped store. - */ -export const getDeployStore: { - (input?: GetDeployStoreOptions): Store - (name: string): Store - (name: string, options: Omit): Store -} = (input: GetDeployStoreOptions | string = {}, options?: Omit): Store => { - const context = getEnvironmentContext() - const mergedOptions = typeof input === 'string' ? { ...options, name: input } : input - const deployID = mergedOptions.deployID ?? context.deployID - - if (!deployID) { - throw new MissingBlobsEnvironmentError(['deployID']) - } - - const clientOptions = getClientOptions(mergedOptions, context) - - if (!clientOptions.region) { - // If a region hasn't been supplied and we're dealing with an edge request, - // use the region from the context if one is defined, otherwise throw. - if (clientOptions.edgeURL || clientOptions.uncachedEdgeURL) { - if (!context.primaryRegion) { - throw new Error( - 'When accessing a deploy store, the Netlify Blobs client needs to be configured with a region, and one was not found in the environment. To manually set the region, set the `region` property in the `getDeployStore` options. If you are using the Netlify CLI, you may have an outdated version; run `npm install -g netlify-cli@latest` to update and try again.', - ) - } - - clientOptions.region = context.primaryRegion - } else { - // For API requests, we can use `auto` and let the API choose the right - // region. - clientOptions.region = REGION_AUTO - } - } - - const client = new Client(clientOptions) - - return new Store({ client, deployID, name: mergedOptions.name }) -} - -export interface GetStoreOptions extends Partial { - deployID?: string - name?: string -} - -/** - * Gets a reference to a store. - * - * @param input Either a string containing the store name or an options object - */ -export const getStore: { - (name: string): Store - (name: string, options: Omit): Store - (options: GetStoreOptions): Store -} = (input: string | GetStoreOptions, options?: Omit) => { - if (typeof input === 'string') { - const contextOverride = - options?.siteID && options?.token ? { siteID: options?.siteID, token: options?.token } : undefined - const clientOptions = getClientOptions(options ?? {}, contextOverride) - const client = new Client(clientOptions) - - return new Store({ client, name: input }) - } - - if (typeof input?.name === 'string') { - const { name } = input - const contextOverride = input?.siteID && input?.token ? { siteID: input?.siteID, token: input?.token } : undefined - const clientOptions = getClientOptions(input, contextOverride) - - if (!name) { - throw new MissingBlobsEnvironmentError(['name']) - } - - const client = new Client(clientOptions) - - return new Store({ client, name }) - } - - if (typeof input?.deployID === 'string') { - const clientOptions = getClientOptions(input) - const { deployID } = input - - if (!deployID) { - throw new MissingBlobsEnvironmentError(['deployID']) - } - - const client = new Client(clientOptions) - - return new Store({ client, deployID }) - } - - throw new Error( - 'The `getStore` method requires the name of the store as a string or as the `name` property of an options object', - ) -} diff --git a/packages/blobs/src/store_list.test.ts b/packages/blobs/src/store_list.test.ts deleted file mode 100644 index 8080140..0000000 --- a/packages/blobs/src/store_list.test.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { Buffer } from 'node:buffer' -import { env, version as nodeVersion } from 'node:process' - -import { MockFetch } from '@netlify/dev-utils' -import semver from 'semver' -import { describe, test, expect, beforeAll, afterEach } from 'vitest' - -import type { ListStoresResponse } from './backend/list_stores.js' -import { listStores } from './main.js' - -beforeAll(async () => { - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.fetch = nodeFetch.default - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Request = nodeFetch.Request - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Response = nodeFetch.Response - // @ts-expect-error Expected type mismatch between native implementation and node-fetch - globalThis.Headers = nodeFetch.Headers - } -}) - -afterEach(() => { - delete env.NETLIFY_BLOBS_CONTEXT - delete globalThis.netlifyBlobsContext -}) - -const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621' -const apiToken = 'some token' -const edgeToken = 'some other token' -const edgeURL = 'https://edge.netlify' - -describe('listStores', () => { - describe('With API credentials', () => { - test('Lists site stores', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store1', 'site:store2', 'deploy:deploy1'] })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A`, - }) - .inject() - - const { stores } = await listStores({ - token: apiToken, - siteID, - }) - - expect(stores).toStrictEqual(['store1', 'store2']) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Paginates automatically', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store1', 'site:store2', 'deploy:6527dfab35be400008332a1a'], - next_cursor: 'cursor_1', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store3', 'site:store4', 'deploy:6527dfab35be400008332a1b'], - next_cursor: 'cursor_2', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A&cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store5', 'deploy:6527dfab35be400008332a1c'] })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A&cursor=cursor_2`, - }) - .inject() - - const { stores } = await listStores({ - token: apiToken, - siteID, - }) - - expect(stores).toStrictEqual(['store1', 'store2', 'store3', 'store4', 'store5']) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Supports manual pagination', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store1', 'site:store2', 'deploy:6527dfab35be400008332a1a'], - next_cursor: 'cursor_1', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store3', 'site:store4', 'deploy:6527dfab35be400008332a1b'], - next_cursor: 'cursor_2', - }), - ), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A&cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store5', 'deploy:6527dfab35be400008332a1c'] })), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A&cursor=cursor_2`, - }) - .inject() - - const result: ListStoresResponse = { - stores: [], - } - - for await (const entry of listStores({ token: apiToken, siteID, paginate: true })) { - result.stores.push(...entry.stores) - } - - expect(result.stores).toStrictEqual(['store1', 'store2', 'store3', 'store4', 'store5']) - expect(mockStore.fulfilled).toBeTruthy() - }) - }) - - test('Handles missing content for auto pagination', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response('', { status: 404 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A`, - }) - .inject() - - const { stores } = await listStores({ - token: apiToken, - siteID, - }) - - expect(stores).toStrictEqual([]) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Handles missing content with manual pagination', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${apiToken}` }, - response: new Response('', { status: 404 }), - url: `https://api.netlify.com/api/v1/blobs/${siteID}?prefix=site%3A`, - }) - .inject() - - const result: ListStoresResponse = { - stores: [], - } - - for await (const entry of listStores({ token: apiToken, siteID, paginate: true })) { - result.stores.push(...entry.stores) - } - - expect(result.stores).toStrictEqual([]) - expect(mockStore.fulfilled).toBeTruthy() - }) - - describe('With edge credentials', () => { - test('Lists site stores', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store1', 'site:store2', 'deploy:deploy1'] })), - url: `https://edge.netlify/${siteID}?prefix=site%3A`, - }) - .inject() - - const { stores } = await listStores({ - edgeURL, - token: edgeToken, - siteID, - }) - - expect(stores).toStrictEqual(['store1', 'store2']) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Loads credentials from the environment', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store1', 'site:store2', 'deploy:deploy1'] })), - url: `https://edge.netlify/${siteID}?prefix=site%3A`, - }) - .inject() - - const context = { - edgeURL, - siteID, - token: edgeToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const { stores } = await listStores() - - expect(stores).toStrictEqual(['store1', 'store2']) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Paginates automatically', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store1', 'site:store2', 'deploy:6527dfab35be400008332a1a'], - next_cursor: 'cursor_1', - }), - ), - url: `https://edge.netlify/${siteID}?prefix=site%3A`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store3', 'site:store4', 'deploy:6527dfab35be400008332a1b'], - next_cursor: 'cursor_2', - }), - ), - url: `https://edge.netlify/${siteID}?prefix=site%3A&cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store5', 'deploy:6527dfab35be400008332a1c'] })), - url: `https://edge.netlify/${siteID}?prefix=site%3A&cursor=cursor_2`, - }) - .inject() - - const context = { - edgeURL, - siteID, - token: edgeToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const { stores } = await listStores() - - expect(stores).toStrictEqual(['store1', 'store2', 'store3', 'store4', 'store5']) - expect(mockStore.fulfilled).toBeTruthy() - }) - - test('Supports manual pagination', async () => { - const mockStore = new MockFetch() - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store1', 'site:store2', 'deploy:6527dfab35be400008332a1a'], - next_cursor: 'cursor_1', - }), - ), - url: `https://edge.netlify/${siteID}?prefix=site%3A`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response( - JSON.stringify({ - stores: ['site:store3', 'site:store4', 'deploy:6527dfab35be400008332a1b'], - next_cursor: 'cursor_2', - }), - ), - url: `https://edge.netlify/${siteID}?prefix=site%3A&cursor=cursor_1`, - }) - .get({ - headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(JSON.stringify({ stores: ['site:store5', 'deploy:6527dfab35be400008332a1c'] })), - url: `https://edge.netlify/${siteID}?prefix=site%3A&cursor=cursor_2`, - }) - .inject() - - const context = { - edgeURL, - siteID, - token: edgeToken, - } - - env.NETLIFY_BLOBS_CONTEXT = Buffer.from(JSON.stringify(context)).toString('base64') - - const result: ListStoresResponse = { - stores: [], - } - - for await (const entry of listStores({ paginate: true })) { - result.stores.push(...entry.stores) - } - - expect(result.stores).toStrictEqual(['store1', 'store2', 'store3', 'store4', 'store5']) - expect(mockStore.fulfilled).toBeTruthy() - }) - }) -}) diff --git a/packages/blobs/src/store_list.ts b/packages/blobs/src/store_list.ts deleted file mode 100644 index 0c82e15..0000000 --- a/packages/blobs/src/store_list.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { ListStoresResponse } from './backend/list_stores.ts' -import { Client, ClientOptions, getClientOptions } from './client.ts' -import { getEnvironmentContext } from './environment.ts' -import { DEPLOY_STORE_PREFIX, SITE_STORE_PREFIX } from './store.ts' -import { HTTPMethod } from './types.ts' -import { collectIterator } from './util.ts' - -export function listStores(options: Partial & { paginate: true }): AsyncIterable -export function listStores(options?: Partial & { paginate?: false }): Promise -export function listStores( - options: Partial & { paginate?: boolean } = {}, -): AsyncIterable | Promise { - const context = getEnvironmentContext() - const clientOptions = getClientOptions(options, context) - const client = new Client(clientOptions) - const iterator = getListIterator(client, SITE_STORE_PREFIX) - - if (options.paginate) { - return iterator - } - - // We can't use `async/await` here because that would make the signature - // incompatible with one of the overloads. - return collectIterator(iterator).then((results) => ({ stores: results.flatMap((page) => page.stores) })) -} - -const formatListStoreResponse = (stores: string[]) => - stores - .filter((store) => !store.startsWith(DEPLOY_STORE_PREFIX)) - .map((store) => (store.startsWith(SITE_STORE_PREFIX) ? store.slice(SITE_STORE_PREFIX.length) : store)) - -const getListIterator = (client: Client, prefix: string): AsyncIterable => { - const parameters: Record = { - prefix, - } - - return { - [Symbol.asyncIterator]() { - let currentCursor: string | null = null - let done = false - - return { - async next() { - if (done) { - return { done: true, value: undefined } - } - - const nextParameters = { ...parameters } - - if (currentCursor !== null) { - nextParameters.cursor = currentCursor - } - - const res = await client.makeRequest({ - method: HTTPMethod.GET, - parameters: nextParameters, - }) - - if (res.status === 404) { - return { done: true, value: undefined } - } - - const page = (await res.json()) as ListStoresResponse - - if (page.next_cursor) { - currentCursor = page.next_cursor - } else { - done = true - } - - return { - done: false, - value: { - ...page, - stores: formatListStoreResponse(page.stores), - }, - } - }, - } - }, - } -} diff --git a/packages/blobs/src/types.ts b/packages/blobs/src/types.ts deleted file mode 100644 index 766589e..0000000 --- a/packages/blobs/src/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -export type BlobInput = string | ArrayBuffer | Blob - -export type Fetcher = typeof globalThis.fetch - -export enum HTTPMethod { - DELETE = 'delete', - GET = 'get', - HEAD = 'head', - PUT = 'put', -} - -// TODO: Import the full type from `@netlify/functions`. -export interface LambdaEvent { - blobs: string - headers: Record -} diff --git a/packages/blobs/src/util.test.ts b/packages/blobs/src/util.test.ts deleted file mode 100644 index 9543c67..0000000 --- a/packages/blobs/src/util.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { it, expect, describe } from 'vitest' - -import { decodeWin32SafeName, encodeWin32SafeName } from './util.ts' - -describe('win32 safe names', () => { - it('encodes unsafe path parts', () => { - const unsafe = 'hello|*<>wo:rld' - const safe = encodeWin32SafeName(unsafe) - expect(safe).not.toContain('|') - expect(safe).not.toContain('.') - expect(safe).not.toContain('*') - expect(safe).not.toContain('<') - expect(safe).not.toContain('>') - expect(safe).not.toContain(':') - }) - - it('disallows invalid names', () => { - expect(encodeWin32SafeName('CON')).not.toBe('CON') - expect(encodeWin32SafeName('COM1')).not.toBe('COM1') - expect(encodeWin32SafeName('com2')).not.toBe('com2') - expect(encodeWin32SafeName('NUL')).not.toBe('NUL') - expect(encodeWin32SafeName('PRN')).not.toBe('PRN') - expect(encodeWin32SafeName('LPT3')).not.toBe('LPT3') - - // no false positives - expect(encodeWin32SafeName('annuling')).toBe('annuling') - }) - - it('replaces end dots', () => { - const safe = encodeWin32SafeName('hello.') - expect(safe).not.toMatch(/\.$/) - }) - - it('replaces end spaces', () => { - const safe = encodeWin32SafeName('hehe ') - expect(safe).not.toMatch(/\s+$/) - }) - - it('can be reversed', () => { - const unsafe = 'hello|.*<>wo:rld' - const safe = encodeWin32SafeName(unsafe) - expect(decodeWin32SafeName(safe)).toEqual(unsafe) - }) -}) diff --git a/packages/blobs/src/util.ts b/packages/blobs/src/util.ts deleted file mode 100644 index 3aa1a97..0000000 --- a/packages/blobs/src/util.ts +++ /dev/null @@ -1,77 +0,0 @@ -import process from 'node:process' -import { getTracer, withActiveSpan } from '@netlify/otel' -import type { Span } from '@netlify/otel/opentelemetry' - -import { NF_ERROR, NF_REQUEST_ID } from './headers.ts' - -export class BlobsInternalError extends Error { - constructor(res: Response) { - let details = res.headers.get(NF_ERROR) || `${res.status} status code` - - if (res.headers.has(NF_REQUEST_ID)) { - details += `, ID: ${res.headers.get(NF_REQUEST_ID)}` - } - - super(`Netlify Blobs has generated an internal error (${details})`) - - this.name = 'BlobsInternalError' - } -} - -export const collectIterator = async (iterator: AsyncIterable): Promise => { - const result: T[] = [] - - for await (const item of iterator) { - result.push(item) - } - - return result -} - -export const isNodeError = (error: unknown): error is NodeJS.ErrnoException => error instanceof Error - -export type Logger = (...message: unknown[]) => void - -function percentEncode(str: string): string { - return str.replace(/./, (char) => { - return '%' + char.charCodeAt(0).toString(16).padStart(2, '0') - }) -} - -const invalidWin32File = /^(CON|COM[1-9]|LPT[1-9]|NUL|PRN|AUX)$/i - -/* - * On Windows, file paths can't include some valid blob/store key characters, so we URI-encode them. fixme: limitations - * - * Limitations: - * - this doesn't deal with long names (blob keys can be 600 chars, default on windows is max 260) - * For keys (which we don't need to decode) maybe a hash would be a better idea - */ -export function encodeWin32SafeName(string: string): string { - if (invalidWin32File.exec(string)) { - return percentEncode(string) - } - return encodeURIComponent(string).replace(/([*]|[. ]$)/g, percentEncode) -} - -// Names are URI-encoded on Windows, so we must decode them first. -export function decodeWin32SafeName(string: string): string { - return decodeURIComponent(string) -} - -export function encodeName(string: string): string { - return process.platform == 'win32' ? encodeWin32SafeName(string) : string -} - -export function decodeName(string: string): string { - return process.platform == 'win32' ? decodeWin32SafeName(string) : string -} - -// Allow users to pass in their own active span or defaults to creating a new active span -export function withSpan ReturnType>(span: Span | undefined, name: string, fn: F) { - if (span) return fn(span) - - return withActiveSpan(getTracer(), name, (span) => { - return fn(span) - }) -} diff --git a/packages/blobs/test/util.ts b/packages/blobs/test/util.ts deleted file mode 100644 index c898501..0000000 --- a/packages/blobs/test/util.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Buffer } from 'node:buffer' - -export const base64Encode = (input: string | object) => { - const payload = typeof input === 'string' ? input : JSON.stringify(input) - - return Buffer.from(payload).toString('base64') -} - -export const streamToString = async function streamToString(stream: NodeJS.ReadableStream): Promise { - const chunks: any[] = [] - - for await (const chunk of stream) { - chunks.push(chunk) - } - - const buffer = Buffer.concat(chunks) - - return buffer.toString('utf-8') -} diff --git a/packages/blobs/tsconfig.json b/packages/blobs/tsconfig.json deleted file mode 100644 index 83e9a4b..0000000 --- a/packages/blobs/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "allowImportingTsExtensions": true, - "emitDeclarationOnly": true, - "target": "ES2020", - "module": "nodenext", - "allowJs": true, - "declaration": true, - "declarationMap": false, - "sourceMap": false, - "outDir": "./dist", - "removeComments": false, - "strict": true, - "moduleResolution": "nodenext", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/blobs/tsup.config.ts b/packages/blobs/tsup.config.ts deleted file mode 100644 index afb1377..0000000 --- a/packages/blobs/tsup.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/server.ts', 'src/main.ts'], - tsconfig: 'tsconfig.json', - bundle: true, - format: ['cjs', 'esm'], - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/blobs/vitest.config.ts b/packages/blobs/vitest.config.ts deleted file mode 100644 index eff32b2..0000000 --- a/packages/blobs/vitest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - }, -}) diff --git a/packages/cache/.gitattributes b/packages/cache/.gitattributes deleted file mode 100644 index 6313b56..0000000 --- a/packages/cache/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto eol=lf diff --git a/packages/cache/.gitignore b/packages/cache/.gitignore deleted file mode 100644 index 6a5f751..0000000 --- a/packages/cache/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -*~ -*.swp -npm-debug.log -node_modules -/core -.eslintcache -.npmrc -.yarn-error.log -/coverage -/build -.vscode -/dist diff --git a/packages/cache/CHANGELOG.md b/packages/cache/CHANGELOG.md deleted file mode 100644 index a227e4c..0000000 --- a/packages/cache/CHANGELOG.md +++ /dev/null @@ -1,618 +0,0 @@ -# Changelog - -## [3.4.8](https://github.com/netlify/primitives/compare/cache-v3.4.7...cache-v3.4.8) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.4.5 to 4.4.6 - * @netlify/types bumped from 2.7.0 to 2.8.0 - -## [3.4.7](https://github.com/netlify/primitives/compare/cache-v3.4.6...cache-v3.4.7) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.4.4 to 4.4.5 - * @netlify/types bumped from 2.6.0 to 2.7.0 - -## [3.4.6](https://github.com/netlify/primitives/compare/cache-v3.4.5...cache-v3.4.6) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.4.3 to 4.4.4 - -## [3.4.5](https://github.com/netlify/primitives/compare/cache-v3.4.4...cache-v3.4.5) (2026-05-12) - - -### Bug Fixes - -* update readme badges to point to current repo ([#594](https://github.com/netlify/primitives/issues/594)) ([0e05d46](https://github.com/netlify/primitives/commit/0e05d46b645b66d20d01e824fe5b82a121b491a2)) - -## [3.4.4](https://github.com/netlify/primitives/compare/cache-v3.4.3...cache-v3.4.4) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.4.2 to 4.4.3 - * @netlify/types bumped from 2.5.0 to 2.6.0 - -## [3.4.3](https://github.com/netlify/primitives/compare/cache-v3.4.2...cache-v3.4.3) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.4.1 to 4.4.2 - * @netlify/types bumped from 2.4.0 to 2.5.0 - -## [3.4.2](https://github.com/netlify/primitives/compare/cache-v3.4.1...cache-v3.4.2) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.4.0 to 4.4.1 - * @netlify/types bumped from 2.3.0 to 2.4.0 - -## [3.4.1](https://github.com/netlify/primitives/compare/cache-v3.4.0...cache-v3.4.1) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.3.3 to 4.4.0 - -## [3.4.0](https://github.com/netlify/primitives/compare/cache-v3.3.5...cache-v3.4.0) (2026-02-27) - - -### Features - -* add SWR support to Cache API ([#597](https://github.com/netlify/primitives/issues/597)) ([fdab4e3](https://github.com/netlify/primitives/commit/fdab4e3ed6298d99c3ab8110b53c4c9bd4055a7a)) - -## [3.3.5](https://github.com/netlify/primitives/compare/cache-v3.3.4...cache-v3.3.5) (2026-02-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.2.1 to 2.3.0 - -## [3.3.4](https://github.com/netlify/primitives/compare/cache-v3.3.3...cache-v3.3.4) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.3.2 to 4.3.3 - * @netlify/types bumped from 2.2.0 to 2.3.0 - -## [3.3.3](https://github.com/netlify/primitives/compare/cache-v3.3.2...cache-v3.3.3) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.3.1 to 4.3.2 - -## [3.3.2](https://github.com/netlify/primitives/compare/cache-v3.3.1...cache-v3.3.2) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.3.0 to 4.3.1 - * @netlify/types bumped from 2.1.0 to 2.2.0 - -## [3.3.1](https://github.com/netlify/primitives/compare/cache-v3.3.0...cache-v3.3.1) (2025-11-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.2.0 to 2.2.1 - -## [3.3.0](https://github.com/netlify/primitives/compare/cache-v3.2.0...cache-v3.3.0) (2025-10-15) - - -### Features - -* add `fetch` parameter to `fetchWithCache` ([#482](https://github.com/netlify/primitives/issues/482)) ([6eff819](https://github.com/netlify/primitives/commit/6eff819fec72b74458269538e8ae48e944ee09d1)) - - -### Bug Fixes - -* make `fetchWithCache` stop throwing on uncacheable response ([#481](https://github.com/netlify/primitives/issues/481)) ([2a4da13](https://github.com/netlify/primitives/commit/2a4da13b5fde1d712484a498f4df0534770815c0)) - -## [3.2.0](https://github.com/netlify/primitives/compare/cache-v3.1.1...cache-v3.2.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.1.0 to 2.2.0 - * devDependencies - * @netlify/dev-utils bumped from 4.2.0 to 4.3.0 - * @netlify/types bumped from 2.0.3 to 2.1.0 - -## [3.1.1](https://github.com/netlify/primitives/compare/cache-v3.1.0...cache-v3.1.1) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.1.3 to 4.2.0 - -## [3.1.0](https://github.com/netlify/primitives/compare/cache-v3.0.11...cache-v3.1.0) (2025-09-05) - - -### Features - -* expose `cacheHeaders` method ([#445](https://github.com/netlify/primitives/issues/445)) ([54eda15](https://github.com/netlify/primitives/commit/54eda159219675696d0bdf34f471e0c2e84fe923)) - -## [3.0.11](https://github.com/netlify/primitives/compare/cache-v3.0.10...cache-v3.0.11) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.1.2 to 4.1.3 - * @netlify/types bumped from 2.0.2 to 2.0.3 - -## [3.0.10](https://github.com/netlify/primitives/compare/cache-v3.0.9...cache-v3.0.10) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.1.1 to 4.1.2 - -## [3.0.9](https://github.com/netlify/primitives/compare/cache-v3.0.8...cache-v3.0.9) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.1.0 to 4.1.1 - -## [3.0.8](https://github.com/netlify/primitives/compare/cache-v3.0.7...cache-v3.0.8) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.0.0 to 4.1.0 - -## [3.0.7](https://github.com/netlify/primitives/compare/cache-v3.0.6...cache-v3.0.7) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.3.0 to 4.0.0 - -## [3.0.6](https://github.com/netlify/primitives/compare/cache-v3.0.5...cache-v3.0.6) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.2.2 to 3.3.0 - -## [3.0.5](https://github.com/netlify/primitives/compare/cache-v3.0.4...cache-v3.0.5) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.2.1 to 3.2.2 - -## [3.0.4](https://github.com/netlify/primitives/compare/cache-v3.0.3...cache-v3.0.4) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.2.0 to 3.2.1 - -## [3.0.3](https://github.com/netlify/primitives/compare/cache-v3.0.2...cache-v3.0.3) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.1.1 to 3.2.0 - -## [3.0.2](https://github.com/netlify/primitives/compare/cache-v3.0.1...cache-v3.0.2) (2025-06-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.0.1 to 2.0.2 - -## [3.0.1](https://github.com/netlify/primitives/compare/cache-v3.0.0...cache-v3.0.1) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.1.0 to 3.1.1 - -## [3.0.0](https://github.com/netlify/primitives/compare/cache-v2.0.0...cache-v3.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Features - -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) - - -### Bug Fixes - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.0.0 to 2.1.0 - * devDependencies - * @netlify/dev-utils bumped from 3.0.0 to 3.1.0 - * @netlify/types bumped from 2.0.0 to 2.0.1 - -## [2.0.0](https://github.com/netlify/primitives/compare/cache-v1.11.2...cache-v2.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Bug Fixes - -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) -* retain request headers in cache lookups ([#204](https://github.com/netlify/primitives/issues/204)) ([6fa04b5](https://github.com/netlify/primitives/commit/6fa04b5990bafaecfef70cb9a510c24fd31a8e15)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 1.3.1 to 2.0.0 - * devDependencies - * @netlify/dev-utils bumped from 2.2.0 to 3.0.0 - * @netlify/types bumped from 1.2.0 to 2.0.0 - -## [1.11.2](https://github.com/netlify/primitives/compare/cache-v1.11.1...cache-v1.11.2) (2025-05-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.1.1 to 2.2.0 - * @netlify/types bumped from 1.1.1 to 1.2.0 - -## [1.11.1](https://github.com/netlify/primitives/compare/cache-v1.11.0...cache-v1.11.1) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 1.3.0 to 1.3.1 - * devDependencies - * @netlify/dev-utils bumped from 2.1.0 to 2.1.1 - * @netlify/types bumped from 1.1.0 to 1.1.1 - -## [1.11.0](https://github.com/netlify/primitives/compare/cache-v1.10.0...cache-v1.11.0) (2025-05-07) - - -### Features - -* add separate package for types ([#175](https://github.com/netlify/primitives/issues/175)) ([bb70188](https://github.com/netlify/primitives/commit/bb7018856ebda7a52ccff291cb306478e2853468)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 1.2.0 to 1.3.0 - * devDependencies - * @netlify/types bumped from 1.0.0 to 1.1.0 - -## [1.10.0](https://github.com/netlify/primitives/compare/cache-v1.9.0...cache-v1.10.0) (2025-05-06) - - -### Features - -* make `fetchWithCache` use `waitUntil` if available ([#161](https://github.com/netlify/primitives/issues/161)) ([dd9b7fd](https://github.com/netlify/primitives/commit/dd9b7fd5d0bd8b236d446d3211bfe880fedf4887)) - - -### Bug Fixes - -* make type definition for CacheStorage and Cache be the same as the one in TypeScript's generated dom type definition ([#166](https://github.com/netlify/primitives/issues/166)) ([c3ec2ed](https://github.com/netlify/primitives/commit/c3ec2ed3f1037f5a216a73af36050c314e7d6c89)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 1.1.0 to 1.2.0 - * devDependencies - * @netlify/dev-utils bumped from 2.0.0 to 2.1.0 - -## [1.9.0](https://github.com/netlify/primitives/compare/cache-v1.8.2...cache-v1.9.0) (2025-05-02) - - -### Features - -* add `runtime` and `runtime-utils` packages ([#150](https://github.com/netlify/primitives/issues/150)) ([be2cbf0](https://github.com/netlify/primitives/commit/be2cbf05cd3b73a795b54f94b7f51dacbcf6ef34)) - - -### Bug Fixes - -* manually tee response body in `fetchWithCache` ([#158](https://github.com/netlify/primitives/issues/158)) ([199590f](https://github.com/netlify/primitives/commit/199590f583711e92e133eedb694ce85e4cc7c7d4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 1.0.0 to 1.1.0 - * devDependencies - * @netlify/dev-utils bumped from 1.1.0 to 2.0.0 - -## [1.8.2](https://github.com/netlify/primitives/compare/cache-v1.8.1...cache-v1.8.2) (2025-04-15) - - -### Bug Fixes - -* simplify build command ([#118](https://github.com/netlify/primitives/issues/118)) ([bd744d5](https://github.com/netlify/primitives/commit/bd744d5cce2f46d895bc063325a9d89bb769df99)) - -## [1.8.1](https://github.com/netlify/primitives/compare/cache-v1.8.0...cache-v1.8.1) (2025-04-15) - - -### Bug Fixes - -* use a proxy for the `caches` export ([#105](https://github.com/netlify/primitives/issues/105)) ([c4c11ce](https://github.com/netlify/primitives/commit/c4c11ce426dc9b9323d223e9b820f5dc11a3e1ee)) - -## [1.8.0](https://github.com/netlify/primitives/compare/cache-v1.5.0...cache-v1.8.0) (2025-04-15) - - -### Features - -* add `caches` export ([#102](https://github.com/netlify/primitives/issues/102)) ([371780d](https://github.com/netlify/primitives/commit/371780d80c1e52dbf904fe1f5858bb7dd5183791)) -* add `logger` option ([#96](https://github.com/netlify/primitives/issues/96)) ([4017d6e](https://github.com/netlify/primitives/commit/4017d6e05ed92b95dc151411cb304f6fb3b1e5e3)) -* make Cache API operations no-ops when context is null ([#90](https://github.com/netlify/primitives/issues/90)) ([240871d](https://github.com/netlify/primitives/commit/240871d1d20f99b0dbe48eeae14980d4d6b9ba1e)) -* move logger to request context ([#98](https://github.com/netlify/primitives/issues/98)) ([c0faba6](https://github.com/netlify/primitives/commit/c0faba688229ae52041c0f0bf74c4a214de9f056)) - - -### Bug Fixes - -* emit `Operation` enum ([#94](https://github.com/netlify/primitives/issues/94)) ([eed9bd5](https://github.com/netlify/primitives/commit/eed9bd5cc04f567c4baa07cc0904291a2b94f90c)) - - -### Miscellaneous Chores - -* release 1.6.1 ([7010f09](https://github.com/netlify/primitives/commit/7010f09dc3d8640a983c14cf9a325ee7615c5c77)) - -## [1.7.1](https://github.com/netlify/primitives/compare/cache-v1.5.0...cache-v1.7.1) (2025-03-19) - - -### Features - -* add `logger` option ([#96](https://github.com/netlify/primitives/issues/96)) ([4017d6e](https://github.com/netlify/primitives/commit/4017d6e05ed92b95dc151411cb304f6fb3b1e5e3)) -* make Cache API operations no-ops when context is null ([#90](https://github.com/netlify/primitives/issues/90)) ([240871d](https://github.com/netlify/primitives/commit/240871d1d20f99b0dbe48eeae14980d4d6b9ba1e)) -* move logger to request context ([#98](https://github.com/netlify/primitives/issues/98)) ([c0faba6](https://github.com/netlify/primitives/commit/c0faba688229ae52041c0f0bf74c4a214de9f056)) - - -### Bug Fixes - -* emit `Operation` enum ([#94](https://github.com/netlify/primitives/issues/94)) ([eed9bd5](https://github.com/netlify/primitives/commit/eed9bd5cc04f567c4baa07cc0904291a2b94f90c)) - - -### Miscellaneous Chores - -* release 1.6.1 ([7010f09](https://github.com/netlify/primitives/commit/7010f09dc3d8640a983c14cf9a325ee7615c5c77)) - -## [1.7.0](https://github.com/netlify/primitives/compare/cache-v1.5.0...cache-v1.7.0) (2025-03-19) - - -### Features - -* add `logger` option ([#96](https://github.com/netlify/primitives/issues/96)) ([4017d6e](https://github.com/netlify/primitives/commit/4017d6e05ed92b95dc151411cb304f6fb3b1e5e3)) -* make Cache API operations no-ops when context is null ([#90](https://github.com/netlify/primitives/issues/90)) ([240871d](https://github.com/netlify/primitives/commit/240871d1d20f99b0dbe48eeae14980d4d6b9ba1e)) - - -### Bug Fixes - -* emit `Operation` enum ([#94](https://github.com/netlify/primitives/issues/94)) ([eed9bd5](https://github.com/netlify/primitives/commit/eed9bd5cc04f567c4baa07cc0904291a2b94f90c)) - - -### Miscellaneous Chores - -* release 1.6.1 ([7010f09](https://github.com/netlify/primitives/commit/7010f09dc3d8640a983c14cf9a325ee7615c5c77)) - -## [1.6.1](https://github.com/netlify/primitives/compare/cache-v1.5.0...cache-v1.6.1) (2025-03-19) - - -### Features - -* make Cache API operations no-ops when context is null ([#90](https://github.com/netlify/primitives/issues/90)) ([240871d](https://github.com/netlify/primitives/commit/240871d1d20f99b0dbe48eeae14980d4d6b9ba1e)) - - -### Bug Fixes - -* emit `Operation` enum ([#94](https://github.com/netlify/primitives/issues/94)) ([eed9bd5](https://github.com/netlify/primitives/commit/eed9bd5cc04f567c4baa07cc0904291a2b94f90c)) - - -### Miscellaneous Chores - -* release 1.6.1 ([7010f09](https://github.com/netlify/primitives/commit/7010f09dc3d8640a983c14cf9a325ee7615c5c77)) - -## [1.6.0](https://github.com/netlify/primitives/compare/cache-v1.5.0...cache-v1.6.0) (2025-03-19) - - -### Features - -* make Cache API operations no-ops when context is null ([#90](https://github.com/netlify/primitives/issues/90)) ([240871d](https://github.com/netlify/primitives/commit/240871d1d20f99b0dbe48eeae14980d4d6b9ba1e)) - -## [1.5.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.5.0) (2025-03-18) - - -### Features - -* log failures in `cache.put` ([#38](https://github.com/netlify/primitives/issues/38)) ([b9f356a](https://github.com/netlify/primitives/commit/b9f356a2bd1b604f3fa66c032eefa099138c317b)) - - -### Bug Fixes - -* disable code-splitting to workaround an issue in deno 2.x's `deno cache` functionality ([#85](https://github.com/netlify/primitives/issues/85)) ([557a0c1](https://github.com/netlify/primitives/commit/557a0c10f9aad4d4ab4a4c49c31cf13b65bc554a)) - - -### Miscellaneous Chores - -* release 1.5.0 ([1224f51](https://github.com/netlify/primitives/commit/1224f5193c51d6a26be02962f46b4957fa595794)) - -## [1.4.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.4.0) (2025-03-12) - - -### Features - -* add `getContext` method ([#77](https://github.com/netlify/primitives/issues/77)) ([ee879ae](https://github.com/netlify/primitives/commit/ee879aece706ba5e34fe1e8d46392580c4a7a7b9)) -* export time interval constants ([#81](https://github.com/netlify/primitives/issues/81)) ([60f048b](https://github.com/netlify/primitives/commit/60f048b7ba42cfee1e62725dbc67633b738d4308)) -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - - -### Miscellaneous Chores - -* release 1.3.0 ([6e7237e](https://github.com/netlify/primitives/commit/6e7237ec38221382fb2d4ec49f0c184705bd68dc)) -* release 1.4.0 ([8c7c297](https://github.com/netlify/primitives/commit/8c7c2973f6d7c6b36eadfad3ce0e8f93bb84440f)) - -## [1.3.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.3.0) (2025-03-12) - - -### Features - -* add `getContext` method ([#77](https://github.com/netlify/primitives/issues/77)) ([ee879ae](https://github.com/netlify/primitives/commit/ee879aece706ba5e34fe1e8d46392580c4a7a7b9)) -* export time interval constants ([#81](https://github.com/netlify/primitives/issues/81)) ([60f048b](https://github.com/netlify/primitives/commit/60f048b7ba42cfee1e62725dbc67633b738d4308)) -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - - -### Miscellaneous Chores - -* release 1.3.0 ([6e7237e](https://github.com/netlify/primitives/commit/6e7237ec38221382fb2d4ec49f0c184705bd68dc)) - -## [1.3.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.3.0) (2025-02-24) - - -### Features - -* add `getContext` method ([#77](https://github.com/netlify/primitives/issues/77)) ([ee879ae](https://github.com/netlify/primitives/commit/ee879aece706ba5e34fe1e8d46392580c4a7a7b9)) -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - - -### Miscellaneous Chores - -* release 1.3.0 ([6e7237e](https://github.com/netlify/primitives/commit/6e7237ec38221382fb2d4ec49f0c184705bd68dc)) - -## [1.2.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.2.0) (2025-02-22) - - -### Features - -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - -## [1.2.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.2.0) (2025-02-22) - - -### Features - -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - -## [1.2.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.2.0) (2025-02-22) - - -### Features - -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - -## [1.2.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.2.0) (2025-02-22) - - -### Features - -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - -## [1.2.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.2.0) (2025-02-22) - - -### Features - -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) - -## [1.2.0](https://github.com/netlify/primitives/compare/cache-v1.1.0...cache-v1.2.0) (2025-02-22) - - -### Features - -* fix release ([0b1d397](https://github.com/netlify/primitives/commit/0b1d3975c6383b0376cbf8e4c5d2541cd9c43e4d)) -* update package.json ([6f59f75](https://github.com/netlify/primitives/commit/6f59f75851edf9ef76c254b9b3ddd33d4f1e56a3)) diff --git a/packages/cache/CODE_OF_CONDUCT.md b/packages/cache/CODE_OF_CONDUCT.md deleted file mode 100644 index fad7632..0000000 --- a/packages/cache/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,60 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making -participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, -disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take -appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, -issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any -contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the -project or its community. Examples of representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed representative at an online or offline -event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at -david@netlify.com. All complaints will be reviewed and investigated and will result in a response that is deemed -necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to -the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent -repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at -[http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/packages/cache/CONTRIBUTING.md b/packages/cache/CONTRIBUTING.md deleted file mode 100644 index 5dfd0c0..0000000 --- a/packages/cache/CONTRIBUTING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributions - -🎉 Thanks for considering contributing to this project! 🎉 - -These guidelines will help you send a pull request. - -Please note that this project is not intended to be used outside my own projects so new features are unlikely to be -accepted. - -If you're submitting an issue instead, please skip this document. - -If your pull request is related to a typo or the documentation being unclear, please click on the relevant page's `Edit` -button (pencil icon) and directly suggest a correction instead. - -This project was made with ❤️. The simplest way to give back is by starring and sharing it online. - -Everyone is welcome regardless of personal background. We enforce a [Code of conduct](CODE_OF_CONDUCT.md) in order to -promote a positive and inclusive environment. - -# Development process - -First fork and clone the repository. If you're not sure how to do this, please watch -[these videos](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). - -Run: - -```bash -npm install -``` - -Make sure everything is correctly setup with: - -```bash -npm test -``` - -After submitting the pull request, please make sure the Continuous Integration checks are passing. - -## Releasing - -1. Merge the release PR -2. Switch to the default branch `git checkout main` -3. Pull latest changes `git pull` -4. Publish the package `npm publish` diff --git a/packages/cache/LICENSE b/packages/cache/LICENSE deleted file mode 100644 index 182fc3f..0000000 --- a/packages/cache/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2022 Netlify - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/cache/README.md b/packages/cache/README.md deleted file mode 100644 index 69d5f12..0000000 --- a/packages/cache/README.md +++ /dev/null @@ -1,14 +0,0 @@ -[![Build](https://github.com/netlify/primitives/workflows/Build/badge.svg)](https://github.com/netlify/primitives/actions) -[![Node](https://img.shields.io/node/v/@netlify/cache.svg?logo=node.js)](https://www.npmjs.com/package/@netlify/cache) - -# @netlify/cache - -TypeScript utilities for interacting with the Netlify cache. - -## Installation - -You can install `@netlify/cache` via npm: - -```shell -npm install @netlify/cache -``` diff --git a/packages/cache/netlify.toml b/packages/cache/netlify.toml deleted file mode 100644 index 01cc9b0a..0000000 --- a/packages/cache/netlify.toml +++ /dev/null @@ -1,13 +0,0 @@ -[build] -command = "" -publish = "src" - -[[headers]] -for = "/*.js" -[headers.values] -Content-Type = "application/javascript; charset=utf-8" - -[[headers]] -for = "/*.ts" -[headers.values] -Content-Type = "application/typescript; charset=utf-8" diff --git a/packages/cache/package.json b/packages/cache/package.json deleted file mode 100644 index 2de3e1a..0000000 --- a/packages/cache/package.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "@netlify/cache", - "version": "3.4.8", - "description": "TypeScript utilities for interacting with the Netlify cache", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json", - "./bootstrap": { - "require": { - "types": "./dist/bootstrap/main.d.cts", - "default": "./dist/bootstrap/main.cjs" - }, - "import": { - "types": "./dist/bootstrap/main.d.ts", - "default": "./dist/bootstrap/main.js" - }, - "default": { - "types": "./dist/bootstrap/main.d.ts", - "default": "./dist/bootstrap/main.js" - } - } - }, - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "test": "run-s build test:ci", - "test:dev": "run-s build test:dev:*", - "test:ci": "run-s build test:ci:*", - "test:dev:vitest": "vitest", - "test:dev:vitest:watch": "vitest watch", - "test:ci:vitest": "vitest run", - "publint": "npx -y publint --strict" - }, - "keywords": [ - "netlify", - "cdn", - "cache", - "cachestorage" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/cache" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/types": "2.8.0", - "npm-run-all2": "^7.0.2", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "@netlify/runtime-utils": "2.3.0" - } -} diff --git a/packages/cache/src/bootstrap/cache.test.ts b/packages/cache/src/bootstrap/cache.test.ts deleted file mode 100644 index 454de6d..0000000 --- a/packages/cache/src/bootstrap/cache.test.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { MockFetch } from '@netlify/dev-utils' -import { describe, test, expect, vi } from 'vitest' - -import { NetlifyCache } from './cache.js' -import { Operation } from './environment.js' -import { ERROR_CODES } from './errors.js' -import { decodeHeaders } from '../test/headers.js' - -const host = 'my-site.netlify' -const url = 'https://example.netlify/.netlify/cache' -const token = 'mock-token' -const userAgent = 'netlify-functions@1.0.0' - -describe('Cache API', () => { - describe('add', () => { - test('makes an HTTP request and adds the response to the cache', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const response = new Response('

Hello world

', { headers }) - const mockFetch = new MockFetch() - .get({ - url: 'https://netlify.com', - response, - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (headers) => { - expect(headers.Authorization).toBe(`Bearer ${token}`) - expect(headers['netlify-forwarded-host']).toBe(host) - expect(headers['netlify-programmable-status']).toBe('200') - expect(headers['netlify-programmable-store']).toBe('my-cache') - - const decodedHeaders = decodeHeaders(headers['netlify-programmable-headers']) - - expect(decodedHeaders.get('content-type')).toBe('text/html') - }, - response: new Response(null, { status: 201 }), - }) - .inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Write) - - return { host, token, url } - }, - name: 'my-cache', - userAgent, - }) - - await cache.add('https://netlify.com') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - }) - - describe('delete', () => { - test('returns a response if there is a matching entry in the cache, otherwise returns undefined', async () => { - const mockFetch = new MockFetch() - .delete({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (headers) => { - expect(headers.Authorization).toBe(`Bearer ${token}`) - expect(headers['netlify-forwarded-host']).toBe(host) - }, - response: new Response(null, { status: 202 }), - }) - .inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Delete) - - return { host, token, url } - }, - name: 'my-cache', - userAgent, - }) - - expect(await cache.delete(new Request('https://netlify.com'))).toBe(true) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('is a no-op when the `getContext` callback returns `null`', async () => { - const mockFetch = new MockFetch().inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Delete) - - return null - }, - name: 'my-cache', - userAgent, - }) - - expect(await cache.delete(new Request('https://netlify.com'))).toBe(true) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - }) - - describe('match', () => { - test('returns a response if there is a matching entry in the cache, otherwise returns undefined', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const response = new Response('

Hello world

', { headers }) - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (headers) => { - expect(headers.Authorization).toBe(`Bearer ${token}`) - expect(headers['netlify-forwarded-host']).toBe(host) - }, - response, - }) - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2Fsome-path', - response: new Response(null, { status: 404 }), - }) - .inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Read) - - return { host, token, url } - }, - name: 'my-cache', - userAgent, - }) - - const hitResponse = await cache.match(new Request('https://netlify.com')) - const missResponse = await cache.match(new Request('https://netlify.com/some-path')) - - mockFetch.restore() - - expect(mockFetch.requests.length).toBe(2) - - expect(hitResponse?.status).toBe(200) - expect(await hitResponse?.text()).toBe('

Hello world

') - expect(hitResponse?.headers.get('authorization')).toBeNull() - expect(hitResponse?.headers.get('netlify-programmable-status')).toBeNull() - expect(hitResponse?.headers.get('netlify-programmable-store')).toBeNull() - expect([...(hitResponse as Response).headers]).toStrictEqual([...headers]) - - expect(missResponse).toBeUndefined() - }) - - test('retains request headers, discarding any forbidden ones', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const response = new Response('

Hello world

', { headers }) - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (headers) => { - expect(headers.Authorization).toBe(`Bearer ${token}`) - expect(headers['netlify-forwarded-host']).toBe(host) - expect(headers['x-custom-header']).toBe('foo') - expect(headers['netlify-programmable-store']).toBe('my-cache') - expect(headers['netlify-programmable-headers']).toBeUndefined() - }, - response, - }) - .inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Read) - - return { host, token, url } - }, - name: 'my-cache', - userAgent, - }) - - const cached = await cache.match( - new Request('https://netlify.com', { - headers: { - 'X-Custom-Header': 'foo', - 'Netlify-Programmable-Headers': 'forbidden', - 'Netlify-Programmable-Store': 'not the right store', - 'Netlify-Forwarded-Host': 'this would break things', - }, - }), - ) - - mockFetch.restore() - - expect(mockFetch.requests.length).toBe(1) - - expect(cached?.status).toBe(200) - expect(await cached?.text()).toBe('

Hello world

') - }) - - test('is a no-op when the `getContext` callback returns `null`', async () => { - const mockFetch = new MockFetch().inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Read) - - return null - }, - name: 'my-cache', - userAgent, - }) - - expect(await cache.match(new Request('https://netlify.com'))).toBe(undefined) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - }) - - describe('put', () => { - test('adds a response to the cache', async () => { - const resourceHeaders = new Headers() - resourceHeaders.set('content-type', 'text/html') - resourceHeaders.set('x-custom-header', 'foobar') - - const mockFetch = new MockFetch() - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - body: async (body) => { - expect(body).toBe('

Hello world

') - }, - headers: (headers) => { - expect(headers.Authorization).toBe(`Bearer ${token}`) - expect(headers['netlify-forwarded-host']).toBe(host) - expect(headers['netlify-programmable-status']).toBe('200') - expect(headers['netlify-programmable-store']).toBe('my-cache') - - const decodedHeaders = decodeHeaders(headers['netlify-programmable-headers']) - expect([...decodedHeaders]).toStrictEqual([...resourceHeaders]) - }, - response: new Response(null, { status: 201 }), - }) - .inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Write) - - return { host, token, url } - }, - name: 'my-cache', - userAgent, - }) - - const response = new Response('

Hello world

', { headers: resourceHeaders }) - - await cache.put(new Request('https://netlify.com'), response) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('logs a message when the response is not added to the cache', async () => { - const logger = vi.fn() - const mockFetch = new MockFetch() - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (headers) => { - expect(headers.Authorization).toBe(`Bearer ${token}`) - expect(headers['netlify-forwarded-host']).toBe(host) - }, - response: new Response(null, { headers: { 'netlify-programmable-error': 'no_ttl' }, status: 400 }), - }) - .inject() - const cache = new NetlifyCache({ - getContext: () => ({ host, logger, token, url }), - name: 'my-cache', - userAgent, - }) - - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const response = new Response('

Hello world

', { headers }) - - await cache.put(new Request('https://netlify.com'), response) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - - expect(logger).toHaveBeenCalledWith(`Failed to write to the cache: ${ERROR_CODES.no_ttl}`) - }) - - test('is a no-op when the `getContext` callback returns `null`', async () => { - const mockFetch = new MockFetch().inject() - const cache = new NetlifyCache({ - getContext: ({ operation }) => { - expect(operation).toBe(Operation.Write) - - return null - }, - name: 'my-cache', - userAgent, - }) - - expect(await cache.put(new Request('https://netlify.com'), new Response('Hello world'))).toBe(undefined) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - }) -}) diff --git a/packages/cache/src/bootstrap/cache.ts b/packages/cache/src/bootstrap/cache.ts deleted file mode 100644 index 15bc83b..0000000 --- a/packages/cache/src/bootstrap/cache.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { base64Encode } from '@netlify/runtime-utils' - -import { EnvironmentOptions, RequestContext, Operation, RequestContextFactory } from './environment.js' - -import { ERROR_CODES, GENERIC_ERROR } from './errors.js' -import * as HEADERS from '../headers.js' - -const allowedProtocols = new Set(['http:', 'https:']) - -// These headers will be discarded from any cached resource and will not be -// sent to the API. -const discardedHeaders = new Set(['cookie', 'content-encoding', 'content-length']) - -// Headers with these prefixes will be discarded from requests when doing cache -// lookups; allowing clients to set them could lead to unexpected behavior. -const forbiddenHeaderPrefixes = ['netlify-programmable-', 'x-nf-'] - -type NetlifyCacheOptions = EnvironmentOptions & { - name: string -} - -const getInternalHeaders = Symbol('getInternalHeaders') -const serializeRequestHeaders = Symbol('serializeRequestHeaders') -const serializeResponseHeaders = Symbol('serializeResponseHeaders') - -export class NetlifyCache implements Cache { - #getContext: RequestContextFactory - #name: string - #userAgent?: string - - constructor({ getContext, name, userAgent }: NetlifyCacheOptions) { - this.#getContext = getContext - this.#name = name - this.#userAgent = userAgent - } - - private [getInternalHeaders](requestContext: RequestContext) { - const { host, token } = requestContext - const headers: Record = { - Authorization: `Bearer ${token}`, - [HEADERS.ResourceStore]: this.#name, - } - - if (host) { - headers[HEADERS.NetlifyForwardedHost] = host - } - - if (this.#userAgent) { - headers[HEADERS.UserAgent] = this.#userAgent - } - - return headers - } - - private [serializeRequestHeaders](headers: Headers) { - const headersMap: Record = {} - - headers.forEach((value, key) => { - const normalizedKey = key.toLowerCase() - - // Discard any internal headers that the client should not be setting. - for (const prefix of forbiddenHeaderPrefixes) { - if (normalizedKey.startsWith(prefix)) { - return - } - } - - headersMap[normalizedKey] = value - }) - - return headersMap - } - - private [serializeResponseHeaders](headers: Headers) { - const headersMap: Record = {} - - headers.forEach((value, key) => { - if (discardedHeaders.has(key)) { - return - } - - // When there are multiple values for the same header, the `value` argument - // will have them as a comma-separated list. The exception is `set-cookie`, - // where the callback fires multiple times, each with a different `value`. - if (key === 'set-cookie') { - headersMap[key] = headersMap[key] || [] - headersMap[key].push(value) - } else { - headersMap[key] = value.split(',') - } - }) - - return base64Encode(JSON.stringify(headersMap)) - } - - async add(request: RequestInfo | URL): Promise { - await this.put(new Request(request), await fetch(request)) - } - - async addAll(requests: RequestInfo[]): Promise { - await Promise.allSettled(requests.map((request) => this.add(request))) - } - - async delete(request: RequestInfo | URL) { - const context = this.#getContext({ operation: Operation.Delete }) - - if (context) { - const resourceURL = extractAndValidateURL(request) - - await fetch(`${context.url}/${toCacheKey(resourceURL)}`, { - headers: this[getInternalHeaders](context), - method: 'DELETE', - }) - } - - return true - } - - async keys(_request?: Request | URL) { - // Not implemented. - return [] - } - - async match(request: RequestInfo | URL) { - try { - const context = this.#getContext({ operation: Operation.Read }) - - if (!context) { - return - } - - const resourceURL = extractAndValidateURL(request) - const cacheURL = `${context.url}/${toCacheKey(resourceURL)}` - const response = await fetch(cacheURL, { - headers: { - ...(request instanceof Request ? this[serializeRequestHeaders](request.headers) : {}), - ...this[getInternalHeaders](context), - }, - method: 'GET', - }) - - if (!response.ok) { - return - } - - return response - } catch { - // no-op - } - } - - async matchAll(request?: RequestInfo | URL, _options?: CacheQueryOptions): Promise { - if (!request) { - return [] - } - - const res = await this.match(request) - - return res ? [res] : [] - } - - async put(request: RequestInfo | URL, response: Response) { - if (!response.ok) { - throw new TypeError(`Cannot cache response with status ${response.status}.`) - } - - if (request instanceof Request && request.method !== 'GET') { - throw new TypeError(`Cannot cache response to ${request.method} request.`) - } - - if (response.status === 206) { - throw new TypeError('Cannot cache response to a range request (206 Partial Content).') - } - - if (response.headers.get('vary')?.includes('*')) { - throw new TypeError("Cannot cache response with 'Vary: *' header.") - } - - const context = this.#getContext({ operation: Operation.Write }) - - if (!context) { - return - } - - const resourceURL = extractAndValidateURL(request) - - const cacheResponse = await fetch(`${context.url}/${toCacheKey(resourceURL)}`, { - body: response.body, - headers: { - ...this[getInternalHeaders](context), - [HEADERS.ResourceHeaders]: this[serializeResponseHeaders](response.headers), - [HEADERS.ResourceStatus]: response.status.toString(), - }, - // @ts-expect-error https://github.com/whatwg/fetch/pull/1457 - duplex: 'half', - method: 'POST', - }) - - if (!cacheResponse.ok) { - const errorDetail = cacheResponse.headers?.get(HEADERS.ErrorDetail) ?? '' - const errorMessage = ERROR_CODES[errorDetail as keyof typeof ERROR_CODES] || GENERIC_ERROR - - context.logger?.(`Failed to write to the cache: ${errorMessage}`) - } - } -} - -const extractAndValidateURL = (input: RequestInfo | URL): URL => { - let url: URL - - if (input instanceof Request) { - url = new URL(input.url) - } else { - try { - url = new URL(String(input)) - } catch { - throw new TypeError(`${input} is not a valid URL.`) - } - } - - if (!allowedProtocols.has(url.protocol)) { - throw new TypeError( - `Cannot cache response for URL with unsupported protocol (${url.protocol}). Supported protocols are ${[ - ...allowedProtocols, - ].join(', ')}.`, - ) - } - - return url -} - -const toCacheKey = (url: URL) => encodeURIComponent(url.toString()) diff --git a/packages/cache/src/bootstrap/cachestorage.ts b/packages/cache/src/bootstrap/cachestorage.ts deleted file mode 100644 index ac7080e..0000000 --- a/packages/cache/src/bootstrap/cachestorage.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NetlifyCache } from './cache.js' -import type { EnvironmentOptions } from './environment.js' - -export class NetlifyCacheStorage { - #environmentOptions: EnvironmentOptions - #stores: Map - - constructor(environmentOptions: EnvironmentOptions) { - this.#environmentOptions = environmentOptions - this.#stores = new Map() - } - - open(name: string): Promise { - let store = this.#stores.get(name) - - if (!store) { - store = new NetlifyCache({ - ...this.#environmentOptions, - name, - }) - - this.#stores.set(name, store) - } - - return Promise.resolve(store) - } - - has(name: string): Promise { - return Promise.resolve(this.#stores.has(name)) - } - - delete(name: string): Promise { - return Promise.resolve(this.#stores.delete(name)) - } - - keys(): Promise { - return Promise.resolve([...this.#stores.keys()]) - } - - async match(request: RequestInfo | URL, options?: MultiCacheQueryOptions): Promise { - if (options?.cacheName) { - return this.#stores.get(options.cacheName)?.match(request) - } - - for (const store of this.#stores.values()) { - const response = await store.match(request) - - if (response === undefined) { - return - } - } - } -} diff --git a/packages/cache/src/bootstrap/environment.ts b/packages/cache/src/bootstrap/environment.ts deleted file mode 100644 index 3621437..0000000 --- a/packages/cache/src/bootstrap/environment.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type Logger = (...args: any[]) => void - -export interface EnvironmentOptions { - getContext: RequestContextFactory - userAgent?: string -} - -export enum Operation { - Delete = 'delete', - Read = 'read', - Write = 'write', -} - -export type RequestContextFactory = (options: { operation: Operation }) => RequestContext | null - -export interface RequestContext { - host: string - logger?: Logger - token: string - url: string -} diff --git a/packages/cache/src/bootstrap/errors.ts b/packages/cache/src/bootstrap/errors.ts deleted file mode 100644 index 2afaf57..0000000 --- a/packages/cache/src/bootstrap/errors.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const ERROR_CODES = { - invalid_vary: - 'Responses must not use unsupported directives of the `Netlify-Vary` header (https://ntl.fyi/cache_api_invalid_vary).', - no_cache: - 'Responses must not set cache control headers with the `private`, `no-cache` or `no-store` directives (https://ntl.fyi/cache_api_no_cache).', - low_ttl: - 'Responses must have a cache control header with a `max-age` or `s-maxage` directive (https://ntl.fyi/cache_api_low_ttl).', - no_directive: - 'Responses must have a cache control header with caching directives (https://ntl.fyi/cache_api_no_directive).', - no_ttl: - 'Responses must have a cache control header with a `max-age` or `s-maxage` directive (https://ntl.fyi/cache_api_no_ttl).', - no_status: 'Responses must specify a status code (https://ntl.fyi/cache_api_no_status).', - invalid_directive: - 'Responses must have a cache control header with caching directives (https://ntl.fyi/cache_api_invalid_directive).', - status: 'Responses must have a status code between 200 and 299 (https://ntl.fyi/cache_api_status).', -} - -export const GENERIC_ERROR = 'The server has returned an unexpected error (https://ntl.fyi/cache_api_error).' diff --git a/packages/cache/src/bootstrap/main.ts b/packages/cache/src/bootstrap/main.ts deleted file mode 100644 index a29955a..0000000 --- a/packages/cache/src/bootstrap/main.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { Operation, RequestContextFactory } from './environment.ts' -export { NetlifyCache } from './cache.ts' -export { NetlifyCacheStorage } from './cachestorage.ts' diff --git a/packages/cache/src/cache-headers/cache-headers.test.ts b/packages/cache/src/cache-headers/cache-headers.test.ts deleted file mode 100644 index 4bb8e2b..0000000 --- a/packages/cache/src/cache-headers/cache-headers.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { describe, test, expect } from 'vitest' - -import { cacheHeaders } from '../main.js' -import { ONE_YEAR } from './cache-headers.js' - -describe('`cacheHaders`', () => { - describe('`tags`', () => { - test('With `ttl`', () => { - expect(cacheHeaders({ tags: ['tag1', 'tag2'], ttl: 50 })).toStrictEqual({ - 'netlify-cdn-cache-control': 's-maxage=50', - 'netlify-cache-tag': 'tag1,tag2', - }) - }) - - test('With `overrideDeployRevalidation`', () => { - expect(cacheHeaders({ overrideDeployRevalidation: 'tag3', tags: ['tag1', 'tag2'] })).toStrictEqual({ - 'netlify-cache-id': 'tag3', - 'netlify-cache-tag': 'tag1,tag2', - }) - }) - - test('Throws when input is not array of strings', () => { - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ tags: ['tag1', true] })).toThrow() - }) - }) - - describe('`ttl`', () => { - test('Accepts a number', () => { - expect(cacheHeaders({ ttl: 50 })).toStrictEqual({ 'netlify-cdn-cache-control': 's-maxage=50' }) - }) - - test('Accepts a string containing a number', () => { - // @ts-expect-error Wrong type - expect(cacheHeaders({ ttl: '50' })).toStrictEqual({ 'netlify-cdn-cache-control': 's-maxage=50' }) - }) - - test('With `durable`', () => { - expect(cacheHeaders({ durable: true, ttl: 50 })).toStrictEqual({ - 'netlify-cdn-cache-control': 's-maxage=50,durable', - }) - }) - - test('Throws when input is not a number', () => { - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ ttl: new Date() })).toThrow() - }) - - test('Throws when number is not integer', () => { - expect(() => cacheHeaders({ ttl: 31.5 })).toThrow() - - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ ttl: '31.5' })).toThrow() - }) - - test('Throws when number is negative', () => { - expect(() => cacheHeaders({ ttl: -50 })).toThrow() - }) - }) - - describe('`swr`', () => { - test('Accepts a number', () => { - expect(cacheHeaders({ swr: 50 })).toStrictEqual({ 'netlify-cdn-cache-control': 'stale-while-revalidate=50' }) - }) - - test('With `ttl`', () => { - expect(cacheHeaders({ ttl: 10, swr: 50 })).toStrictEqual({ - 'netlify-cdn-cache-control': 's-maxage=10,stale-while-revalidate=50', - }) - }) - - test('With `ttl` and `durable`', () => { - expect(cacheHeaders({ durable: true, ttl: 10, swr: 50 })).toStrictEqual({ - 'netlify-cdn-cache-control': 's-maxage=10,stale-while-revalidate=50,durable', - }) - }) - - test('Accepts a boolean', () => { - expect(cacheHeaders({ swr: true })).toStrictEqual({ - 'netlify-cdn-cache-control': `stale-while-revalidate=${ONE_YEAR}`, - }) - }) - - test('Accepts a string containing a number', () => { - // @ts-expect-error Wrong type - expect(cacheHeaders({ swr: '50' })).toStrictEqual({ 'netlify-cdn-cache-control': 'stale-while-revalidate=50' }) - }) - - test('Throws when input is not a number', () => { - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ swr: new Date() })).toThrow() - }) - - test('Throws when number is not integer', () => { - expect(() => cacheHeaders({ swr: 31.5 })).toThrow() - }) - - test('Throws when number is negative', () => { - expect(() => cacheHeaders({ swr: -50 })).toThrow() - }) - }) - - describe('`vary`', () => { - test('With `cookie`', () => { - expect(cacheHeaders({ vary: { cookie: 'cookie1' } })).toStrictEqual({ 'netlify-vary': 'cookie=cookie1' }) - expect(cacheHeaders({ vary: { cookie: ['cookie1'] } })).toStrictEqual({ 'netlify-vary': 'cookie=cookie1' }) - expect(cacheHeaders({ vary: { cookie: ['cookie1', 'cookie2'] } })).toStrictEqual({ - 'netlify-vary': 'cookie=cookie1|cookie2', - }) - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { cookie: true } })).toThrow() - }) - - test('With `country`', () => { - expect(cacheHeaders({ vary: { country: 'pt' } })).toStrictEqual({ 'netlify-vary': 'country=pt' }) - expect(cacheHeaders({ vary: { country: ['es', 'pt'] } })).toStrictEqual({ 'netlify-vary': 'country=es|pt' }) - expect(cacheHeaders({ vary: { country: ['es', ['br', 'pt']] } })).toStrictEqual({ - 'netlify-vary': 'country=es|br+pt', - }) - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { country: true } })).toThrow() - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { country: ['pt', 3] } })).toThrow() - }) - - test('With `header`', () => { - expect(cacheHeaders({ vary: { header: 'Device-Type' } })).toStrictEqual({ 'netlify-vary': 'header=Device-Type' }) - expect(cacheHeaders({ vary: { header: ['Device-Type'] } })).toStrictEqual({ - 'netlify-vary': 'header=Device-Type', - }) - expect(cacheHeaders({ vary: { header: ['Device-Type', 'App-Version'] } })).toStrictEqual({ - 'netlify-vary': 'header=Device-Type|App-Version', - }) - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { header: true } })).toThrow() - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { header: ['Device-Type', 3] } })).toThrow() - }) - - test('With `language`', () => { - expect(cacheHeaders({ vary: { language: 'pt' } })).toStrictEqual({ 'netlify-vary': 'language=pt' }) - expect(cacheHeaders({ vary: { language: ['es', 'pt'] } })).toStrictEqual({ 'netlify-vary': 'language=es|pt' }) - expect(cacheHeaders({ vary: { language: ['es', ['nl', 'pt']] } })).toStrictEqual({ - 'netlify-vary': 'language=es|nl+pt', - }) - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { language: true } })).toThrow() - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { language: ['pt', 3] } })).toThrow() - }) - - test('With `query`', () => { - expect(cacheHeaders({ vary: { query: true } })).toStrictEqual({ 'netlify-vary': 'query' }) - expect(cacheHeaders({ vary: { query: 'page' } })).toStrictEqual({ 'netlify-vary': 'query=page' }) - expect(cacheHeaders({ vary: { query: ['page'] } })).toStrictEqual({ - 'netlify-vary': 'query=page', - }) - expect(cacheHeaders({ vary: { query: ['page', 'per_page'] } })).toStrictEqual({ - 'netlify-vary': 'query=page|per_page', - }) - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { query: 3 } })).toThrow() - // @ts-expect-error Wrong type - expect(() => cacheHeaders({ vary: { query: ['page', 3] } })).toThrow() - }) - - test('With multiple', () => { - expect(cacheHeaders({ vary: { header: ['Device-Type', 'App-Version'], query: true } })).toStrictEqual({ - 'netlify-vary': 'header=Device-Type|App-Version,query', - }) - expect( - cacheHeaders({ vary: { country: ['es', ['br', 'pt']], header: ['Device-Type', 'App-Version'], query: true } }), - ).toStrictEqual({ - 'netlify-vary': 'country=es|br+pt,header=Device-Type|App-Version,query', - }) - }) - }) -}) diff --git a/packages/cache/src/cache-headers/cache-headers.ts b/packages/cache/src/cache-headers/cache-headers.ts deleted file mode 100644 index a24e11a..0000000 --- a/packages/cache/src/cache-headers/cache-headers.ts +++ /dev/null @@ -1,118 +0,0 @@ -import * as HEADERS from '../headers.js' -import { CacheSettings, VaryOptions } from './options.js' -import { - ensureArray, - requireArrayOfStrings, - requireArrayOfStringsWithNesting, - requirePositiveInteger, -} from './validation.js' - -export const ONE_YEAR = 60 * 24 * 365 - -export const cacheHeaders = (cacheSettings: CacheSettings) => { - const { durable, overrideDeployRevalidation: id, tags, ttl, swr, vary } = cacheSettings - const headers: Record = {} - const cacheControlDirectives: string[] = [] - - if (ttl) { - const ttlValue = requirePositiveInteger('ttl', ttl) - - if (ttlValue > 0) { - cacheControlDirectives.push(`s-maxage=${ttlValue}`) - } - } - - if (swr) { - // Accept the bare stale-while-revalidate directive and set to one year. - const swrValue = swr === true ? ONE_YEAR : requirePositiveInteger('swr', swr) - - if (swrValue > 0) { - cacheControlDirectives.push(`stale-while-revalidate=${swrValue}`) - } - } - - if (cacheControlDirectives.length > 0) { - if (durable) { - cacheControlDirectives.push('durable') - } - - headers[HEADERS.NetlifyCdnCacheControl] = cacheControlDirectives.join(',') - } - - if (tags) { - headers[HEADERS.NetlifyCacheTag] = requireArrayOfStrings('tags', tags).join(',') - } - - const netlifyVary = getNetlifyVary(vary) - - if (netlifyVary) { - headers[HEADERS.NetlifyVary] = netlifyVary - } - - if (id) { - headers[HEADERS.NetlifyCacheId] = requireArrayOfStrings('id', ensureArray(id)).join(',') - } - - return headers -} - -const getNetlifyVary = (varyOptions?: VaryOptions) => { - if (!varyOptions) { - return null - } - - const { cookie, country, header, language, query } = varyOptions - const directives: string[] = [] - - if (cookie) { - directives.push(`cookie=${requireArrayOfStrings('cookie', ensureArray(cookie)).join('|')}`) - } - - if (country) { - directives.push(`country=${requireArrayOfStringsWithNesting('country', ensureArray(country), '+').join('|')}`) - } - - if (header) { - directives.push(`header=${requireArrayOfStrings('header', ensureArray(header)).join('|')}`) - } - - if (language) { - directives.push(`language=${requireArrayOfStringsWithNesting('language', ensureArray(language), '+').join('|')}`) - } - - if (query) { - if (query === true) { - directives.push(`query`) - } else { - directives.push(`query=${requireArrayOfStrings('query', ensureArray(query)).join('|')}`) - } - } - - if (directives.length === 0) { - return null - } - - return directives.join(',') -} - -export const applyHeaders = (subject: Headers, headersObject: Record) => { - for (const name in headersObject) { - if (name === HEADERS.NetlifyCdnCacheControl) { - subject.set(name, headersObject[name]) - } else { - subject.append(name, headersObject[name]) - } - } -} - -export const setCacheHeaders = (response: Response, cacheSettings: CacheSettings): Response => { - if (!(response instanceof Response)) { - throw new TypeError('Input must be a Response object.') - } - - const newResponse = new Response(response.body, response) - - applyHeaders(newResponse.headers, cacheHeaders(cacheSettings)) - - return newResponse -} diff --git a/packages/cache/src/cache-headers/options.ts b/packages/cache/src/cache-headers/options.ts deleted file mode 100644 index 9153b37..0000000 --- a/packages/cache/src/cache-headers/options.ts +++ /dev/null @@ -1,84 +0,0 @@ -export interface CacheSettings { - /** - * Persist the response in the durable cache, shared across all CDN nodes. - * - * {@link} https://ntl.fyi/durable - */ - durable?: boolean - - /** - * Override the default behavior of revalidating cached responses with new - * deploys. You must provide one or more values that will be registered as - * cache tags for you to purge the responses on-demand. - * - * {@link} https://ntl.fyi/cache-id - */ - overrideDeployRevalidation?: string | string[] - - /** - * Provide one or more cache tags to associate with the response. You can use - * these tags to revalidate responses on-demand, making sure you target the - * specific responses you want based on your application logic. - * - * {@link} https://ntl.fyi/cache-tags - */ - tags?: string[] - - /** - * Define the period of time (in seconds) during which the response can be - * considered fresh. After this period, the response will revalidated in - * the background if used with the `stale-while-revalidate` directive, - * otherwise the response will be discarded. - * - * {@link} https://ntl.fyi/cache-ttl - */ - ttl?: number - - /** - * Define the period of time (in seconds) after the response is considered - * stale (set by the `ttl` property) and during which it can still - * be served, while starting a revalidation in the background. - * - * {@link} https://ntl.fyi/cache-swr - */ - swr?: boolean | number - - /** - * Defines how cache key variations are created for the response, giving you - * fine-grained control over which parts of a request are taken into - * consideration for matching cache objects. - * - * {@link} https://ntl.fyi/cache-vary - */ - vary?: VaryOptions -} - -export interface VaryOptions { - /** - * Define cache key variations based on a subset of cookie keys. - */ - cookie?: string | string[] - - /** - * Define cache key variations based on the geographical origin of the request. - */ - country?: string | (string | string[])[] - - /** - * Define cache key variations based on your custom request headers and most - * standard request headers. - */ - header?: string | string[] - - /** - * Define cache key variations for one or more individual languages or custom - * language groups. - */ - language?: string | (string | string[])[] - - /** - * Define cache key variations based on a specific subset of query parameters - * included with a request or all request query parameters. - */ - query?: boolean | string | string[] -} diff --git a/packages/cache/src/cache-headers/validation.ts b/packages/cache/src/cache-headers/validation.ts deleted file mode 100644 index 07d720e..0000000 --- a/packages/cache/src/cache-headers/validation.ts +++ /dev/null @@ -1,33 +0,0 @@ -export const ensureArray = (value: any): string[] => (Array.isArray(value) ? value : [value]) - -export const requireArrayOfStrings = (name: string, value: any): string[] => { - if (!Array.isArray(value) || value.some((part) => typeof part !== 'string' || part.length === 0)) { - throw new TypeError(`'${name}' must be an array of non-empty strings.`) - } - - return value -} - -export const requireArrayOfStringsWithNesting = (name: string, value: any, joiner: string): string[] => { - if (!Array.isArray(value)) { - throw new TypeError(`'${name}' must be an array.`) - } - - return value.map((part, index) => { - if (typeof part === 'string') { - return part - } - - return requireArrayOfStrings(`${name}[${index}]`, part).join(joiner) - }) -} - -export const requirePositiveInteger = (name: string, value: any) => { - const number = Number.parseFloat(value) - - if (Number.isNaN(number) || !Number.isInteger(number) || number < 0 || number === Number.POSITIVE_INFINITY) { - throw new TypeError(`'${name}' must be a positive integer number.`) - } - - return number -} diff --git a/packages/cache/src/cache-status/cache-status.test.ts b/packages/cache/src/cache-status/cache-status.test.ts deleted file mode 100644 index 72ecb03..0000000 --- a/packages/cache/src/cache-status/cache-status.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { describe, test, expect } from 'vitest' - -import { getCacheStatus, needsRevalidation, parseCacheStatusValues, parseCacheStatusValue } from './cache-status.js' - -describe('`parseCacheStatus`', () => { - test('Accepts a string with the values of the `cache-status` header', () => { - expect(getCacheStatus(`"Netlify Durable"; fwd=miss; stored=true; ttl=3600`)).toStrictEqual({ - hit: false, - caches: { - durable: { - fresh: false, - hit: false, - stored: true, - ttl: 3600, - }, - }, - }) - }) - - test('Accepts a `Headers` object', () => { - const headers = new Headers() - headers.set('cache-status', `"Netlify Durable"; fwd=miss; stored=true; ttl=3600`) - - expect(getCacheStatus(headers)).toStrictEqual({ - hit: false, - caches: { - durable: { - fresh: false, - hit: false, - stored: true, - ttl: 3600, - }, - }, - }) - }) - - test('Accepts a `Response` object', () => { - const response = new Response('Hello world', { - headers: { - 'cache-status': `"Netlify Durable"; fwd=miss; stored=true; ttl=3600`, - }, - }) - - expect(getCacheStatus(response)).toStrictEqual({ - hit: false, - caches: { - durable: { - fresh: false, - hit: false, - stored: true, - ttl: 3600, - }, - }, - }) - }) - - test('Throws if the input is of an unsupported type', () => { - // @ts-expect-error Wrong type - expect(() => getCacheStatus({})).toThrow() - }) -}) - -describe('`parseCacheStatusValue`', () => { - test('Extracts the name of the cache and any attributes', () => { - expect(parseCacheStatusValue(`"Netlify Durable"; hit; ttl=1234`)).toStrictEqual({ - attributes: { hit: '', ttl: '1234' }, - name: 'netlify durable', - }) - - expect(parseCacheStatusValue(`"Netlify Durable"; fwd=miss`)).toStrictEqual({ - attributes: { fwd: 'miss' }, - name: 'netlify durable', - }) - - expect(parseCacheStatusValue(`"Netlify Edge"`)).toStrictEqual({ - attributes: {}, - name: 'netlify edge', - }) - }) - - test('Extracts the cache name even if it does not have wrapping quotes', () => { - expect(parseCacheStatusValue(`something`)).toStrictEqual({ - attributes: {}, - name: 'something', - }) - }) -}) - -describe('`needsRevalidation`', () => { - test('Returns true when the durable cache signals client revalidation', () => { - const response = new Response('stale content', { - headers: { - 'cache-status': `"Netlify Durable"; hit; ttl=-5; detail=client-revalidate`, - }, - }) - - expect(needsRevalidation(response)).toBe(true) - }) - - test('Returns false when there is no detail parameter', () => { - const response = new Response('fresh content', { - headers: { - 'cache-status': `"Netlify Durable"; hit; ttl=3600`, - }, - }) - - expect(needsRevalidation(response)).toBe(false) - }) - - test('Returns false when there is no cache-status header', () => { - const response = new Response('content') - - expect(needsRevalidation(response)).toBe(false) - }) - - test('Returns false when the detail value is not client-revalidate', () => { - const response = new Response('content', { - headers: { - 'cache-status': `"Netlify Durable"; hit; detail=something-else`, - }, - }) - - expect(needsRevalidation(response)).toBe(false) - }) -}) - -describe('`parseCacheStatusValues`', () => { - test('Ignores non-Netlify caches', () => { - expect(parseCacheStatusValues('ExampleCache; hit; detail=MEMORY')).toBeNull() - - expect(parseCacheStatusValues(`ExampleCache; hit; detail=MEMORY,"Netlify Durable"; fwd=miss`)).toStrictEqual({ - hit: false, - caches: { - durable: { - fresh: false, - hit: false, - stored: false, - ttl: 0, - }, - }, - }) - }) - - test('Handles a single Netlify cache', () => { - expect(parseCacheStatusValues(`"Netlify Durable"; fwd=miss; stored=true; ttl=3600`)).toStrictEqual({ - hit: false, - caches: { - durable: { - fresh: false, - hit: false, - stored: true, - ttl: 3600, - }, - }, - }) - - expect(parseCacheStatusValues(`"Netlify Edge"; hit`)).toStrictEqual({ - hit: true, - caches: { - edge: { - fresh: true, - hit: true, - }, - }, - }) - }) - - test('Handles multiple Netlify caches', () => { - expect( - parseCacheStatusValues(`"Netlify Edge"; hit,"Netlify Durable"; fwd=miss; stored=true; ttl=3600`), - ).toStrictEqual({ - hit: true, - caches: { - durable: { - fresh: false, - hit: false, - stored: true, - ttl: 3600, - }, - edge: { - fresh: true, - hit: true, - }, - }, - }) - - expect( - parseCacheStatusValues(`"Netlify Edge"; fwd=stale,"Netlify Durable"; fwd=miss; stored=true; ttl=3600`), - ).toStrictEqual({ - hit: false, - caches: { - durable: { - fresh: false, - hit: false, - stored: true, - ttl: 3600, - }, - edge: { - fresh: false, - hit: false, - }, - }, - }) - }) -}) diff --git a/packages/cache/src/cache-status/cache-status.ts b/packages/cache/src/cache-status/cache-status.ts deleted file mode 100644 index 4f3a05d..0000000 --- a/packages/cache/src/cache-status/cache-status.ts +++ /dev/null @@ -1,167 +0,0 @@ -import * as HEADERS from '../headers.js' - -const CACHE_DURABLE = 'netlify durable' -const CACHE_EDGE = 'netlify edge' - -interface CacheStatus { - /** - * Whether the response was served from a Netlify cache. - */ - hit: boolean - - /** - * Granular information about how the different Netlify caches have - * contributed to the delivery of the response. - */ - caches: { - /** - * How the response has interacted with the durable cache. - * - * {@link} https://ntl.fyi/durable - */ - durable?: { - hit: boolean - fresh: boolean - stored?: boolean - ttl: number - } - - /** - * How the response has interacted with the edge cache. - * - * {@link} https://ntl.fyi/edge-cache - */ - edge?: { - hit: boolean - fresh: boolean - } - } -} - -export const parseCacheStatusValue = (value: string) => { - const parts = value.split(';').map((part) => part.trim()) - const [namePart, ...attributeParts] = parts - const name = (namePart ?? '').replace(/"/g, '').toLowerCase() - const attributes = attributeParts.reduce( - (acc, part) => { - const [key, value = ''] = part.split('=') - - return { - ...acc, - [key]: value, - } - }, - {} as Record, - ) - - return { - attributes, - name, - } -} - -export const parseCacheStatusValues = (cacheStatusValues: string): CacheStatus | null => { - const cacheStatus: CacheStatus = { - hit: false, - caches: {}, - } - - for (const value of cacheStatusValues.split(',')) { - const { attributes, name } = parseCacheStatusValue(value) - - if (name === CACHE_EDGE) { - const hit = attributes.hit !== undefined - - cacheStatus.caches.edge = { - hit, - fresh: hit && attributes.fwd !== 'stale', - } - - cacheStatus.hit = cacheStatus.hit || hit - - continue - } - - if (name === CACHE_DURABLE) { - let ttl = 0 - - if (attributes.ttl !== undefined) { - const parsedTTL = Number.parseInt(attributes.ttl) - - if (!Number.isNaN(parsedTTL)) { - ttl = parsedTTL - } - } - - const hit = attributes.hit !== undefined - - cacheStatus.caches.durable = { - hit, - fresh: hit && attributes.fwd !== 'stale', - stored: attributes.stored === 'true', - ttl, - } - - cacheStatus.hit = cacheStatus.hit || hit - - continue - } - } - - if (Object.keys(cacheStatus.caches).length === 0) { - return null - } - - return cacheStatus -} - -type ParseCacheStatus = { - (header: string): CacheStatus | null - (headers: Headers): CacheStatus | null - (response: Response): CacheStatus | null -} - -/** - * Returns whether a cached response includes a signal that the client should - * perform a background revalidation. This may happen when using the Cache API - * with the `stale-while-revalidate` directive, since unlike the regular cache, - * the client is the one responsible for explicitly inserting new entries into - * the cache. So when this returns `true`, the caller should fetch the resource - * and write the fresh response back to the cache with `cache.put()`. - */ -export const needsRevalidation = (response: Response): boolean => { - const header = response.headers.get(HEADERS.CacheStatus) - if (!header) { - return false - } - - for (const value of header.split(',')) { - const { attributes, name } = parseCacheStatusValue(value) - if (name === CACHE_DURABLE && attributes.detail === 'client-revalidate') { - return true - } - } - - return false -} - -/** - * Retrieves information about how a response has interacted with Netlify's - * global caching infrastructure, including whether the response has been - * served by a cache and whether it's fresh or stale. - */ -export const getCacheStatus: ParseCacheStatus = (input: string | Headers | Response): CacheStatus | null => { - if (typeof input === 'string') { - return parseCacheStatusValues(input) - } - - if (input instanceof Headers) { - return parseCacheStatusValues(input.get(HEADERS.CacheStatus) ?? '') - } - - if (input instanceof Response) { - return parseCacheStatusValues(input.headers.get(HEADERS.CacheStatus) ?? '') - } - - throw new TypeError('`getCacheStatus` expects a string, a `Headers` object or a `Response` object.') -} diff --git a/packages/cache/src/constants.test.ts b/packages/cache/src/constants.test.ts deleted file mode 100644 index 566bbeb..0000000 --- a/packages/cache/src/constants.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { test, expect } from 'vitest' - -import { MINUTE, HOUR, DAY, WEEK, YEAR } from './main.js' - -test('Exports time interval constants', () => { - expect(MINUTE).toBe(60) - expect(HOUR).toBe(60 * 60) - expect(DAY).toBe(60 * 60 * 24) - expect(WEEK).toBe(60 * 60 * 24 * 7) - expect(YEAR).toBe(60 * 60 * 24 * 365) -}) diff --git a/packages/cache/src/constants.ts b/packages/cache/src/constants.ts deleted file mode 100644 index 9ac176d..0000000 --- a/packages/cache/src/constants.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Number of seconds in one minute. - */ -export const MINUTE = 60 - -/** - * Number of seconds in one hour. - */ -export const HOUR = 60 * MINUTE - -/** - * Number of seconds in one day. - */ -export const DAY = 24 * HOUR - -/** - * Number of seconds in one week. - */ -export const WEEK = 7 * DAY - -/** - * Number of seconds in one year. - */ -export const YEAR = 365 * DAY diff --git a/packages/cache/src/fetchwithcache.test.ts b/packages/cache/src/fetchwithcache.test.ts deleted file mode 100644 index 261ca45..0000000 --- a/packages/cache/src/fetchwithcache.test.ts +++ /dev/null @@ -1,520 +0,0 @@ -import { MockFetch } from '@netlify/dev-utils' -import { describe, test, expect, beforeEach, afterAll, vi } from 'vitest' - -import { NetlifyCacheStorage } from './bootstrap/cachestorage.js' -import { fetchWithCache } from './fetchwithcache.js' -import { sleep } from './test/util.js' -import { decodeHeaders } from './test/headers.js' - -const host = 'host.netlify' -const url = 'https://example.netlify/.netlify/cache' -const token = 'mock-token' - -const originalCaches = globalThis.caches - -beforeEach(async () => { - globalThis.caches = new NetlifyCacheStorage({ - getContext: () => ({ host, token, url }), - }) -}) - -afterAll(() => { - globalThis.caches = originalCaches -}) - -describe('`fetchWithCache`', () => { - test('Returns the response from cache, if available', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const cachedResponse = new Response('

Hello world

', { headers }) - const mockFetch = new MockFetch() - .post({ - response: new Response(null, { status: 201 }), - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .get({ - response: () => cachedResponse, - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .inject() - const resourceURL = 'https://netlify.com' - - const cache = await caches.open('') - await cache.put(resourceURL, cachedResponse) - - const response = await fetchWithCache(resourceURL) - - expect(await response.text()).toBe('

Hello world

') - - mockFetch.restore() - - expect(mockFetch.requests.length).toBe(2) - }) - - test('Respects request headers', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('vary', 'x-custom-header') - - const cachedResponse = new Response('

Hello world

', { headers }) - const mockFetch = new MockFetch() - .post({ - response: new Response(null, { status: 201 }), - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .get({ - headers: (headers) => { - expect(headers.vary).toBe('x-custom-header') - }, - response: () => cachedResponse, - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .inject() - const resourceURL = 'https://netlify.com' - - const cache = await caches.open('') - await cache.put(resourceURL, cachedResponse) - - const response = await fetchWithCache(resourceURL, { - headers: { - vary: 'x-custom-header', - }, - }) - - expect(await response.text()).toBe('

Hello world

') - - mockFetch.restore() - - expect(mockFetch.requests.length).toBe(2) - }) - - test('Throws when used with a method other than GET', async () => { - const mockFetch = new MockFetch().inject() - const resourceURL = 'https://netlify.com' - - expect(() => fetchWithCache(resourceURL, { method: 'POST' })).rejects.toThrowError() - expect(() => fetchWithCache(resourceURL, { method: 'PUT' })).rejects.toThrowError() - expect(() => fetchWithCache(new Request(resourceURL, { method: 'POST' }))).rejects.toThrowError() - expect(() => fetchWithCache(new Request(resourceURL, { method: 'PUT' }))).rejects.toThrowError() - - mockFetch.restore() - - expect(mockFetch.requests.length).toBe(0) - }) - - describe('When not in the cache, fetches the resource and adds it to the cache', () => { - test('Without a `onCachePut` handler and no `waitUntil` available', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const cacheOptions = { - tags: ['tag1', 'tag2'], - ttl: 30, - } - const ac = new AbortController() - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 404 }), - }) - .post({ - body: async (body) => { - expect(body).toBe('

Hello world

') - }, - headers: async (reqHeaders) => { - const headers = decodeHeaders(reqHeaders['netlify-programmable-headers']) - - expect(headers.get('netlify-cache-tag')).toBe(cacheOptions.tags.join(', ')) - expect(headers.get('netlify-cdn-cache-control')).toBe(`s-maxage=${cacheOptions.ttl}`) - }, - response: () => - new Promise((resolve) => { - ac.signal.onabort = () => resolve(new Response(null, { status: 201 })) - }), - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: () => new Response('

Hello world

', { headers }), - }) - .get({ url: 'https://netlify.com/', response: new Response('

Hello world

', { headers }) }) - .inject() - const resourceURL = 'https://netlify.com' - - // `fetchWithCache` doesn't resolve until the cache put resolves. - expect(await Promise.race([fetchWithCache(resourceURL, cacheOptions), sleep(50, 'timeout')])).toBe('timeout') - - ac.abort() - - const cached = await fetchWithCache(resourceURL, cacheOptions) - expect(await cached.text()).toBe('

Hello world

') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('Without a `onCachePut` handler and with `waitUntil` available', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const cacheOptions = { - tags: ['tag1', 'tag2'], - ttl: 30, - } - const ac = new AbortController() - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 404 }), - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (reqHeaders) => { - const headers = decodeHeaders(reqHeaders['netlify-programmable-headers']) - - expect(headers.get('netlify-cache-tag')).toBe(cacheOptions.tags.join(', ')) - expect(headers.get('netlify-cdn-cache-control')).toBe(`s-maxage=${cacheOptions.ttl}`) - }, - response: () => - new Promise((resolve) => { - ac.signal.onabort = () => resolve(new Response(null, { status: 201 })) - }), - }) - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response('

Hello world

', { headers }), - }) - .get({ - url: 'https://netlify.com/', - response: new Response('

Hello world

', { headers }), - }) - .inject() - const resourceURL = 'https://netlify.com' - const waitUntil = vi.fn() - - // @ts-expect-error - globalThis.Netlify = { - context: { - waitUntil, - }, - } - - // `fetchWithCache` resolves without the cache put having resolved. - const fresh = await fetchWithCache(resourceURL, cacheOptions) - expect(await fresh.text()).toBe('

Hello world

') - - // @ts-expect-error - delete globalThis.Netlify - - expect(ac.signal.aborted).toBe(false) - expect(waitUntil).toHaveBeenCalledOnce() - - ac.abort() - - const cached = await fetchWithCache(resourceURL, cacheOptions) - expect(await cached.text()).toBe('

Hello world

') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('With a `onCachePut` handler', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - headers.set('x-custom-header', 'foobar') - - const cacheOptions = { - tags: ['tag1', 'tag2'], - ttl: 30, - } - const ac = new AbortController() - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 404 }), - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (reqHeaders) => { - const headers = decodeHeaders(reqHeaders['netlify-programmable-headers']) - - expect(headers.get('netlify-cache-tag')).toBe(cacheOptions.tags.join(', ')) - expect(headers.get('netlify-cdn-cache-control')).toBe(`s-maxage=${cacheOptions.ttl}`) - }, - response: () => - new Promise((resolve) => { - ac.signal.onabort = () => resolve(new Response(null, { status: 201 })) - }), - }) - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response('

Hello world

', { headers }), - }) - .get({ - url: 'https://netlify.com/', - response: new Response('

Hello world

', { headers }), - }) - .inject() - const resourceURL = 'https://netlify.com' - const onCachePut = vi.fn() - - // `fetchWithCache` resolves without the cache put having resolved. - const fresh = await fetchWithCache(resourceURL, { - ...cacheOptions, - onCachePut, - }) - expect(await fresh.text()).toBe('

Hello world

') - - expect(ac.signal.aborted).toBe(false) - expect(onCachePut).toHaveBeenCalledOnce() - - ac.abort() - - const cached = await fetchWithCache(resourceURL, cacheOptions) - expect(await cached.text()).toBe('

Hello world

') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - }) - - test('Uses the exported `caches` proxy', async () => { - const html = '

Hello world

' - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(html), - }) - .get({ - url: 'https://netlify.com/', - response: new Response(html), - }) - .inject() - const resourceURL = 'https://netlify.com' - const responseWithCache = await fetchWithCache(resourceURL) - expect(await responseWithCache.text()).toBe('

Hello world

') - - // @ts-expect-error - delete globalThis.caches - - const responseWithProxy = await fetchWithCache(resourceURL) - expect(await responseWithProxy.text()).toBe('

Hello world

') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('Accepts a custom `fetch` implementation', async () => { - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 404 }), - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 201 }), - }) - .inject() - const customFetch: typeof globalThis.fetch = async () => new Response('rijwiel') - - const response = await fetchWithCache('https://netlify.com', { fetch: customFetch }) - expect(await response.text()).toBe('rijwiel') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - describe('SWR revalidation', () => { - test('Triggers background revalidation on cache hit with SWR signal', async () => { - const staleBody = '

Stale

' - const freshBody = '

Fresh

' - const cacheOptions = { - tags: ['tag1'], - ttl: 60, - } - - const staleHeaders = new Headers() - staleHeaders.set('cache-status', '"Netlify Durable"; hit; ttl=-10; detail=client-revalidate') - - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(staleBody, { headers: staleHeaders }), - }) - .get({ - url: 'https://netlify.com/', - response: new Response(freshBody), - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - headers: (reqHeaders) => { - const headers = decodeHeaders(reqHeaders['netlify-programmable-headers']) - - expect(headers.get('netlify-cache-tag')).toBe('tag1') - expect(headers.get('netlify-cdn-cache-control')).toBe('s-maxage=60') - }, - response: new Response(null, { status: 201 }), - }) - .inject() - - const response = await fetchWithCache('https://netlify.com', cacheOptions) - expect(await response.text()).toBe(staleBody) - - // Wait for the fire-and-forget revalidation to complete. - await sleep(10) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('Uses waitUntil for background revalidation when available', async () => { - const staleHeaders = new Headers() - staleHeaders.set('cache-status', '"Netlify Durable"; hit; ttl=-10; detail=client-revalidate') - - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response('

Stale

', { headers: staleHeaders }), - }) - .get({ - url: 'https://netlify.com/', - response: new Response('

Fresh

'), - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 201 }), - }) - .inject() - - const waitUntil = vi.fn() - - // @ts-expect-error - globalThis.Netlify = { context: { waitUntil } } - - const response = await fetchWithCache('https://netlify.com') - expect(await response.text()).toBe('

Stale

') - expect(waitUntil).toHaveBeenCalledOnce() - - // @ts-expect-error - delete globalThis.Netlify - - // Wait for the revalidation to complete. - await waitUntil.mock.calls[0][0] - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('Uses onCachePut for background revalidation when provided', async () => { - const staleHeaders = new Headers() - staleHeaders.set('cache-status', '"Netlify Durable"; hit; ttl=-10; detail=client-revalidate') - - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response('

Stale

', { headers: staleHeaders }), - }) - .get({ - url: 'https://netlify.com/', - response: new Response('

Fresh

'), - }) - .post({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 201 }), - }) - .inject() - - const onCachePut = vi.fn() - - const response = await fetchWithCache('https://netlify.com', { onCachePut }) - expect(await response.text()).toBe('

Stale

') - expect(onCachePut).toHaveBeenCalledOnce() - - // Wait for the revalidation to complete. - await onCachePut.mock.calls[0][0] - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('Does not trigger revalidation for cache hits without SWR signal', async () => { - const headers = new Headers() - headers.set('content-type', 'text/html') - - const cachedResponse = new Response('

Hello

', { headers }) - const mockFetch = new MockFetch() - .post({ - response: new Response(null, { status: 201 }), - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .get({ - response: () => cachedResponse, - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .inject() - - const cache = await caches.open('') - await cache.put('https://netlify.com', cachedResponse) - - const response = await fetchWithCache('https://netlify.com') - expect(await response.text()).toBe('

Hello

') - - mockFetch.restore() - - // Only the cache.put POST and cache.match GET — no origin fetch. - expect(mockFetch.requests.length).toBe(2) - expect(mockFetch.fulfilled).toBe(true) - }) - - test('Background revalidation errors do not affect the caller', async () => { - const staleHeaders = new Headers() - staleHeaders.set('cache-status', '"Netlify Durable"; hit; ttl=-10; detail=client-revalidate') - - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response('

Stale

', { headers: staleHeaders }), - }) - .get({ - url: 'https://netlify.com/', - response: new Error('Network error'), - }) - .inject() - - const response = await fetchWithCache('https://netlify.com') - expect(await response.text()).toBe('

Stale

') - - // Wait for the fire-and-forget revalidation to settle. - await sleep(10) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) - }) - - test('Does not throw an error when response returns a 5xx error', async () => { - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(null, { status: 404 }), - }) - .get({ - url: 'https://netlify.com/', - response: new Response('Internal Server Error', { status: 500 }), - }) - .inject() - const resourceURL = 'https://netlify.com' - - const response = await fetchWithCache(resourceURL) - - expect(response.status).toBe(500) - expect(await response.text()).toBe('Internal Server Error') - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) -}) diff --git a/packages/cache/src/fetchwithcache.ts b/packages/cache/src/fetchwithcache.ts deleted file mode 100644 index cbfc5c4..0000000 --- a/packages/cache/src/fetchwithcache.ts +++ /dev/null @@ -1,196 +0,0 @@ -import type { NetlifyGlobal } from '@netlify/types' - -import type { NetlifyCache } from './bootstrap/cache.js' -import { applyHeaders, cacheHeaders } from './cache-headers/cache-headers.js' -import type { CacheSettings } from './cache-headers/options.js' -import { needsRevalidation } from './cache-status/cache-status.js' -import { caches } from './polyfill.js' - -type GlobalScope = typeof globalThis & { Netlify?: NetlifyGlobal } - -const requestInitOptions = [ - 'method', - 'keepalive', - 'headers', - 'body', - 'redirect', - 'integrity', - 'signal', - 'credentials', - 'mode', - 'referrer', - 'referrerPolicy', - 'window', - 'dispatcher', - 'duplex', -] - -type CacheOptions = CacheSettings & { - /** - * A `Cache` instance or the name of the cache that should be used. If not - * set, a cache without a name (i.e. `""`) will be used. - */ - cache?: NetlifyCache | string - - /** - * A custom `fetch` implementation to be used instead of the native one. - */ - fetch?: typeof globalThis.fetch - - /** - * When `fetchWithCache` fetches a new response and adds it to the cache, the - * `Promise` it returns waits for both the network call to finish and for the - * response to be cached. Customize this behavior by setting a `onCachePut` - * handler that receives the cache write `Promise`, giving you the option to - * handle it as you like. This lets you remove the cache write from the "hot - * path" and run it in the background. - */ - onCachePut?: (cachePut: Promise) => void | Promise -} - -const isRequestInit = (input: any): input is RequestInit => { - if (typeof input !== 'object') { - return false - } - - for (const property of requestInitOptions) { - if (property in input) { - return true - } - } - - return false -} - -type FetchWithCache = { - (request: string | URL | Request, init?: RequestInit): Promise - (request: string | URL | Request, cacheSettings?: CacheOptions): Promise - (request: string | URL | Request, init: RequestInit, cacheSettings?: CacheOptions): Promise -} - -/** - * Serves a resource from the Cache API if available, otherwise it's fetched - * from the network and added to the cache. It's a drop-in replacement for - * `fetch`, supporting the same arguments and return value. A third (optional) - * argument makes it possible to set the caching configuration of the response - * as it's added to the cache, overridding any cache control settings it sets. - * It returns a `Promise` that resolves with the resulting `Response` object, - * whether it comes from the cache or from the network. - */ -export const fetchWithCache: FetchWithCache = async ( - requestOrURL: string | URL | Request, - optionsOrCacheSettings?: RequestInit | CacheSettings, - cacheOptionsParam?: CacheOptions, -) => { - let cacheOptions: CacheOptions - let requestInit: RequestInit - - if (isRequestInit(optionsOrCacheSettings)) { - cacheOptions = cacheOptionsParam || {} - requestInit = optionsOrCacheSettings - } else { - cacheOptions = optionsOrCacheSettings || {} - requestInit = {} - } - - const request = new Request(requestOrURL, requestInit) - - if (request.method.toLowerCase() !== 'get') { - throw new TypeError('`fetchWithCache` only supports GET requests.') - } - - let cache: Cache - - const { cache: cacheParam, onCachePut, ...cacheSettings } = cacheOptions - - if (cacheParam) { - if (typeof cacheParam === 'string') { - cache = await caches.open(cacheParam) - } else if (cacheParam instanceof Cache) { - cache = cacheParam - } else { - throw new TypeError('`cache` must be a string representing the cache name or an instance of `Cache`.') - } - } else { - cache = await caches.open('') - } - - const cached = await cache.match(request) - - if (cached) { - if (needsRevalidation(cached)) { - const { fetch: fetchFn = globalThis.fetch } = cacheOptions - const revalidation = performBackgroundRevalidation(request, cache, cacheSettings, fetchFn) - - if (onCachePut) { - await onCachePut(revalidation) - } else { - const netlifyGlobal: NetlifyGlobal | undefined = (globalThis as GlobalScope).Netlify - const requestContext = netlifyGlobal?.context - if (requestContext) { - requestContext.waitUntil(revalidation) - } - } - } - - return cached - } - - const { fetch = globalThis.fetch } = cacheOptions - - const fresh = await fetch(request) - if (!fresh.body) { - return fresh - } - - const [clientStream, cacheStream] = fresh.body.tee() - - // The response to be returned to the client. - const clientResponse = new Response(clientStream, fresh) - - // The response to be added to the cache. - const cacheResponse = new Response(cacheStream, fresh) - applyHeaders(cacheResponse.headers, cacheHeaders(cacheSettings)) - - const cachePut = cache.put(request, cacheResponse).catch(() => { - // If we fail to cache the response, we want to swallow the error because - // we'll still return the result of `fetch`. - }) - - if (onCachePut) { - await onCachePut(cachePut) - } else { - // NOTE: when `requestContext` is assigned via a single expression here, we - // hit some `@typescript-eslint/no-unsafe-assignment` bug. TODO(serhalp): try - // to reduce this down to a minimal repro and file an issue. - const netlifyGlobal: NetlifyGlobal | undefined = (globalThis as GlobalScope).Netlify - const requestContext = netlifyGlobal?.context - - if (requestContext) { - requestContext.waitUntil(cachePut) - } else { - await cachePut - } - } - - return clientResponse -} - -const performBackgroundRevalidation = async ( - request: Request, - cache: Cache, - cacheSettings: CacheSettings, - fetchFn: typeof globalThis.fetch, -): Promise => { - try { - const fresh = await fetchFn(request) - if (!fresh.body) { - return - } - const cacheResponse = new Response(fresh.body, fresh) - applyHeaders(cacheResponse.headers, cacheHeaders(cacheSettings)) - await cache.put(request, cacheResponse) - } catch (error) { - console.warn('`fetchWithCache` has failed to revalidate a stale response:', error) - } -} diff --git a/packages/cache/src/headers.ts b/packages/cache/src/headers.ts deleted file mode 100644 index 828b5b3..0000000 --- a/packages/cache/src/headers.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const CacheStatus = 'cache-status' -export const NetlifyCacheId = 'netlify-cache-id' -export const NetlifyCacheTag = 'netlify-cache-tag' -export const NetlifyCdnCacheControl = 'netlify-cdn-cache-control' -export const NetlifyVary = 'netlify-vary' -export const ErrorDetail = 'netlify-programmable-error' -export const ResourceHeaders = 'netlify-programmable-headers' -export const ResourceStatus = 'netlify-programmable-status' -export const ResourceStore = 'netlify-programmable-store' -export const NetlifyForwardedHost = 'netlify-forwarded-host' -export const UserAgent = 'user-agent' diff --git a/packages/cache/src/main.test.ts b/packages/cache/src/main.test.ts deleted file mode 100644 index 289b74a..0000000 --- a/packages/cache/src/main.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MockFetch } from '@netlify/dev-utils' -import { describe, test, expect } from 'vitest' - -import { NetlifyCacheStorage } from './bootstrap/cachestorage.js' -import { caches } from './main.js' - -const host = 'host.netlify' -const url = 'https://example.netlify/.netlify/cache' -const token = 'mock-token' - -describe('`caches` export', () => { - test('Provides a no-op cache implementation', async () => { - const html = '

Hello world

' - const mockFetch = new MockFetch() - .get({ - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - response: new Response(html), - }) - .inject() - const cache1 = await caches.open('cache1') - const res1 = await cache1.match('https://netlify.com') - expect(res1).toBeUndefined() - - globalThis.caches = new NetlifyCacheStorage({ - getContext: () => ({ host, token, url }), - }) - - const cache2 = await caches.open('cache2') - const res2 = await cache2.match('https://netlify.com') - expect(res2?.status).toBe(200) - expect(await res2?.text()).toBe(html) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) -}) diff --git a/packages/cache/src/main.ts b/packages/cache/src/main.ts deleted file mode 100644 index 280a026..0000000 --- a/packages/cache/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { caches } from './polyfill.js' -export { cacheHeaders, setCacheHeaders } from './cache-headers/cache-headers.js' -export { getCacheStatus, needsRevalidation } from './cache-status/cache-status.js' -export { fetchWithCache } from './fetchwithcache.js' -export * from './constants.js' diff --git a/packages/cache/src/polyfill.ts b/packages/cache/src/polyfill.ts deleted file mode 100644 index df790d1..0000000 --- a/packages/cache/src/polyfill.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Polyfill for local development environments where `globalThis.caches` is not - * available. It's a no-op cache. In production it will use the real one that - * has been set up in the environment by the bootstrap layer. - */ -class NetlifyCacheStorageProxy implements CacheStorage { - async delete(name: string): Promise { - if (globalThis.caches) { - return globalThis.caches.delete(name) - } - - return false - } - - async has(name: string): Promise { - if (globalThis.caches) { - return globalThis.caches.has(name) - } - - return false - } - - async keys(): Promise { - if (globalThis.caches) { - return globalThis.caches.keys() - } - - return [] - } - - async match(request: RequestInfo, options?: MultiCacheQueryOptions): Promise { - if (globalThis.caches) { - return globalThis.caches.match(request, options) - } - } - - async open(cacheName: string) { - if (globalThis.caches) { - return globalThis.caches.open(cacheName) - } - - return new NetlifyNoopCache() - } -} - -class NetlifyNoopCache implements Cache { - async add(_: RequestInfo): Promise {} - - async addAll(_: RequestInfo[]): Promise {} - - async delete(_: RequestInfo): Promise { - return true - } - - async keys(_?: Request): Promise { - return [] - } - - async match(_: RequestInfo): Promise {} - - async matchAll(_?: RequestInfo): Promise { - return [] - } - - async put(_: RequestInfo | URL | string, __: Response) {} -} - -export const caches = new NetlifyCacheStorageProxy() diff --git a/packages/cache/src/test/headers.ts b/packages/cache/src/test/headers.ts deleted file mode 100644 index cbe7d2a..0000000 --- a/packages/cache/src/test/headers.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const decodeHeaders = (encodedHeader: string | null) => { - const headers = new Headers() - - if (!encodedHeader) { - return headers - } - - const decoded = Buffer.from(encodedHeader, 'base64').toString('utf8') - const parsed = JSON.parse(decoded) as Record - - for (const key in parsed) { - for (const value of parsed[key]) { - headers.append(key, value) - } - } - - return headers -} diff --git a/packages/cache/src/test/util.ts b/packages/cache/src/test/util.ts deleted file mode 100644 index 48ac255..0000000 --- a/packages/cache/src/test/util.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function sleep(ms: number, value?: T) { - return new Promise((resolve) => setTimeout(() => resolve(value), ms)) -} diff --git a/packages/cache/tsconfig.json b/packages/cache/tsconfig.json deleted file mode 100644 index 7fedf6e..0000000 --- a/packages/cache/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "allowImportingTsExtensions": true, - "emitDeclarationOnly": true, - "target": "ES2020", - "module": "es2020", - "allowJs": true, - "declaration": true, - "declarationMap": false, - "sourceMap": false, - "outDir": "./dist", - "removeComments": false, - "strict": true, - "moduleResolution": "node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/cache/tsup.config.ts b/packages/cache/tsup.config.ts deleted file mode 100644 index a0dfdab..0000000 --- a/packages/cache/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['cjs', 'esm'], - entry: ['src/bootstrap/main.ts', 'src/main.ts'], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/cache/vitest.config.ts b/packages/cache/vitest.config.ts deleted file mode 100644 index eff32b2..0000000 --- a/packages/cache/vitest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - }, -}) diff --git a/packages/database/.gitignore b/packages/database/.gitignore deleted file mode 100644 index 1eae0cf..0000000 --- a/packages/database/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist/ -node_modules/ diff --git a/packages/database/dev/CHANGELOG.md b/packages/database/dev/CHANGELOG.md deleted file mode 100644 index af5ece6..0000000 --- a/packages/database/dev/CHANGELOG.md +++ /dev/null @@ -1,72 +0,0 @@ -# Changelog - -## [0.10.1](https://github.com/netlify/primitives/compare/database-dev-v0.10.0...database-dev-v0.10.1) (2026-04-27) - - -### Bug Fixes - -* **database:** support both formats when applying migrations ([#665](https://github.com/netlify/primitives/issues/665)) ([89b40e2](https://github.com/netlify/primitives/commit/89b40e23d35b7277c9fbd7554a2e86959e29e338)) - -## [0.10.0](https://github.com/netlify/primitives/compare/database-dev-v0.9.0...database-dev-v0.10.0) (2026-04-20) - - -### Features - -* **database:** ensure migrations tracking table exists ([#661](https://github.com/netlify/primitives/issues/661)) ([4b914d6](https://github.com/netlify/primitives/commit/4b914d686ce479fbb8613896697a40c52017e5af)) - -## [0.9.0](https://github.com/netlify/primitives/compare/database-dev-v0.8.0...database-dev-v0.9.0) (2026-04-20) - - -### Features - -* **database:** update migrations table name ([#658](https://github.com/netlify/primitives/issues/658)) ([e65a740](https://github.com/netlify/primitives/commit/e65a740223c69fedebe02e72a21cd451fadc7682)) - -## [0.8.0](https://github.com/netlify/primitives/compare/database-dev-v0.7.0...database-dev-v0.8.0) (2026-04-13) - - -### Features - -* rename database package ([#649](https://github.com/netlify/primitives/issues/649)) ([bbe80bb](https://github.com/netlify/primitives/commit/bbe80bb31eedb74d08c08f35cd21f1360b9eb41f)) - -## [0.7.0](https://github.com/netlify/primitives/compare/db-dev-v0.6.0...db-dev-v0.7.0) (2026-03-10) - - -### Features - -* **db:** make NetlifyDB fulfill SQLExecutor ([#620](https://github.com/netlify/primitives/issues/620)) ([a91a390](https://github.com/netlify/primitives/commit/a91a390a32a66a0bdd86efaa8574e597abef3b82)) - -## [0.6.0](https://github.com/netlify/primitives/compare/db-dev-v0.5.0...db-dev-v0.6.0) (2026-03-10) - - -### Features - -* **db-dev:** abstract pg client into interface ([#619](https://github.com/netlify/primitives/issues/619)) ([2c92b2d](https://github.com/netlify/primitives/commit/2c92b2dfdd973255883caad44594dfd470799a6d)) - -## [0.5.0](https://github.com/netlify/primitives/compare/db-dev-v0.4.0...db-dev-v0.5.0) (2026-03-06) - - -### Features - -* **db:** allow to reset database schemas ([#615](https://github.com/netlify/primitives/issues/615)) ([6438372](https://github.com/netlify/primitives/commit/6438372264df6ede84c0f098d1f2a5e98a22325b)) - -## [0.4.0](https://github.com/netlify/primitives/compare/db-dev-v0.3.0...db-dev-v0.4.0) (2026-03-04) - - -### Features - -* **db:** add `applyMigrations` method ([#608](https://github.com/netlify/primitives/issues/608)) ([71cbbac](https://github.com/netlify/primitives/commit/71cbbac911d57b217ed9f636c1cbfcb9e71466da)) - -## [0.3.0](https://github.com/netlify/primitives/compare/db-dev-v0.2.0...db-dev-v0.3.0) (2026-02-27) - - -### Features - -* **db:** add support for LISTEN/NOTIFY ([#598](https://github.com/netlify/primitives/issues/598)) ([99078ce](https://github.com/netlify/primitives/commit/99078cec3103a85230c8ac7c898eaae2db37b718)) - -## [0.2.0](https://github.com/netlify/primitives/compare/db-dev-v0.1.0...db-dev-v0.2.0) (2026-02-17) - - -### Features - -* add `db` package ([#581](https://github.com/netlify/primitives/issues/581)) ([b60a313](https://github.com/netlify/primitives/commit/b60a313bd9ba19fd5deced4736012c3d7c7fe842)) -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) diff --git a/packages/database/dev/package.json b/packages/database/dev/package.json deleted file mode 100644 index b1c025a..0000000 --- a/packages/database/dev/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "@netlify/database-dev", - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "type": "module", - "exports": { - ".": { - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - } - }, - "version": "0.10.1", - "description": "Local dev emulation of Netlify Database", - "files": [ - "dist/**/*.js", - "dist/**/*.mjs", - "dist/**/*.d.ts", - "dist/**/*.d.mts" - ], - "scripts": { - "dev": "tsup-node --watch", - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest" - }, - "keywords": [ - "netlify", - "db", - "database", - "postgres", - "pglite" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/database/dev" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "@electric-sql/pglite": "^0.3.15", - "pg-gateway": "0.3.0-beta.4" - }, - "devDependencies": { - "@types/pg": "^8.11.0", - "pg": "^8.11.0", - "tmp-promise": "^3.0.3", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, - "engines": { - "node": ">=20.6.1" - } -} diff --git a/packages/database/dev/src/lib/migrations.test.ts b/packages/database/dev/src/lib/migrations.test.ts deleted file mode 100644 index 61a3fa5..0000000 --- a/packages/database/dev/src/lib/migrations.test.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { promises as fs } from 'node:fs' -import { join } from 'node:path' - -import { PGlite } from '@electric-sql/pglite' -import tmp from 'tmp-promise' -import { test, expect, afterEach } from 'vitest' - -import { NetlifyDB } from '../main.js' -import { applyMigrations } from './migrations.js' - -let db: PGlite | undefined -let tmpDir: tmp.DirectoryResult | undefined - -afterEach(async () => { - if (db) { - await db.close() - db = undefined - } - - if (tmpDir) { - await fs.rm(tmpDir.path, { force: true, recursive: true }) - tmpDir = undefined - } -}) - -async function createMigrationDir(basePath: string, name: string, sql: string) { - const dir = join(basePath, name) - - await fs.mkdir(dir, { recursive: true }) - await fs.writeFile(join(dir, 'migration.sql'), sql) -} - -async function createFlatMigration(basePath: string, name: string, sql: string) { - await fs.writeFile(join(basePath, `${name}.sql`), sql) -} - -async function setupMigrations(migrations: { name: string; sql: string }[]) { - tmpDir = await tmp.dir() - - for (const { name, sql } of migrations) { - await createMigrationDir(tmpDir.path, name, sql) - } - - db = await PGlite.create() - - return { migrationsDir: tmpDir.path, db } -} - -test('Applies all migrations when no target is specified', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - { name: '0003_add_comments', sql: 'CREATE TABLE comments (id SERIAL PRIMARY KEY, body TEXT)' }, - ]) - - const applied = await applyMigrations(pgDb, migrationsDir) - - expect(applied).toHaveLength(3) - expect(applied[0]).toBe('0001_create_users') - expect(applied[1]).toBe('0002_add_posts') - expect(applied[2]).toBe('0003_add_comments') - - // Verify all tables were created - const usersResult = await pgDb.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'users'") - expect(usersResult.rows).toHaveLength(1) - - const postsResult = await pgDb.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'posts'") - expect(postsResult.rows).toHaveLength(1) - - const commentsResult = await pgDb.query( - "SELECT table_name FROM information_schema.tables WHERE table_name = 'comments'", - ) - expect(commentsResult.rows).toHaveLength(1) -}) - -test('Applies all migrations up to named target', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - { name: '0003_add_comments', sql: 'CREATE TABLE comments (id SERIAL PRIMARY KEY, body TEXT)' }, - ]) - - const applied = await applyMigrations(pgDb, migrationsDir, '0002_add_posts') - - expect(applied).toHaveLength(2) - expect(applied[0]).toBe('0001_create_users') - expect(applied[1]).toBe('0002_add_posts') - - // Verify tables were created - const usersResult = await pgDb.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'users'") - expect(usersResult.rows).toHaveLength(1) - - const postsResult = await pgDb.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'posts'") - expect(postsResult.rows).toHaveLength(1) - - // Migration 3 should NOT have been applied - const commentsResult = await pgDb.query( - "SELECT table_name FROM information_schema.tables WHERE table_name = 'comments'", - ) - expect(commentsResult.rows).toHaveLength(0) -}) - -test('Skips already-applied migrations (idempotency)', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - ]) - - // Apply first time - const first = await applyMigrations(pgDb, migrationsDir, '0002_add_posts') - expect(first).toHaveLength(2) - - // Apply again — should skip all - const second = await applyMigrations(pgDb, migrationsDir, '0002_add_posts') - expect(second).toHaveLength(0) -}) - -test('Applies incrementally (apply to A, then later to B)', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - { name: '0003_add_comments', sql: 'CREATE TABLE comments (id SERIAL PRIMARY KEY, body TEXT)' }, - ]) - - // Apply up to migration 1 - const first = await applyMigrations(pgDb, migrationsDir, '0001_create_users') - expect(first).toHaveLength(1) - expect(first[0]).toBe('0001_create_users') - - // Apply up to migration 3 — should only apply 2 and 3 - const second = await applyMigrations(pgDb, migrationsDir, '0003_add_comments') - expect(second).toHaveLength(2) - expect(second[0]).toBe('0002_add_posts') - expect(second[1]).toBe('0003_add_comments') -}) - -test('Resolves target by prefix only', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - ]) - - const applied = await applyMigrations(pgDb, migrationsDir, '0002') - - expect(applied).toHaveLength(2) - expect(applied[1]).toBe('0002_add_posts') -}) - -test('Throws DatabaseNotStartedError if start() not called', async () => { - const server = new NetlifyDB() - - await expect(server.applyMigrations('/nonexistent', '0001')).rejects.toThrow('Database has not been started') -}) - -test('Throws MigrationDirectoryNotFoundError for missing directory', async () => { - db = await PGlite.create() - - await expect(applyMigrations(db, '/nonexistent/path', '0001')).rejects.toThrow('Migration directory not found') -}) - -test('Throws MigrationNotFoundError for unknown target', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - ]) - - await expect(applyMigrations(pgDb, migrationsDir, '9999_nonexistent')).rejects.toThrow( - 'No migration found matching target', - ) -}) - -test('Throws MigrationFileNotFoundError for directory missing migration.sql', async () => { - tmpDir = await tmp.dir() - - // Create a directory without migration.sql - await fs.mkdir(join(tmpDir.path, '0001_missing_file')) - - db = await PGlite.create() - - await expect(applyMigrations(db, tmpDir.path, '0001_missing_file')).rejects.toThrow( - /Migration SQL file not found: .*0001_missing_file[/\\]migration.sql/, - ) -}) - -test('Rolls back failed migration, preserves prior successful ones', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_bad_migration', sql: 'INVALID SQL SYNTAX HERE' }, - { name: '0003_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - ]) - - await expect(applyMigrations(pgDb, migrationsDir, '0003_add_posts')).rejects.toThrow() - - // Migration 1 should be committed - const tracking = await pgDb.query<{ name: string }>('SELECT name FROM netlify.migrations ORDER BY name') - expect(tracking.rows).toHaveLength(1) - expect(tracking.rows[0].name).toBe('0001_create_users') - - // users table should exist - const usersResult = await pgDb.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'users'") - expect(usersResult.rows).toHaveLength(1) - - // posts table should NOT exist (migration 3 was never reached) - const postsResult = await pgDb.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'posts'") - expect(postsResult.rows).toHaveLength(0) -}) - -test('Ignores non-matching entries (.DS_Store, readme.md, etc.)', async () => { - tmpDir = await tmp.dir() - - // Create valid migration - await createMigrationDir(tmpDir.path, '0001_create_users', 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)') - - // Create non-matching entries - await fs.writeFile(join(tmpDir.path, '.DS_Store'), '') - await fs.writeFile(join(tmpDir.path, 'readme.md'), '# Migrations') - await fs.mkdir(join(tmpDir.path, 'not_a_migration')) - - db = await PGlite.create() - - const applied = await applyMigrations(db, tmpDir.path, '0001_create_users') - - expect(applied).toHaveLength(1) - expect(applied[0]).toBe('0001_create_users') -}) - -test('Lexicographic ordering with timestamp-style prefixes', async () => { - const { migrationsDir, db: pgDb } = await setupMigrations([ - { name: '1709312400_add_comments', sql: 'CREATE TABLE comments (id SERIAL PRIMARY KEY, body TEXT)' }, - { name: '0001_create_users', sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)' }, - { name: '0002_add_posts', sql: 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)' }, - ]) - - const applied = await applyMigrations(pgDb, migrationsDir, '1709312400_add_comments') - - // Lexicographic sort: 0001, 0002, 1709312400 - expect(applied).toHaveLength(3) - expect(applied[0]).toBe('0001_create_users') - expect(applied[1]).toBe('0002_add_posts') - expect(applied[2]).toBe('1709312400_add_comments') -}) - -test('Applies flat .sql file migrations', async () => { - tmpDir = await tmp.dir() - - await createFlatMigration(tmpDir.path, '0001_create_users', 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)') - await createFlatMigration(tmpDir.path, '0002_add_posts', 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)') - - db = await PGlite.create() - - const applied = await applyMigrations(db, tmpDir.path) - - expect(applied).toEqual(['0001_create_users', '0002_add_posts']) - - const usersResult = await db.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'users'") - expect(usersResult.rows).toHaveLength(1) - - const postsResult = await db.query("SELECT table_name FROM information_schema.tables WHERE table_name = 'posts'") - expect(postsResult.rows).toHaveLength(1) -}) - -test('Applies a mix of directory and flat-file migrations in lexicographic order', async () => { - tmpDir = await tmp.dir() - - await createMigrationDir(tmpDir.path, '0001_create_users', 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)') - await createFlatMigration(tmpDir.path, '0002_add_posts', 'CREATE TABLE posts (id SERIAL PRIMARY KEY, title TEXT)') - await createMigrationDir(tmpDir.path, '0003_add_comments', 'CREATE TABLE comments (id SERIAL PRIMARY KEY, body TEXT)') - - db = await PGlite.create() - - const applied = await applyMigrations(db, tmpDir.path) - - expect(applied).toEqual(['0001_create_users', '0002_add_posts', '0003_add_comments']) -}) - -test('Throws when a directory and flat file share the same name', async () => { - tmpDir = await tmp.dir() - - await createMigrationDir(tmpDir.path, '0001_create_users', 'CREATE TABLE users (id SERIAL PRIMARY KEY)') - await createFlatMigration(tmpDir.path, '0001_create_users', 'CREATE TABLE users (id SERIAL PRIMARY KEY)') - - db = await PGlite.create() - - await expect(applyMigrations(db, tmpDir.path)).rejects.toThrow(/Duplicate migration name "0001_create_users"/) -}) - -test('Ignores flat .sql files whose name does not match the migration pattern', async () => { - tmpDir = await tmp.dir() - - await createFlatMigration(tmpDir.path, '0001_create_users', 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)') - // None of these should be picked up. - await fs.writeFile(join(tmpDir.path, 'seed.sql'), 'SELECT 1') - await fs.writeFile(join(tmpDir.path, 'readme.sql'), 'SELECT 1') - - db = await PGlite.create() - - const applied = await applyMigrations(db, tmpDir.path) - - expect(applied).toEqual(['0001_create_users']) -}) diff --git a/packages/database/dev/src/lib/migrations.ts b/packages/database/dev/src/lib/migrations.ts deleted file mode 100644 index 9ae68af..0000000 --- a/packages/database/dev/src/lib/migrations.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { readdir, readFile } from 'node:fs/promises' -import { join } from 'node:path' - -import type { Dirent } from 'node:fs' - -import type { SQLExecutor } from './sql-executor.js' - -const MIGRATION_NAME_PATTERN = /^\d+_.+$/ -const MIGRATION_FILE = 'migration.sql' -const SQL_EXTENSION = '.sql' -const TRACKING_SCHEMA = 'netlify' -const TRACKING_TABLE = `${TRACKING_SCHEMA}.migrations` - -interface Migration { - name: string - sqlPath: string -} - -// Maps a directory entry to a Migration, or null if it isn't one. Supports -// both directory-style migrations (`_/migration.sql`) and flat -// file migrations (`_.sql`). -function toMigration(entry: Dirent, migrationsDirectory: string): Migration | null { - if (entry.isDirectory()) { - if (!MIGRATION_NAME_PATTERN.test(entry.name)) { - return null - } - - return { - name: entry.name, - sqlPath: join(migrationsDirectory, entry.name, MIGRATION_FILE), - } - } - - if (entry.isFile() && entry.name.endsWith(SQL_EXTENSION)) { - const name = entry.name.slice(0, -SQL_EXTENSION.length) - - if (!MIGRATION_NAME_PATTERN.test(name)) { - return null - } - - return { - name, - sqlPath: join(migrationsDirectory, entry.name), - } - } - - return null -} - -// Creates the migrations tracking table if it doesn't already exist. It's -// idempotent. -export async function initializeTrackingTable(db: SQLExecutor): Promise { - await db.exec(` - CREATE SCHEMA IF NOT EXISTS ${TRACKING_SCHEMA}; - CREATE TABLE IF NOT EXISTS ${TRACKING_TABLE} ( - name TEXT PRIMARY KEY, - applied_at TIMESTAMPTZ NOT NULL DEFAULT now() - ) - `) -} - -export async function applyMigrations( - db: SQLExecutor, - migrationsDirectory: string, - target?: string, -): Promise { - await initializeTrackingTable(db) - - let migrations: Migration[] - - try { - const dirents = await readdir(migrationsDirectory, { withFileTypes: true }) - migrations = dirents - .map((entry) => toMigration(entry, migrationsDirectory)) - .filter((m): m is Migration => m !== null) - } catch { - throw new Error(`Migration directory not found: ${migrationsDirectory}`) - } - - const seen = new Map() - for (const migration of migrations) { - const existing = seen.get(migration.name) - if (existing) { - throw new Error( - `Duplicate migration name "${migration.name}" in ${migrationsDirectory}: ` + - `found both "${existing}" and "${migration.sqlPath}". Remove one before applying migrations.`, - ) - } - seen.set(migration.name, migration.sqlPath) - } - - migrations.sort((a, b) => a.name.localeCompare(b.name)) - - let migrationsToConsider: Migration[] - - if (target === undefined) { - migrationsToConsider = migrations - } else { - // Resolve target — exact match first, then prefix match. - let targetIndex = migrations.findIndex((m) => m.name === target) - - if (targetIndex === -1) { - targetIndex = migrations.findIndex((m) => m.name.startsWith(`${target}_`)) - } - - if (targetIndex === -1) { - throw new Error(`No migration found matching target: ${target}`) - } - - migrationsToConsider = migrations.slice(0, targetIndex + 1) - } - - const names = migrationsToConsider.map((m) => m.name) - const result = await db.query<{ name: string }>(`SELECT name FROM ${TRACKING_TABLE} WHERE name = ANY($1)`, [names]) - const alreadyApplied = new Set(result.rows.map((row) => row.name)) - - const applied: string[] = [] - - for (const migration of migrationsToConsider) { - if (alreadyApplied.has(migration.name)) { - continue - } - - let sql: string - - try { - sql = await readFile(migration.sqlPath, 'utf-8') - } catch (error) { - const err = error as NodeJS.ErrnoException - if (err.code === 'ENOENT') { - throw new Error(`Migration SQL file not found: ${migration.sqlPath}`) - } - - throw new Error(`Failed to read migration "${migration.name}" at "${migration.sqlPath}": ${err.message}`) - } - - await db.transaction(async (tx) => { - await tx.exec(sql) - await tx.query(`INSERT INTO ${TRACKING_TABLE} (name) VALUES ($1)`, [migration.name]) - }) - - applied.push(migration.name) - } - - return applied -} diff --git a/packages/database/dev/src/lib/notifications.ts b/packages/database/dev/src/lib/notifications.ts deleted file mode 100644 index 63a4334..0000000 --- a/packages/database/dev/src/lib/notifications.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { Socket } from 'node:net' - -import type { PGlite } from '@electric-sql/pglite' - -// PostgreSQL wire protocol message type for NotificationResponse. -// https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-NOTIFICATIONRESPONSE -const NOTIFICATION_RESPONSE = 0x41 // 'A' - -const textEncoder = new TextEncoder() - -/** - * Encodes a NotificationResponse message according to the PostgreSQL wire - * protocol. The format is: - * - * Byte1('A') | Int32(length) | Int32(processId) | String(channel) | String(payload) - * - * Where strings are null-terminated and `length` includes itself but not the - * message type byte. - * - * https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-NOTIFICATIONRESPONSE - */ -function buildNotificationResponse(channel: string, payload: string, processId = 0): Uint8Array { - const channelBytes = textEncoder.encode(channel) - const payloadBytes = textEncoder.encode(payload) - - // 4 bytes for Int32(length) + 4 bytes for Int32(processId) + 1 null terminator per string - const bodyLength = 10 + channelBytes.length + payloadBytes.length - const buf = new Uint8Array(1 + bodyLength) - const view = new DataView(buf.buffer) - let offset = 0 - - buf[offset++] = NOTIFICATION_RESPONSE - view.setInt32(offset, bodyLength) - offset += 4 - view.setInt32(offset, processId) - offset += 4 - buf.set(channelBytes, offset) - offset += channelBytes.length - buf[offset++] = 0 - buf.set(payloadBytes, offset) - offset += payloadBytes.length - buf[offset++] = 0 - - return buf -} - -/** - * Subscribes to PGLite's `onNotification` callback and broadcasts each - * notification to every connected socket as a wire-protocol - * NotificationResponse message. - * - * This is necessary because PGLite exposes a single internal connection. - * When multiple clients connect through pg-gateway, a NOTIFY triggered by - * one client produces a NotificationResponse in that client's - * `execProtocolRaw` response — not on the socket of the client that called - * LISTEN. By hooking into `onNotification` (https://pglite.dev/docs/api#onnotification) - * and writing directly to every socket, we ensure listeners receive - * notifications regardless of which connection triggered the NOTIFY. - * - * Returns an unsubscribe function that stops the broadcast. - */ -export function broadcastNotifications(db: PGlite, connections: Set): () => void { - return db.onNotification((channel, payload) => { - const message = buildNotificationResponse(channel, payload) - - for (const socket of connections) { - if (!socket.destroyed) { - socket.write(message) - } - } - }) -} diff --git a/packages/database/dev/src/lib/sql-executor.ts b/packages/database/dev/src/lib/sql-executor.ts deleted file mode 100644 index 24c6466..0000000 --- a/packages/database/dev/src/lib/sql-executor.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface SQLExecutor { - exec(sql: string): Promise - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters - query(sql: string, params?: unknown[]): Promise<{ rows: T[] }> - transaction(fn: (tx: Pick) => Promise): Promise -} diff --git a/packages/database/dev/src/main.test.ts b/packages/database/dev/src/main.test.ts deleted file mode 100644 index affd151..0000000 --- a/packages/database/dev/src/main.test.ts +++ /dev/null @@ -1,457 +0,0 @@ -import { promises as fs } from 'node:fs' - -import { Client } from 'pg' -import tmp from 'tmp-promise' -import { test, expect, afterEach } from 'vitest' - -import { NetlifyDB } from './main.js' - -let server: NetlifyDB | undefined -let tmpDir: tmp.DirectoryResult | undefined - -afterEach(async () => { - if (server) { - await server.stop() - server = undefined - } - - if (tmpDir) { - await fs.rm(tmpDir.path, { force: true, recursive: true }) - tmpDir = undefined - } -}) - -test('Starts a server and returns a connection string', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - expect(connectionString).toMatch(/^postgres:\/\/localhost:\d+\/postgres$/) -}) - -test('Uses the specified port when provided', async () => { - const port = 15432 - server = new NetlifyDB({ port }) - const connectionString = await server.start() - - expect(connectionString).toBe(`postgres://localhost:${String(port)}/postgres`) -}) - -test('Accepts PostgreSQL client connections', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const client = new Client({ connectionString }) - - await client.connect() - - const result = await client.query('SELECT 1 as value') - expect(result.rows).toHaveLength(1) - - await client.end() -}) - -test('Executes basic SQL queries', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const client = new Client({ connectionString }) - - await client.connect() - - // Create a table - await client.query(` - CREATE TABLE users ( - id SERIAL PRIMARY KEY, - name VARCHAR(100) NOT NULL, - email VARCHAR(100) UNIQUE NOT NULL - ) - `) - - // Insert data - await client.query( - ` - INSERT INTO users (name, email) VALUES ($1, $2) - `, - ['Alice', 'alice@example.com'], - ) - - await client.query( - ` - INSERT INTO users (name, email) VALUES ($1, $2) - `, - ['Bob', 'bob@example.com'], - ) - - // Query data - const result = await client.query<{ id: number; name: string; email: string }>('SELECT * FROM users ORDER BY id') - - expect(result.rows).toHaveLength(2) - expect(result.rows[0].name).toBe('Alice') - expect(result.rows[0].email).toBe('alice@example.com') - expect(result.rows[1].name).toBe('Bob') - expect(result.rows[1].email).toBe('bob@example.com') - - await client.end() -}) - -test('Supports multiple concurrent client connections', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const client1 = new Client({ connectionString }) - const client2 = new Client({ connectionString }) - - await client1.connect() - await client2.connect() - - // Create table with client1 - await client1.query(` - CREATE TABLE test_table ( - id SERIAL PRIMARY KEY, - value TEXT - ) - `) - - // Insert with client1 - await client1.query(`INSERT INTO test_table (value) VALUES ('from client 1')`) - - // Insert with client2 - await client2.query(`INSERT INTO test_table (value) VALUES ('from client 2')`) - - // Read from both clients - const result1 = await client1.query('SELECT * FROM test_table ORDER BY id') - const result2 = await client2.query('SELECT * FROM test_table ORDER BY id') - - expect(result1.rows).toHaveLength(2) - expect(result2.rows).toHaveLength(2) - - await client1.end() - await client2.end() -}) - -test('Persists data to disk when directory is provided', async () => { - tmpDir = await tmp.dir() - - // Start server with directory - server = new NetlifyDB({ directory: tmpDir.path }) - const connectionString1 = await server.start() - - const client1 = new Client({ connectionString: connectionString1 }) - - await client1.connect() - - // Create table and insert data - await client1.query(` - CREATE TABLE persistent_data ( - id SERIAL PRIMARY KEY, - message TEXT - ) - `) - await client1.query(`INSERT INTO persistent_data (message) VALUES ('Hello, persistence!')`) - - await client1.end() - await server.stop() - - // Start a new server with the same directory - server = new NetlifyDB({ directory: tmpDir.path }) - const connectionString2 = await server.start() - - const client2 = new Client({ connectionString: connectionString2 }) - - await client2.connect() - - // Data should still be there - const result = await client2.query<{ id: number; message: string }>('SELECT * FROM persistent_data') - - expect(result.rows).toHaveLength(1) - expect(result.rows[0].message).toBe('Hello, persistence!') - - await client2.end() -}) - -test('Uses in-memory storage when no directory is provided', async () => { - server = new NetlifyDB() - const connectionString1 = await server.start() - - const client1 = new Client({ connectionString: connectionString1 }) - - await client1.connect() - - // Create table and insert data - await client1.query(` - CREATE TABLE temp_data ( - id SERIAL PRIMARY KEY, - value TEXT - ) - `) - await client1.query(`INSERT INTO temp_data (value) VALUES ('temporary')`) - - const result1 = await client1.query('SELECT * FROM temp_data') - expect(result1.rows).toHaveLength(1) - - await client1.end() - await server.stop() - - // Start a new server without directory - data should be gone - server = new NetlifyDB() - const connectionString2 = await server.start() - - const client2 = new Client({ connectionString: connectionString2 }) - - await client2.connect() - - // Table should not exist - await expect(client2.query('SELECT * FROM temp_data')).rejects.toThrow() - - await client2.end() -}) - -test('Delivers LISTEN/NOTIFY across separate connections', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const listener = new Client({ connectionString }) - const notifier = new Client({ connectionString }) - - await listener.connect() - await notifier.connect() - - const received: { channel: string; payload: string }[] = [] - - listener.on('notification', (msg) => { - received.push({ channel: msg.channel, payload: msg.payload ?? '' }) - }) - - await listener.query('LISTEN test_channel') - - // Send notifications from a different connection. - await notifier.query("NOTIFY test_channel, 'hello'") - await notifier.query("NOTIFY test_channel, 'world'") - - // Give a brief moment for async delivery. - await new Promise((resolve) => setTimeout(resolve, 200)) - - expect(received).toEqual([ - { channel: 'test_channel', payload: 'hello' }, - { channel: 'test_channel', payload: 'world' }, - ]) - - await listener.end() - await notifier.end() -}) - -test('Supports UNLISTEN to stop receiving notifications', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const listener = new Client({ connectionString }) - const notifier = new Client({ connectionString }) - - await listener.connect() - await notifier.connect() - - const received: string[] = [] - - listener.on('notification', (msg) => { - received.push(msg.payload ?? '') - }) - - await listener.query('LISTEN test_unsub') - await notifier.query("NOTIFY test_unsub, 'before'") - await new Promise((resolve) => setTimeout(resolve, 200)) - - await listener.query('UNLISTEN test_unsub') - await notifier.query("NOTIFY test_unsub, 'after'") - await new Promise((resolve) => setTimeout(resolve, 200)) - - expect(received).toEqual(['before']) - - await listener.end() - await notifier.end() -}) - -test('Delivers notifications to multiple listeners', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const listener1 = new Client({ connectionString }) - const listener2 = new Client({ connectionString }) - const notifier = new Client({ connectionString }) - - await listener1.connect() - await listener2.connect() - await notifier.connect() - - const received1: string[] = [] - const received2: string[] = [] - - listener1.on('notification', (msg) => { - received1.push(msg.payload ?? '') - }) - - listener2.on('notification', (msg) => { - received2.push(msg.payload ?? '') - }) - - await listener1.query('LISTEN shared_channel') - await listener2.query('LISTEN shared_channel') - - await notifier.query("NOTIFY shared_channel, 'broadcast'") - await new Promise((resolve) => setTimeout(resolve, 200)) - - expect(received1).toEqual(['broadcast']) - expect(received2).toEqual(['broadcast']) - - await listener1.end() - await listener2.end() - await notifier.end() -}) - -test('Cleans up subscriptions when a connection closes', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const listener = new Client({ connectionString }) - const notifier = new Client({ connectionString }) - const observer = new Client({ connectionString }) - - await listener.connect() - await notifier.connect() - await observer.connect() - - const observerReceived: string[] = [] - - observer.on('notification', (msg) => { - observerReceived.push(msg.payload ?? '') - }) - - await listener.query('LISTEN cleanup_test') - await observer.query('LISTEN cleanup_test') - - // Close the first listener. - await listener.end() - await new Promise((resolve) => setTimeout(resolve, 100)) - - // Notify — only the observer should receive it. - await notifier.query("NOTIFY cleanup_test, 'after_close'") - await new Promise((resolve) => setTimeout(resolve, 200)) - - expect(observerReceived).toEqual(['after_close']) - - await notifier.end() - await observer.end() -}) - -test('Handles quoted channel names', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const listener = new Client({ connectionString }) - const notifier = new Client({ connectionString }) - - await listener.connect() - await notifier.connect() - - const received: { channel: string; payload: string }[] = [] - - listener.on('notification', (msg) => { - received.push({ channel: msg.channel, payload: msg.payload ?? '' }) - }) - - await listener.query('LISTEN "MyChannel"') - await notifier.query(`NOTIFY "MyChannel", 'test'`) - await new Promise((resolve) => setTimeout(resolve, 200)) - - expect(received).toEqual([{ channel: 'MyChannel', payload: 'test' }]) - - await listener.end() - await notifier.end() -}) - -test('Resets the database by dropping all tables', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const client = new Client({ connectionString }) - - await client.connect() - - await client.query(` - CREATE TABLE reset_test ( - id SERIAL PRIMARY KEY, - value TEXT - ) - `) - await client.query(`INSERT INTO reset_test (value) VALUES ('before reset')`) - - const before = await client.query('SELECT * FROM reset_test') - expect(before.rows).toHaveLength(1) - - await server.reset() - - await expect(client.query('SELECT * FROM reset_test')).rejects.toThrow() - - await client.end() -}) - -test('Allows creating tables again after reset', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const client = new Client({ connectionString }) - - await client.connect() - - await client.query('CREATE TABLE first_table (id SERIAL PRIMARY KEY)') - await server.reset() - - await client.query('CREATE TABLE first_table (id SERIAL PRIMARY KEY)') - const result = await client.query<{ value: number }>('SELECT 1 AS value') - expect(result.rows[0].value).toBe(1) - - await client.end() -}) - -test('Drops custom schemas on reset', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - const client = new Client({ connectionString }) - - await client.connect() - - await client.query('CREATE SCHEMA custom_schema') - await client.query('CREATE TABLE custom_schema.my_table (id SERIAL PRIMARY KEY)') - - await server.reset() - - await expect(client.query('SELECT * FROM custom_schema.my_table')).rejects.toThrow() - - await client.end() -}) - -test('Throws when reset is called before start', async () => { - server = new NetlifyDB() - - await expect(server.reset()).rejects.toThrow('Database has not been started') -}) - -test('Stops the server cleanly', async () => { - server = new NetlifyDB() - const connectionString = await server.start() - - // Verify server is running - const client = new Client({ connectionString }) - - await client.connect() - await client.end() - - // Stop the server - await server.stop() - server = undefined - - // New connections should fail - const client2 = new Client({ connectionString }) - - await expect(client2.connect()).rejects.toThrow() -}) diff --git a/packages/database/dev/src/main.ts b/packages/database/dev/src/main.ts deleted file mode 100644 index e33f379..0000000 --- a/packages/database/dev/src/main.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { mkdir } from 'node:fs/promises' -import { createServer as createNetServer, type AddressInfo, type Server, type Socket } from 'node:net' - -import { PGlite } from '@electric-sql/pglite' -import type { ConnectionState, MessageResponse } from 'pg-gateway' -import { fromNodeSocket } from 'pg-gateway/node' - -import { broadcastNotifications } from './lib/notifications.js' -import { applyMigrations, initializeTrackingTable } from './lib/migrations.js' -import type { SQLExecutor } from './lib/sql-executor.js' - -export { applyMigrations, initializeTrackingTable } from './lib/migrations.js' -export type { SQLExecutor } from './lib/sql-executor.js' - -const DEFAULT_HOST = 'localhost' - -type Logger = (...message: unknown[]) => void - -export interface NetlifyDBOptions { - /** - * Directory for data persistence. If not provided, uses in-memory storage. - */ - directory?: string - - /** - * Function to log messages. Defaults to `console.log`. - */ - logger?: Logger - - /** - * Port to run the database server on. If not provided, picks a random available port. - */ - port?: number -} - -export async function resetDatabase(db: SQLExecutor): Promise { - const result = await db.query<{ schema_name: string }>( - `SELECT schema_name - FROM information_schema.schemata - WHERE schema_name <> 'information_schema' - AND schema_name NOT LIKE 'pg_%'`, - ) - - for (const { schema_name } of result.rows) { - const escapedSchemaName = schema_name.replaceAll('"', '""') - await db.exec(`DROP SCHEMA "${escapedSchemaName}" CASCADE`) - } - - await db.exec('CREATE SCHEMA IF NOT EXISTS public') - await initializeTrackingTable(db) -} - -export class NetlifyDB implements SQLExecutor { - private db?: PGlite - private directory?: string - private logger: Logger - private port?: number - private server?: Server - - // All active client sockets, tracked so notifications can be broadcast - // and so they can be destroyed on stop(). - private connections = new Set() - - // Unsubscribe function for the global onNotification handler. - private unsubNotification?: () => void - - constructor({ directory, logger, port }: NetlifyDBOptions = {}) { - this.directory = directory - this.logger = logger ?? console.log - this.port = port - } - - async start(): Promise { - if (this.directory) { - await mkdir(this.directory, { recursive: true }) - } - - this.db = await PGlite.create(this.directory) - - await initializeTrackingTable(this.db) - - this.unsubNotification = broadcastNotifications(this.db, this.connections) - - this.server = createNetServer((socket: Socket) => { - this.handleConnection(socket) - }) - - return new Promise((resolve, reject) => { - if (!this.server) { - reject(new Error('Server not initialized')) - - return - } - - this.server.on('error', reject) - this.server.listen(this.port ?? 0, DEFAULT_HOST, () => { - this.server?.off('error', reject) - - const { address, port } = this.server?.address() as AddressInfo - const host = address === '::1' || address === '127.0.0.1' ? 'localhost' : address - - resolve(`postgres://${host}:${String(port)}/postgres`) - }) - }) - } - - async applyMigrations(migrationsDirectory: string, target?: string): Promise { - if (!this.db) { - throw new Error('Database has not been started. Call start() before applying migrations.') - } - - return applyMigrations(this.db, migrationsDirectory, target) - } - - async reset(): Promise { - if (!this.db) { - throw new Error('Database has not been started. Call start() before resetting.') - } - - await resetDatabase(this.db) - } - - async exec(sql: string): Promise { - if (!this.db) { - throw new Error('Database has not been started. Call start() before executing queries.') - } - - return this.db.exec(sql) - } - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters - async query(sql: string, params?: unknown[]): Promise<{ rows: T[] }> { - if (!this.db) { - throw new Error('Database has not been started. Call start() before executing queries.') - } - - return this.db.query(sql, params) - } - - async transaction(fn: (tx: Pick) => Promise): Promise { - if (!this.db) { - throw new Error('Database has not been started. Call start() before executing queries.') - } - - return this.db.transaction(fn) - } - - async stop(): Promise { - if (this.unsubNotification) { - this.unsubNotification() - this.unsubNotification = undefined - } - - // Destroy all active client connections so the server can close - // immediately rather than waiting for long-lived connections (e.g. - // LISTEN) to end on their own. - for (const socket of this.connections) { - socket.destroy() - } - - this.connections.clear() - - await new Promise((resolve, reject) => { - if (!this.server) { - resolve() - - return - } - - this.server.close((err) => { - if (err) { - reject(err) - } else { - resolve() - } - }) - }) - - // Close PGLite to release internal handles (WASM runtime, etc.). - if (this.db) { - await this.db.close() - this.db = undefined - } - } - - private handleConnection(socket: Socket): void { - if (!this.db) { - return - } - - const db = this.db - - this.connections.add(socket) - - socket.on('close', () => { - this.connections.delete(socket) - }) - - fromNodeSocket(socket, { - serverVersion: '16.3 (NetlifyDB/pglite)', - auth: { - method: 'trust', - }, - - async onMessage(data: Uint8Array, { isAuthenticated }: ConnectionState): Promise { - // Skip startup/handshake messages handled by pg-gateway, as PGLite - // doesn't expect them. - if (!isAuthenticated) { - return - } - - return db.execProtocolRaw(data) - }, - }).catch((error: unknown) => { - if (error instanceof Error && error.message.includes('ECONNRESET')) { - return - } - - this.logger('Unexpected connection error:', error) - }) - } -} diff --git a/packages/database/dev/tsconfig.json b/packages/database/dev/tsconfig.json deleted file mode 100644 index 4c9f1a6..0000000 --- a/packages/database/dev/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "bundler", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/database/dev/tsup.config.ts b/packages/database/dev/tsup.config.ts deleted file mode 100644 index 88bc157..0000000 --- a/packages/database/dev/tsup.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - outDir: 'dist', - entry: ['src/main.ts'], - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, -}) diff --git a/packages/database/dev/vitest.config.ts b/packages/database/dev/vitest.config.ts deleted file mode 100644 index 1f197ac..0000000 --- a/packages/database/dev/vitest.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - typecheck: { - enabled: true, - }, - }, -}) diff --git a/packages/database/prod/CHANGELOG.md b/packages/database/prod/CHANGELOG.md deleted file mode 100644 index 6d96ce8..0000000 --- a/packages/database/prod/CHANGELOG.md +++ /dev/null @@ -1,66 +0,0 @@ -# Changelog - -## [1.0.0](https://github.com/netlify/primitives/compare/database-v0.7.0...database-v1.0.0) (2026-04-29) - - -### Features - -* update error message ([#672](https://github.com/netlify/primitives/issues/672)) ([6837ca5](https://github.com/netlify/primitives/commit/6837ca5bff8b31a8969c7c624cf4176abad52252)) - -## [0.7.0](https://github.com/netlify/primitives/compare/database-v0.6.1...database-v0.7.0) (2026-04-20) - - -### Features - -* **deps:** update `@neondatabase/serverless` ([#660](https://github.com/netlify/primitives/issues/660)) ([30f17d8](https://github.com/netlify/primitives/commit/30f17d8743a89cf345d65b41166e497b01f3fb14)) - -## [0.6.1](https://github.com/netlify/primitives/compare/database-v0.6.0...database-v0.6.1) (2026-04-15) - - -### Bug Fixes - -* **db:** move deps back into `dependencies` ([#656](https://github.com/netlify/primitives/issues/656)) ([0dc36d4](https://github.com/netlify/primitives/commit/0dc36d4cd2ceba6a5b7a870804ba7b4a0833e254)) - -## [0.6.0](https://github.com/netlify/primitives/compare/database-v0.5.0...database-v0.6.0) (2026-04-14) - - -### Features - -* **database:** add `getConnectionString` method ([#652](https://github.com/netlify/primitives/issues/652)) ([9a65377](https://github.com/netlify/primitives/commit/9a6537761a7189c43d6e9bfe65e8a443e570caec)) - -## [0.5.0](https://github.com/netlify/primitives/compare/database-v0.4.0...database-v0.5.0) (2026-04-13) - - -### Features - -* rename database package ([#649](https://github.com/netlify/primitives/issues/649)) ([bbe80bb](https://github.com/netlify/primitives/commit/bbe80bb31eedb74d08c08f35cd21f1360b9eb41f)) - -## [0.4.0](https://github.com/netlify/primitives/compare/db-v0.3.0...db-v0.4.0) (2026-03-19) - - -### Features - -* move db drivers to `peerDependencies` ([#632](https://github.com/netlify/primitives/issues/632)) ([4ac68a9](https://github.com/netlify/primitives/commit/4ac68a9b6071a64ff6df52dbeaffda9f28f54b88)) - -## [0.3.0](https://github.com/netlify/primitives/compare/db-v0.2.0...db-v0.3.0) (2026-03-03) - - -### Features - -* **db:** configure WebSocket constructor automatically ([#603](https://github.com/netlify/primitives/issues/603)) ([9495c25](https://github.com/netlify/primitives/commit/9495c259f1690fd364990858104d165033a470bc)) - -## [0.2.0](https://github.com/netlify/primitives/compare/db-v0.1.0...db-v0.2.0) (2026-03-02) - - -### Features - -* expose driver in `getDatabase` ([#601](https://github.com/netlify/primitives/issues/601)) ([eec2587](https://github.com/netlify/primitives/commit/eec2587bbd0dc6de7aa082f71509e0341353127a)) - -## [0.1.0](https://github.com/netlify/primitives/compare/db-v0.0.1...db-v0.1.0) (2026-02-16) - - -### Features - -* add `db` package ([#581](https://github.com/netlify/primitives/issues/581)) ([b60a313](https://github.com/netlify/primitives/commit/b60a313bd9ba19fd5deced4736012c3d7c7fe842)) -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) -* update `@netlify/db` version ([#589](https://github.com/netlify/primitives/issues/589)) ([a0da26e](https://github.com/netlify/primitives/commit/a0da26e41f2c72ef22233968b139663b5d7dea79)) diff --git a/packages/database/prod/package.json b/packages/database/prod/package.json deleted file mode 100644 index 77275f6..0000000 --- a/packages/database/prod/package.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "name": "@netlify/database", - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "type": "module", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - } - }, - "version": "1.0.0", - "publishConfig": { - "access": "public" - }, - "description": "TypeScript utilities for interacting with Netlify Database", - "files": [ - "dist/**/*.js", - "dist/**/*.cjs", - "dist/**/*.mjs", - "dist/**/*.d.ts", - "dist/**/*.d.cts", - "dist/**/*.d.mts" - ], - "scripts": { - "dev": "tsup-node --watch", - "build": "tsup-node", - "prepack": "npm run build", - "test": "run-s test:ci", - "test:ci": "run-s test:ci:*", - "test:ci:vitest": "npm run build && vitest run", - "test:dev": "vitest" - }, - "keywords": [ - "netlify", - "db", - "database" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/database/prod" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "@neondatabase/serverless": "^1.1.0", - "@netlify/runtime-utils": "2.3.0", - "pg": "^8.13.0", - "waddler": "^0.1.1", - "ws": "^8.18.0" - }, - "devDependencies": { - "@types/ws": "^8.18.1", - "npm-run-all2": "^5.0.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, - "engines": { - "node": ">=20.6.1" - } -} diff --git a/packages/database/prod/src/environment.ts b/packages/database/prod/src/environment.ts deleted file mode 100644 index fcb39d5..0000000 --- a/packages/database/prod/src/environment.ts +++ /dev/null @@ -1,9 +0,0 @@ -export class MissingDatabaseConnectionError extends Error { - constructor() { - super( - 'The environment has not been configured to use Netlify Database. You must supply the `connectionString` option when calling `getDatabase()`. See https://ntl.fyi/database-environment for details.', - ) - - this.name = 'MissingDatabaseConnectionError' - } -} diff --git a/packages/database/prod/src/main.test.ts b/packages/database/prod/src/main.test.ts deleted file mode 100644 index cc13b91..0000000 --- a/packages/database/prod/src/main.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' - -import { getConnectionString, getDatabase, MissingDatabaseConnectionError } from './main.js' - -const { mockWaddlerNodePostgres, mockWaddlerNeonHttp, mockPgPool, mockNeonPool, mockNeon, mockNeonConfig } = vi.hoisted( - () => ({ - mockWaddlerNodePostgres: vi.fn().mockReturnValue('node-postgres-sql'), - mockWaddlerNeonHttp: vi.fn().mockReturnValue('neon-http-sql'), - mockPgPool: vi.fn(), - mockNeonPool: vi.fn(), - mockNeon: vi.fn().mockReturnValue('neon-http-client'), - mockNeonConfig: {} as Record, - }), -) - -vi.mock('waddler/node-postgres', () => ({ - waddler: mockWaddlerNodePostgres, -})) - -vi.mock('waddler/neon-http', () => ({ - waddler: mockWaddlerNeonHttp, -})) - -vi.mock('pg', () => ({ - default: { Pool: mockPgPool }, -})) - -vi.mock('@neondatabase/serverless', () => ({ - Pool: mockNeonPool, - neon: mockNeon, - neonConfig: mockNeonConfig, -})) - -vi.mock('ws', () => ({ - default: function MockWebSocket() {}, -})) - -const CONNECTION_STRING = 'postgres://user:pass@localhost:5432/mydb' -const OTHER_CONNECTION_STRING = 'postgres://other:pass@localhost:5432/otherdb' - -describe('getDatabase', () => { - const originalEnv = process.env - - beforeEach(() => { - process.env = { ...originalEnv } - delete process.env.NETLIFY_DB_URL - delete process.env.NETLIFY_DB_DRIVER - }) - - afterEach(() => { - process.env = originalEnv - vi.clearAllMocks() - }) - - it('throws MissingDatabaseConnectionError when no connection string is available', () => { - expect(() => getDatabase()).toThrow(MissingDatabaseConnectionError) - expect(() => getDatabase()).toThrow( - 'The environment has not been configured to use Netlify Database. You must supply the `connectionString` option when calling `getDatabase()`. See https://ntl.fyi/database-environment for details.', - ) - }) - - it('returns an object with sql, pool, and connectionString using node-postgres by default', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - - const result = getDatabase() - - expect(mockPgPool).toHaveBeenCalledWith({ connectionString: CONNECTION_STRING }) - expect(mockWaddlerNodePostgres).toHaveBeenCalledWith({ client: expect.any(Object) }) - expect(mockWaddlerNeonHttp).not.toHaveBeenCalled() - expect(mockNeonPool).not.toHaveBeenCalled() - expect(result).toEqual({ - driver: 'server', - sql: 'node-postgres-sql', - pool: expect.any(Object), - connectionString: CONNECTION_STRING, - }) - }) - - it('uses node-postgres when NETLIFY_DB_DRIVER is "server"', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - process.env.NETLIFY_DB_DRIVER = 'server' - - const result = getDatabase() - - expect(mockWaddlerNodePostgres).toHaveBeenCalled() - expect(mockWaddlerNeonHttp).not.toHaveBeenCalled() - expect(result.connectionString).toBe(CONNECTION_STRING) - }) - - it('uses neon-http for sql and neon Pool for pool when NETLIFY_DB_DRIVER is "serverless"', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - process.env.NETLIFY_DB_DRIVER = 'serverless' - - const result = getDatabase() - - expect(mockWaddlerNeonHttp).toHaveBeenCalledWith({ client: 'neon-http-client' }) - expect(mockNeonPool).toHaveBeenCalledWith({ connectionString: CONNECTION_STRING }) - expect(mockWaddlerNodePostgres).not.toHaveBeenCalled() - expect(mockPgPool).not.toHaveBeenCalled() - expect(mockNeon).toHaveBeenCalledWith(CONNECTION_STRING) - expect(result).toEqual({ - driver: 'serverless', - sql: 'neon-http-sql', - pool: expect.any(Object), - httpClient: 'neon-http-client', - connectionString: CONNECTION_STRING, - }) - }) - - it('sets neonConfig.webSocketConstructor from ws when WebSocket is not globally available', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - process.env.NETLIFY_DB_DRIVER = 'serverless' - delete mockNeonConfig.webSocketConstructor - - const originalWebSocket = globalThis.WebSocket - // @ts-expect-error — removing global to simulate older Node - delete globalThis.WebSocket - - try { - getDatabase() - expect(mockNeonConfig.webSocketConstructor).toBeDefined() - } finally { - globalThis.WebSocket = originalWebSocket - } - }) - - it('does not override neonConfig.webSocketConstructor if already set', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - process.env.NETLIFY_DB_DRIVER = 'serverless' - const existingWs = function ExistingWebSocket() {} - mockNeonConfig.webSocketConstructor = existingWs - - getDatabase() - - expect(mockNeonConfig.webSocketConstructor).toBe(existingWs) - }) - - it('allows override via connectionString option', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - - const result = getDatabase({ connectionString: OTHER_CONNECTION_STRING }) - - expect(mockPgPool).toHaveBeenCalledWith({ connectionString: OTHER_CONNECTION_STRING }) - expect(result.connectionString).toBe(OTHER_CONNECTION_STRING) - }) - - it('uses NETLIFY_DB_URL environment variable', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - - const result = getDatabase() - - expect(mockPgPool).toHaveBeenCalledWith({ connectionString: CONNECTION_STRING }) - expect(result.connectionString).toBe(CONNECTION_STRING) - }) -}) - -describe('getConnectionString', () => { - const originalEnv = process.env - - beforeEach(() => { - process.env = { ...originalEnv } - delete process.env.NETLIFY_DB_URL - }) - - afterEach(() => { - process.env = originalEnv - }) - - it('returns the connection string from NETLIFY_DB_URL', () => { - process.env.NETLIFY_DB_URL = CONNECTION_STRING - - expect(getConnectionString()).toBe(CONNECTION_STRING) - }) - - it('throws MissingDatabaseConnectionError when NETLIFY_DB_URL is not set', () => { - expect(() => getConnectionString()).toThrow(MissingDatabaseConnectionError) - }) -}) diff --git a/packages/database/prod/src/main.ts b/packages/database/prod/src/main.ts deleted file mode 100644 index 1911e84..0000000 --- a/packages/database/prod/src/main.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { neon, neonConfig, Pool as NeonPool } from '@neondatabase/serverless' -import type { NeonQueryFunction } from '@neondatabase/serverless' -import ws from 'ws' -import pg from 'pg' -import type { SQL } from 'waddler' -import { waddler as waddlerNeonHttp } from 'waddler/neon-http' -import { waddler as waddlerNodePostgres } from 'waddler/node-postgres' - -import { getEnvironment } from '@netlify/runtime-utils' - -import { MissingDatabaseConnectionError } from './environment.js' - -export interface GetDatabaseOptions { - connectionString?: string - debug?: boolean -} - -export interface ServerDatabaseConnection { - driver: 'server' - sql: SQL - pool: pg.Pool - connectionString: string -} - -export interface ServerlessDatabaseConnection { - driver: 'serverless' - sql: SQL - pool: NeonPool - // Using because neon() returns NeonQueryFunction, - // which is incompatible with drizzle-orm's NeonHttpClient (NeonQueryFunction) - // due to contravariance in the transaction method's generic parameters. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - httpClient: NeonQueryFunction - connectionString: string -} - -export type DatabaseConnection = ServerDatabaseConnection | ServerlessDatabaseConnection - -export function getConnectionString(): string { - const env = getEnvironment() - const connectionString = env.get('NETLIFY_DB_URL') - - if (!connectionString) { - throw new MissingDatabaseConnectionError() - } - - return connectionString -} - -export function getDatabase(options: GetDatabaseOptions = {}): DatabaseConnection { - const env = getEnvironment() - const connectionString = options.connectionString ?? env.get('NETLIFY_DB_URL') - - if (!connectionString) { - throw new MissingDatabaseConnectionError() - } - - const driver = env.get('NETLIFY_DB_DRIVER') - - if (driver === 'serverless') { - // We can remove this, and the dependency on `ws`, once we stop supporting - // Node.js 22. - /* eslint-disable n/no-unsupported-features/node-builtins */ - if (!neonConfig.webSocketConstructor && typeof WebSocket === 'undefined') { - neonConfig.webSocketConstructor = ws as unknown as typeof WebSocket - } - /* eslint-enable n/no-unsupported-features/node-builtins */ - - const httpClient = neon(connectionString) - - return { - driver: 'serverless', - sql: waddlerNeonHttp({ client: httpClient }), - pool: new NeonPool({ connectionString }), - httpClient, - connectionString, - } - } - - // Default ("server"): node-postgres for long-running servers - const pool = new pg.Pool({ connectionString }) - - return { - driver: 'server', - sql: waddlerNodePostgres({ client: pool }), - pool, - connectionString, - } -} - -export { MissingDatabaseConnectionError } diff --git a/packages/database/prod/tsconfig.json b/packages/database/prod/tsconfig.json deleted file mode 100644 index 4c9f1a6..0000000 --- a/packages/database/prod/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "bundler", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/database/prod/tsup.config.ts b/packages/database/prod/tsup.config.ts deleted file mode 100644 index 996cded..0000000 --- a/packages/database/prod/tsup.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - format: ['cjs', 'esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - external: [ - '@neondatabase/serverless', - 'pg', - 'waddler', - 'waddler/node-postgres', - 'waddler/neon-http', - 'waddler/neon-serverless', - ], -}) diff --git a/packages/database/prod/vitest.config.ts b/packages/database/prod/vitest.config.ts deleted file mode 100644 index 1f197ac..0000000 --- a/packages/database/prod/vitest.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - typecheck: { - enabled: true, - }, - }, -}) diff --git a/packages/database/proxy/CHANGELOG.md b/packages/database/proxy/CHANGELOG.md deleted file mode 100644 index b850921..0000000 --- a/packages/database/proxy/CHANGELOG.md +++ /dev/null @@ -1,50 +0,0 @@ -# Changelog - -## [0.1.5](https://github.com/netlify/primitives/compare/database-proxy-v0.1.4...database-proxy-v0.1.5) (2026-04-27) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/database-dev bumped from 0.10.0 to 0.10.1 - -## [0.1.4](https://github.com/netlify/primitives/compare/database-proxy-v0.1.3...database-proxy-v0.1.4) (2026-04-20) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/database-dev bumped from 0.9.0 to 0.10.0 - -## [0.1.3](https://github.com/netlify/primitives/compare/database-proxy-v0.1.2...database-proxy-v0.1.3) (2026-04-20) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/database-dev bumped from 0.8.0 to 0.9.0 - -## [0.1.2](https://github.com/netlify/primitives/compare/database-proxy-v0.1.1...database-proxy-v0.1.2) (2026-04-13) - - -### Features - -* rename database package ([#649](https://github.com/netlify/primitives/issues/649)) ([bbe80bb](https://github.com/netlify/primitives/commit/bbe80bb31eedb74d08c08f35cd21f1360b9eb41f)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/database-dev bumped from * to 0.8.0 - -## [0.1.1](https://github.com/netlify/primitives/compare/db-proxy-v0.1.0...db-proxy-v0.1.1) (2026-04-07) - - -### Features - -* add `@netlify/db-proxy` package ([#645](https://github.com/netlify/primitives/issues/645)) ([c52e3a1](https://github.com/netlify/primitives/commit/c52e3a19cbc5cb77427e6910a058cda6e70c7222)) -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) diff --git a/packages/database/proxy/package.json b/packages/database/proxy/package.json deleted file mode 100644 index 47bba2b..0000000 --- a/packages/database/proxy/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@netlify/database-proxy", - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "type": "module", - "exports": { - ".": { - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - } - }, - "version": "0.1.5", - "description": "Transparent PostgreSQL proxy for Netlify Database with dynamic provisioning", - "files": [ - "dist/**/*.js", - "dist/**/*.mjs", - "dist/**/*.d.ts", - "dist/**/*.d.mts" - ], - "scripts": { - "dev": "tsup-node --watch", - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest" - }, - "keywords": [ - "netlify", - "db", - "database", - "postgres", - "proxy" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/database/proxy" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "pg": "^8.11.0" - }, - "devDependencies": { - "@netlify/database-dev": "0.10.1", - "@types/pg": "^8.11.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, - "engines": { - "node": ">=20.6.1" - } -} diff --git a/packages/database/proxy/src/lib/connection.ts b/packages/database/proxy/src/lib/connection.ts deleted file mode 100644 index 3bc63eb..0000000 --- a/packages/database/proxy/src/lib/connection.ts +++ /dev/null @@ -1,180 +0,0 @@ -import net from 'node:net' - -import pg from 'pg' - -import type { ProvisionCallback } from '../main.js' -import { parseConnectionString } from '../main.js' - -import { - SSL_REQUEST_CODE, - PROTOCOL_VERSION_3_0, - SSL_RESPONSE_NO, - buildAuthOkAndReady, - buildErrorResponse, -} from './pg-protocol.js' - -interface HandleStartupOptions { - clientSocket: net.Socket - provision: ProvisionCallback - logger: (...args: unknown[]) => void - cleanup: () => void -} - -async function handleStartup(options: HandleStartupOptions): Promise { - const { clientSocket, provision, logger, cleanup } = options - - let connectionString: string - try { - connectionString = await provision() - } catch (err) { - const message = err instanceof Error ? err.message : 'Provisioning failed' - logger('Provisioning error:', message) - clientSocket.end(buildErrorResponse(message)) - cleanup() - throw err - } - - const credentials = parseConnectionString(connectionString) - - const pgClient = new pg.Client({ - host: credentials.host, - port: credentials.port, - user: credentials.user, - password: credentials.password, - database: credentials.database, - ssl: credentials.ssl, - options: credentials.options, - }) - - // Suppress unhandled errors from the pg client - pgClient.on('error', () => {}) - - try { - await pgClient.connect() - } catch (err) { - const message = err instanceof Error ? err.message : 'Remote connection failed' - logger('Remote connection error:', message) - clientSocket.end(buildErrorResponse(message)) - cleanup() - throw err - } - - // Get the underlying socket from the pg client. - const pgConnection = pgClient.connection - const pgStream = pgConnection.stream as net.Socket - - // Completely mute the pg driver — remove all listeners from both - // the Connection EventEmitter and the raw socket so we can handle - // raw bytes ourselves without the driver interfering or throwing - // unhandled errors on teardown. - pgConnection.removeAllListeners() - pgStream.removeAllListeners() - - const remoteSocket = pgStream - - // Set up error/close handlers on both sides - const onError = (side: string) => (err: NodeJS.ErrnoException) => { - if (err.code !== 'ECONNRESET') { - logger(`${side} socket error:`, err.message) - } - cleanup() - } - - remoteSocket.on('error', onError('Remote')) - remoteSocket.on('close', cleanup) - clientSocket.on('error', onError('Client')) - clientSocket.on('close', cleanup) - - // Send auth OK and ready to the client - clientSocket.write(buildAuthOkAndReady()) - - // Set up bidirectional data forwarding (manual instead of pipe - // to avoid pipe adding its own end/close/error listeners that - // can cause unhandled errors during teardown) - clientSocket.on('data', (chunk: Buffer) => { - if (!remoteSocket.destroyed) { - remoteSocket.write(chunk) - } - }) - - remoteSocket.on('data', (chunk: Buffer) => { - if (!clientSocket.destroyed) { - clientSocket.write(chunk) - } - }) - - clientSocket.resume() - - return remoteSocket -} - -interface ConnectionHandlerOptions { - provision: ProvisionCallback - logger: (...args: unknown[]) => void - onCleanup: () => void -} - -export function handleConnection(clientSocket: net.Socket, options: ConnectionHandlerOptions): void { - const { provision, logger, onCleanup } = options - let remoteSocket: net.Socket | undefined - let phase: 'ssl' | 'startup' | 'piping' = 'ssl' - let cleaned = false - - function cleanup() { - if (cleaned) return - cleaned = true - - clientSocket.destroy() - remoteSocket?.destroy() - onCleanup() - } - - clientSocket.on('error', (err: NodeJS.ErrnoException) => { - if (err.code !== 'ECONNRESET') { - logger('Client socket error:', err.message) - } - cleanup() - }) - - clientSocket.on('data', (data: Buffer) => { - if (phase === 'ssl') { - if (data.length >= 8) { - const requestCode = data.readInt32BE(4) - if (requestCode === SSL_REQUEST_CODE) { - clientSocket.write(SSL_RESPONSE_NO) - phase = 'startup' - return - } - } - phase = 'startup' - } - - if (phase === 'startup') { - if (data.length < 8) { - clientSocket.end(buildErrorResponse('Invalid startup message')) - cleanup() - return - } - - const protocolVersion = data.readInt32BE(4) - if (protocolVersion !== PROTOCOL_VERSION_3_0) { - clientSocket.end(buildErrorResponse('Unsupported protocol version')) - cleanup() - return - } - - clientSocket.pause() - clientSocket.removeAllListeners('data') - - handleStartup({ clientSocket, provision, logger, cleanup }).then( - (stream) => { - remoteSocket = stream - }, - (err: unknown) => { - logger('Startup error:', err) - cleanup() - }, - ) - } - }) -} diff --git a/packages/database/proxy/src/lib/pg-protocol.ts b/packages/database/proxy/src/lib/pg-protocol.ts deleted file mode 100644 index 92e9e66..0000000 --- a/packages/database/proxy/src/lib/pg-protocol.ts +++ /dev/null @@ -1,50 +0,0 @@ -export const SSL_REQUEST_CODE = 80877103 -export const PROTOCOL_VERSION_3_0 = 196608 -export const SSL_RESPONSE_NO = Buffer.from([0x4e]) - -/** - * Builds the AuthenticationOk + ReadyForQuery messages to send to a client - * after successful authentication. - * - * AuthenticationOk: 'R' + int32(8) + int32(0) - * ReadyForQuery: 'Z' + int32(5) + byte('I') - */ -export function buildAuthOkAndReady(): Buffer { - // AuthenticationOk message - const authOk = Buffer.alloc(9) - authOk.writeUInt8(0x52, 0) // 'R' - authOk.writeInt32BE(8, 1) // length - authOk.writeInt32BE(0, 5) // success - - // ReadyForQuery message - const ready = Buffer.alloc(6) - ready.writeUInt8(0x5a, 0) // 'Z' - ready.writeInt32BE(5, 1) // length - ready.writeUInt8(0x49, 5) // 'I' = idle - - return Buffer.concat([authOk, ready]) -} - -/** - * Builds a PostgreSQL ErrorResponse message. - * - * ErrorResponse: 'E' + int32(length) + fields + null terminator - * Fields: byte(type) + null-terminated string - */ -export function buildErrorResponse(message: string): Buffer { - // Severity field: 'S' + "ERROR\0" - const severity = Buffer.from('SERROR\0', 'utf8') - // Message field: 'M' + message + '\0' - const msgField = Buffer.concat([Buffer.from('M', 'utf8'), Buffer.from(message + '\0', 'utf8')]) - // Code field: 'C' + "XX000\0" (internal error) - const code = Buffer.from('CXX000\0', 'utf8') - // Null terminator for the message - const terminator = Buffer.from([0]) - - const bodyLength = severity.length + msgField.length + code.length + terminator.length - const header = Buffer.alloc(5) - header.writeUInt8(0x45, 0) // 'E' - header.writeInt32BE(bodyLength + 4, 1) // length includes itself - - return Buffer.concat([header, severity, code, msgField, terminator]) -} diff --git a/packages/database/proxy/src/main.test.ts b/packages/database/proxy/src/main.test.ts deleted file mode 100644 index e17b5ae..0000000 --- a/packages/database/proxy/src/main.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { Client } from 'pg' -import { test, expect, afterEach, describe } from 'vitest' -import { NetlifyDB } from '@netlify/database-dev' - -import { NetlifyDBProxy } from './main.js' - -let backend: NetlifyDB | undefined -let proxy: NetlifyDBProxy | undefined - -afterEach(async () => { - if (proxy) { - await proxy.stop() - proxy = undefined - } - - if (backend) { - await backend.stop() - backend = undefined - } -}) - -async function setupBackendAndProxy( - provisionOverride?: () => Promise, -): Promise<{ backendUrl: string; proxyUrl: string }> { - backend = new NetlifyDB({ logger: () => {} }) - const backendUrl = await backend.start() - - proxy = new NetlifyDBProxy({ - provision: provisionOverride ?? (() => Promise.resolve(backendUrl)), - logger: () => {}, - }) - - const proxyUrl = await proxy.start() - - return { backendUrl, proxyUrl } -} - -describe('NetlifyDBProxy', () => { - test('starts and returns a valid connection string', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - expect(proxyUrl).toMatch(/^postgres:\/\/127\.0\.0\.1:\d+$/) - }) - - test('accepts a client connection and runs SELECT 1', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - const client = new Client({ connectionString: proxyUrl }) - await client.connect() - - const result = await client.query('SELECT 1 AS value') - expect(result.rows).toEqual([{ value: 1 }]) - - await client.end() - }) - - test('provision callback is invoked on connection', async () => { - backend = new NetlifyDB({ logger: () => {} }) - const backendUrl = await backend.start() - - let provisionCalled = false - - proxy = new NetlifyDBProxy({ - logger: () => {}, - provision: () => { - provisionCalled = true - return Promise.resolve(backendUrl) - }, - }) - - const proxyUrl = await proxy.start() - - const client = new Client({ connectionString: proxyUrl }) - await client.connect() - await client.end() - - expect(provisionCalled).toBe(true) - }) - - test('handles SSL negotiation (sslmode=prefer)', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - const client = new Client({ - connectionString: proxyUrl, - ssl: false, - }) - await client.connect() - - const result = await client.query('SELECT 1 AS value') - expect(result.rows).toEqual([{ value: 1 }]) - - await client.end() - }) - - test('proxies DDL and DML operations', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - const client = new Client({ connectionString: proxyUrl }) - await client.connect() - - await client.query('CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT NOT NULL)') - await client.query("INSERT INTO test_table (name) VALUES ('alice')") - await client.query("INSERT INTO test_table (name) VALUES ('bob')") - - const result = await client.query('SELECT name FROM test_table ORDER BY id') - expect(result.rows).toEqual([{ name: 'alice' }, { name: 'bob' }]) - - await client.end() - }) - - test('supports multiple concurrent connections', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - const client1 = new Client({ connectionString: proxyUrl }) - const client2 = new Client({ connectionString: proxyUrl }) - - await client1.connect() - await client2.connect() - - await client1.query('CREATE TABLE concurrent_test (id SERIAL PRIMARY KEY, val INT)') - await client1.query('INSERT INTO concurrent_test (val) VALUES (1)') - await client2.query('INSERT INTO concurrent_test (val) VALUES (2)') - - const result = await client1.query('SELECT val FROM concurrent_test ORDER BY val') - expect(result.rows).toEqual([{ val: 1 }, { val: 2 }]) - - await client1.end() - await client2.end() - }) - - test('provisioning failure sends PG error to client', async () => { - proxy = new NetlifyDBProxy({ - logger: () => {}, - provision: () => { - return Promise.reject(new Error('Database not found')) - }, - }) - - const proxyUrl = await proxy.start() - - const client = new Client({ connectionString: proxyUrl }) - - await expect(client.connect()).rejects.toThrow() - }) - - test('clean shutdown via stop()', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - const client = new Client({ connectionString: proxyUrl }) - // Suppress unhandled errors from the pg client when the proxy destroys the socket - client.on('error', () => {}) - await client.connect() - - // Verify connection works - await client.query('SELECT 1') - - // Stop the proxy — this should destroy the client socket - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const proxyRef = proxy! - proxy = undefined - await proxyRef.stop() - - // The client should be disconnected - await expect(client.query('SELECT 1')).rejects.toThrow() - }) - - test('client disconnect cleans up remote socket', async () => { - const { proxyUrl } = await setupBackendAndProxy() - - const client = new Client({ connectionString: proxyUrl }) - await client.connect() - - await client.query('SELECT 1') - await client.end() - - // Give a moment for cleanup - await new Promise((resolve) => setTimeout(resolve, 100)) - - // Proxy should still be running and accept new connections - const client2 = new Client({ connectionString: proxyUrl }) - await client2.connect() - const result = await client2.query('SELECT 1 AS value') - expect(result.rows).toEqual([{ value: 1 }]) - await client2.end() - }) -}) diff --git a/packages/database/proxy/src/main.ts b/packages/database/proxy/src/main.ts deleted file mode 100644 index 9389959..0000000 --- a/packages/database/proxy/src/main.ts +++ /dev/null @@ -1,103 +0,0 @@ -import net from 'node:net' - -import { handleConnection } from './lib/connection.js' - -export interface ConnectionCredentials { - host: string - port: number - user: string - password: string - database: string - ssl?: boolean | object - options?: string -} - -export type ProvisionCallback = () => Promise - -export interface NetlifyDBProxyOptions { - host?: string - port?: number - logger?: (...args: unknown[]) => void - provision: ProvisionCallback -} - -export function parseConnectionString(connectionString: string): ConnectionCredentials { - const url = new URL(connectionString) - - return { - host: url.hostname, - port: Number(url.port) || 5432, - user: decodeURIComponent(url.username), - password: decodeURIComponent(url.password), - database: url.pathname.slice(1) || 'postgres', - ssl: url.searchParams.get('sslmode') === 'require' ? true : undefined, - options: url.searchParams.get('options') ?? undefined, - } -} - -export class NetlifyDBProxy { - private server: net.Server | undefined - private sockets = new Set() - private host: string - private port: number - private logger: (...args: unknown[]) => void - private provision: ProvisionCallback - - constructor(options: NetlifyDBProxyOptions) { - this.host = options.host ?? '127.0.0.1' - this.port = options.port ?? 0 - this.logger = options.logger ?? (() => {}) - this.provision = options.provision - } - - async start(): Promise { - return new Promise((resolve, reject) => { - const server = net.createServer((socket) => { - this.sockets.add(socket) - socket.on('close', () => { - this.sockets.delete(socket) - }) - - handleConnection(socket, { - provision: this.provision, - logger: this.logger, - onCleanup: () => { - this.sockets.delete(socket) - }, - }) - }) - - server.on('error', (err) => { - reject(err) - }) - - server.listen(this.port, this.host, () => { - this.server = server - const addr = server.address() as net.AddressInfo - const connectionString = `postgres://${this.host}:${String(addr.port)}` - this.logger('Proxy listening on', connectionString) - resolve(connectionString) - }) - }) - } - - async stop(): Promise { - // Destroy all active client sockets - for (const socket of this.sockets) { - socket.destroy() - } - this.sockets.clear() - - return new Promise((resolve) => { - if (!this.server) { - resolve() - return - } - - this.server.close(() => { - this.server = undefined - resolve() - }) - }) - } -} diff --git a/packages/database/proxy/tsconfig.json b/packages/database/proxy/tsconfig.json deleted file mode 100644 index 4c9f1a6..0000000 --- a/packages/database/proxy/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "bundler", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/database/proxy/tsup.config.ts b/packages/database/proxy/tsup.config.ts deleted file mode 100644 index 88bc157..0000000 --- a/packages/database/proxy/tsup.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - outDir: 'dist', - entry: ['src/main.ts'], - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, -}) diff --git a/packages/database/proxy/vitest.config.ts b/packages/database/proxy/vitest.config.ts deleted file mode 100644 index 1f197ac..0000000 --- a/packages/database/proxy/vitest.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - typecheck: { - enabled: true, - }, - }, -}) diff --git a/packages/dev-utils/.gitignore b/packages/dev-utils/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/dev-utils/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md deleted file mode 100644 index e362bb0..0000000 --- a/packages/dev-utils/CHANGELOG.md +++ /dev/null @@ -1,262 +0,0 @@ -# Changelog - -## [4.4.6](https://github.com/netlify/primitives/compare/dev-utils-v4.4.5...dev-utils-v4.4.6) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.7.0 to 2.8.0 - -## [4.4.5](https://github.com/netlify/primitives/compare/dev-utils-v4.4.4...dev-utils-v4.4.5) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.6.0 to 2.7.0 - -## [4.4.4](https://github.com/netlify/primitives/compare/dev-utils-v4.4.3...dev-utils-v4.4.4) (2026-05-15) - - -### Bug Fixes - -* **dev-utils:** replace `write-file-atomic` with `atomically` ([#686](https://github.com/netlify/primitives/issues/686)) ([39b6fb5](https://github.com/netlify/primitives/commit/39b6fb5a5db961e4423f425ed3a65c2f274f65fc)) - -## [4.4.3](https://github.com/netlify/primitives/compare/dev-utils-v4.4.2...dev-utils-v4.4.3) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.5.0 to 2.6.0 - -## [4.4.2](https://github.com/netlify/primitives/compare/dev-utils-v4.4.1...dev-utils-v4.4.2) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.4.0 to 2.5.0 - -## [4.4.1](https://github.com/netlify/primitives/compare/dev-utils-v4.4.0...dev-utils-v4.4.1) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.3.0 to 2.4.0 - -## [4.4.0](https://github.com/netlify/primitives/compare/dev-utils-v4.3.3...dev-utils-v4.4.0) (2026-03-10) - - -### Features - -* add `FileWatcher` class ([#607](https://github.com/netlify/primitives/issues/607)) ([1f8bdfc](https://github.com/netlify/primitives/commit/1f8bdfc06e411703cc9338b9cd7dfe3a0c0f4eff)) - -## [4.3.3](https://github.com/netlify/primitives/compare/dev-utils-v4.3.2...dev-utils-v4.3.3) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.2.0 to 2.3.0 - -## [4.3.2](https://github.com/netlify/primitives/compare/dev-utils-v4.3.1...dev-utils-v4.3.2) (2025-11-14) - - -### Bug Fixes - -* **deps:** update dependency uuid to v13 ([#539](https://github.com/netlify/primitives/issues/539)) ([aedb279](https://github.com/netlify/primitives/commit/aedb279a24ad41d1db5db98d1e0e976e4a2db98a)) - -## [4.3.1](https://github.com/netlify/primitives/compare/dev-utils-v4.3.0...dev-utils-v4.3.1) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.1.0 to 2.2.0 - -## [4.3.0](https://github.com/netlify/primitives/compare/dev-utils-v4.2.0...dev-utils-v4.3.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.0.3 to 2.1.0 - -## [4.2.0](https://github.com/netlify/primitives/compare/dev-utils-v4.1.3...dev-utils-v4.2.0) (2025-09-22) - - -### Features - -* add `@netlify/vite-plugin-tanstack-start` ([#455](https://github.com/netlify/primitives/issues/455)) ([fd8b2cc](https://github.com/netlify/primitives/commit/fd8b2cc9012801c190f332089e9f4322fad95a45)) - -## [4.1.3](https://github.com/netlify/primitives/compare/dev-utils-v4.1.2...dev-utils-v4.1.3) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.0.1 to 2.0.3 - -## [4.1.2](https://github.com/netlify/primitives/compare/dev-utils-v4.1.1...dev-utils-v4.1.2) (2025-08-19) - - -### Bug Fixes - -* **deps:** replace lodash.debounce with dettle ([#388](https://github.com/netlify/primitives/issues/388)) ([9c5c1e7](https://github.com/netlify/primitives/commit/9c5c1e7cd326a63818a4a09ea11b77fb5e09eed1)) - -## [4.1.1](https://github.com/netlify/primitives/compare/dev-utils-v4.1.0...dev-utils-v4.1.1) (2025-07-29) - - -### Bug Fixes - -* include html templates with dev-utils package ([#396](https://github.com/netlify/primitives/issues/396)) ([8fc2e28](https://github.com/netlify/primitives/commit/8fc2e28223763fb195729d81b7d2146d49c63819)) - -## [4.1.0](https://github.com/netlify/primitives/compare/dev-utils-v4.0.0...dev-utils-v4.1.0) (2025-07-23) - - -### Features - -* add actual dev geolocation to functions and edge functions context ([#345](https://github.com/netlify/primitives/issues/345)) ([916c38b](https://github.com/netlify/primitives/commit/916c38b84632b705a1d6ab4bfc6d60bfebd1ed2c)) - -## [4.0.0](https://github.com/netlify/primitives/compare/dev-utils-v3.3.0...dev-utils-v4.0.0) (2025-07-17) - - -### ⚠ BREAKING CHANGES - -* add named exports for global-config utils ([#359](https://github.com/netlify/primitives/issues/359)) - -### Bug Fixes - -* add named exports for global-config utils ([#359](https://github.com/netlify/primitives/issues/359)) ([c66b7e0](https://github.com/netlify/primitives/commit/c66b7e0ac3c2c1a3725883fe45b81bdc7ffb24fd)) - -## [3.3.0](https://github.com/netlify/primitives/compare/dev-utils-v3.2.2...dev-utils-v3.3.0) (2025-07-15) - - -### Features - -* add `@netlify/nuxt` Nuxt module ([#344](https://github.com/netlify/primitives/issues/344)) ([efdf8df](https://github.com/netlify/primitives/commit/efdf8dfb22ffe33b557d2140fd3a3152e23cc95c)) - -## [3.2.2](https://github.com/netlify/primitives/compare/dev-utils-v3.2.1...dev-utils-v3.2.2) (2025-07-04) - - -### Bug Fixes - -* **deps:** move tmp-promise to prod deps ([#329](https://github.com/netlify/primitives/issues/329)) ([f8d46bf](https://github.com/netlify/primitives/commit/f8d46bf759e15ed866436838610ddadbb06c0de1)) - -## [3.2.1](https://github.com/netlify/primitives/compare/dev-utils-v3.2.0...dev-utils-v3.2.1) (2025-06-18) - - -### Bug Fixes - -* clean up edge functions server ([#310](https://github.com/netlify/primitives/issues/310)) ([243f3b4](https://github.com/netlify/primitives/commit/243f3b472d1350eb6a80d8f736385750de8bc0d4)) - -## [3.2.0](https://github.com/netlify/primitives/compare/dev-utils-v3.1.1...dev-utils-v3.2.0) (2025-06-06) - - -### Features - -* image cdn support ([#232](https://github.com/netlify/primitives/issues/232)) ([01c844d](https://github.com/netlify/primitives/commit/01c844d82a27a9812be7634219d9bdc69a128985)) - -## [3.1.1](https://github.com/netlify/primitives/compare/dev-utils-v3.1.0...dev-utils-v3.1.1) (2025-06-03) - - -### Bug Fixes - -* revamp dev and vite plugin logging ([#269](https://github.com/netlify/primitives/issues/269)) ([de9b46c](https://github.com/netlify/primitives/commit/de9b46c1cb1c7b2bf6437ab516134e44203d83b7)) - -## [3.1.0](https://github.com/netlify/primitives/compare/dev-utils-v3.0.0...dev-utils-v3.1.0) (2025-06-02) - - -### Features - -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) - - -### Bug Fixes - -* ensure valid 18.14.0+ dependencies ([#254](https://github.com/netlify/primitives/issues/254)) ([09dd0d8](https://github.com/netlify/primitives/commit/09dd0d8e1ab0c028eee8715b05307d8961b28463)) - -## [3.0.0](https://github.com/netlify/primitives/compare/dev-utils-v2.2.0...dev-utils-v3.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Features - -* add support for headers config ([#200](https://github.com/netlify/primitives/issues/200)) ([dca313e](https://github.com/netlify/primitives/commit/dca313ec82980231724a2d801bcc739df1d27924)) - - -### Bug Fixes - -* **deps:** update dependency @whatwg-node/server to ^0.10.0 ([#214](https://github.com/netlify/primitives/issues/214)) ([b3ea166](https://github.com/netlify/primitives/commit/b3ea1661c63b223f8c0722910ae76ee936f754b4)) -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - -## [2.2.0](https://github.com/netlify/primitives/compare/dev-utils-v2.1.1...dev-utils-v2.2.0) (2025-05-23) - - -### Features - -* add support for environment variables ([#197](https://github.com/netlify/primitives/issues/197)) ([03878db](https://github.com/netlify/primitives/commit/03878dbfff4e7e379b9d3e4fb6d9d783e66cc2af)) - - -### Bug Fixes - -* pass route to function invocation ([#202](https://github.com/netlify/primitives/issues/202)) ([7bb9396](https://github.com/netlify/primitives/commit/7bb939649dede2fae6642f724e3491dc598621b6)) - -## [2.1.1](https://github.com/netlify/primitives/compare/dev-utils-v2.1.0...dev-utils-v2.1.1) (2025-05-09) - - -### Bug Fixes - -* **deps:** update netlify packages ([#153](https://github.com/netlify/primitives/issues/153)) ([1fd1824](https://github.com/netlify/primitives/commit/1fd1824cd9f398921f006b0ccd538f371935d1fa)) -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - -## [2.1.0](https://github.com/netlify/primitives/compare/dev-utils-v2.0.0...dev-utils-v2.1.0) (2025-05-06) - - -### Features - -* add Vite plugin ([#165](https://github.com/netlify/primitives/issues/165)) ([2ec775e](https://github.com/netlify/primitives/commit/2ec775e29be11138f77f8db73e2a3bcfdbe88934)) - -## [2.0.0](https://github.com/netlify/primitives/compare/dev-utils-v1.1.0...dev-utils-v2.0.0) (2025-05-02) - - -### ⚠ BREAKING CHANGES - -* The `BlobsServer` class now only exports the `start()` and `stop()` methods. This class is not part of the Netlify Blobs client, and it's mostly used internally by Netlify tooling and by some users for integration tests — if you're just using the methods listed in https://docs.netlify.com/blobs/overview/#api-reference, this change does not apply to you and you can safely upgrade. - -### Features - -* add `runtime` and `runtime-utils` packages ([#150](https://github.com/netlify/primitives/issues/150)) ([be2cbf0](https://github.com/netlify/primitives/commit/be2cbf05cd3b73a795b54f94b7f51dacbcf6ef34)) -* add `start` entry point ([#154](https://github.com/netlify/primitives/issues/154)) ([b23c607](https://github.com/netlify/primitives/commit/b23c607ed3aa5e76279efa773b8c6c4d0dee972c)) - -## [1.1.0](https://github.com/netlify/primitives/compare/dev-utils-v1.0.0...dev-utils-v1.1.0) (2025-04-16) - - -### Features - -* move primitives into monorepo ([#101](https://github.com/netlify/primitives/issues/101)) ([93b72b1](https://github.com/netlify/primitives/commit/93b72b1364022e45cbd87814dc6aa235f1e1c83e)) diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json deleted file mode 100644 index d1e4ee0..0000000 --- a/packages/dev-utils/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "@netlify/dev-utils", - "version": "4.4.6", - "description": "TypeScript utilities for the local emulation of the Netlify environment", - "type": "module", - "engines": { - "node": "^18.14.0 || >=20" - }, - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json" - }, - "files": [ - "dist/**/*", - "src/templates/*.html" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/dev-utils" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@netlify/types": "2.8.0", - "@types/node": "^18.19.110", - "@types/parse-gitignore": "^1.0.2", - "execa": "^8.0.1", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "@whatwg-node/server": "^0.10.0", - "ansis": "^4.1.0", - "atomically": "^2.0.3", - "chokidar": "^4.0.1", - "decache": "^4.6.2", - "dettle": "^1.0.5", - "dot-prop": "9.0.0", - "empathic": "^2.0.0", - "env-paths": "^3.0.0", - "image-size": "^2.0.2", - "js-image-generator": "^1.0.4", - "parse-gitignore": "^2.0.0", - "semver": "^7.7.2", - "tmp-promise": "^3.0.3" - } -} diff --git a/packages/dev-utils/src/lib/api-token.ts b/packages/dev-utils/src/lib/api-token.ts deleted file mode 100644 index d7cd5fe..0000000 --- a/packages/dev-utils/src/lib/api-token.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getGlobalConfigStore } from './global-config.js' - -export const getAPIToken = async () => { - const globalConfig = await getGlobalConfigStore() - const userId = globalConfig.get('userId') - const token = globalConfig.get(`users.${userId}.auth.token`) as string | undefined - - return token -} diff --git a/packages/dev-utils/src/lib/base64.test.ts b/packages/dev-utils/src/lib/base64.test.ts deleted file mode 100644 index 2980354..0000000 --- a/packages/dev-utils/src/lib/base64.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import { shouldBase64Encode } from './base64.js' - -describe('`shouldBase64Encode` helper', () => { - test('Returns `false` for `text/` content types', async () => { - expect(shouldBase64Encode('text/html')).toBeFalsy() - }) -}) diff --git a/packages/dev-utils/src/lib/base64.ts b/packages/dev-utils/src/lib/base64.ts deleted file mode 100644 index fd3115c..0000000 --- a/packages/dev-utils/src/lib/base64.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Should be equivalent to https://github.com/netlify/proxy/blob/main/pkg/functions/request.go#L105. -const exceptionsList = new Set([ - 'application/csp-report', - 'application/graphql', - 'application/json', - 'application/javascript', - 'application/x-www-form-urlencoded', - 'application/x-ndjson', - 'application/xml', -]) - -export const shouldBase64Encode = (contentType: string) => { - if (!contentType) { - return true - } - - const [contentTypeSegment] = contentType.split(';') - contentType = contentTypeSegment - contentType = contentType.toLowerCase() - - if (contentType.startsWith('text/')) { - return false - } - - if (contentType.endsWith('+json') || contentType.endsWith('+xml')) { - return false - } - - if (exceptionsList.has(contentType)) { - return false - } - - return true -} diff --git a/packages/dev-utils/src/lib/errors.ts b/packages/dev-utils/src/lib/errors.ts deleted file mode 100644 index 93693e1..0000000 --- a/packages/dev-utils/src/lib/errors.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { readFile } from 'node:fs/promises' -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' - -const templatesPath = dirname(fileURLToPath(import.meta.url)) -const functionErrorTemplatePath = resolve(templatesPath, '../src/templates/function-error.html') - -let errorTemplateFile: string - -export const renderFunctionErrorPage = async (errString: string, functionType: string) => { - const errorDetailsRegex = //g - const functionTypeRegex = //g - - try { - errorTemplateFile = errorTemplateFile || (await readFile(functionErrorTemplatePath, 'utf-8')) - - return errorTemplateFile.replace(errorDetailsRegex, errString).replace(functionTypeRegex, functionType) - } catch { - return errString - } -} diff --git a/packages/dev-utils/src/lib/event.ts b/packages/dev-utils/src/lib/event.ts deleted file mode 100644 index c334445..0000000 --- a/packages/dev-utils/src/lib/event.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface DevEvent { - name: string -} - -export type DevEventHandler = (event: DevEvent) => void diff --git a/packages/dev-utils/src/lib/file-watcher/index.test.ts b/packages/dev-utils/src/lib/file-watcher/index.test.ts deleted file mode 100644 index 15947ae..0000000 --- a/packages/dev-utils/src/lib/file-watcher/index.test.ts +++ /dev/null @@ -1,374 +0,0 @@ -import { promises as fs } from 'node:fs' -import { tmpdir } from 'node:os' -import path from 'node:path' - -import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' - -import { FileWatcher } from './index.js' - -// Helper to wait for file system events to propagate through chokidar. -// macOS FSEvents can be slow, so we use a generous delay. -const waitForEvents = (ms = 500) => new Promise((resolve) => setTimeout(resolve, ms)) - -describe('FileWatcher', () => { - let tempDir: string - let watcher: FileWatcher - - beforeEach(async () => { - tempDir = await fs.mkdtemp(path.join(tmpdir(), 'file-watcher-test-')) - watcher = new FileWatcher() - }) - - afterEach(async () => { - await watcher.close() - await fs.rm(tempDir, { recursive: true, force: true }) - }) - - test('routes change events to the correct subscription', async () => { - const dirA = path.join(tempDir, 'a') - const dirB = path.join(tempDir, 'b') - await fs.mkdir(dirA) - await fs.mkdir(dirB) - - const fileA = path.join(dirA, 'test.txt') - const fileB = path.join(dirB, 'test.txt') - await fs.writeFile(fileA, 'initial') - await fs.writeFile(fileB, 'initial') - - const changesA = vi.fn() - const changesB = vi.fn() - - watcher.subscribe({ paths: dirA, onChange: changesA }) - watcher.subscribe({ paths: dirB, onChange: changesB }) - - await waitForEvents() - changesA.mockClear() - changesB.mockClear() - - await fs.writeFile(fileA, 'changed') - await waitForEvents() - - expect(changesA).toHaveBeenCalled() - const allPathsA = changesA.mock.calls.flatMap((call: [string[]]) => call[0]) - expect(allPathsA).toContain(fileA) - expect(changesB).not.toHaveBeenCalled() - }) - - test('routes add events correctly', async () => { - const dir = path.join(tempDir, 'add-test') - await fs.mkdir(dir) - - const onAdd = vi.fn() - - watcher.subscribe({ paths: dir, onAdd }) - - await waitForEvents() - onAdd.mockClear() - - const newFile = path.join(dir, 'new.txt') - await fs.writeFile(newFile, 'hello') - await waitForEvents() - - expect(onAdd).toHaveBeenCalled() - const allPaths = onAdd.mock.calls.flatMap((call: [string[]]) => call[0]) - expect(allPaths).toContain(newFile) - }) - - test('routes unlink events correctly', async () => { - const dir = path.join(tempDir, 'unlink-test') - await fs.mkdir(dir) - const file = path.join(dir, 'doomed.txt') - await fs.writeFile(file, 'goodbye') - - const onUnlink = vi.fn() - - watcher.subscribe({ paths: dir, onUnlink }) - - await waitForEvents() - onUnlink.mockClear() - - await fs.unlink(file) - await waitForEvents() - - expect(onUnlink).toHaveBeenCalled() - const allPaths = onUnlink.mock.calls.flatMap((call: [string[]]) => call[0]) - expect(allPaths).toContain(file) - }) - - test('supports dynamic path addition via handle.add()', async () => { - const dir1 = path.join(tempDir, 'dir1') - const dir2 = path.join(tempDir, 'dir2') - await fs.mkdir(dir1) - await fs.mkdir(dir2) - await fs.writeFile(path.join(dir2, 'existing.txt'), 'initial') - - const onChange = vi.fn() - - const handle = watcher.subscribe({ paths: dir1, onChange }) - - await waitForEvents() - onChange.mockClear() - - // Changes in dir2 should not trigger yet - await fs.writeFile(path.join(dir2, 'existing.txt'), 'changed-before') - await waitForEvents() - expect(onChange).not.toHaveBeenCalled() - - // Add dir2 dynamically - handle.add(dir2) - await waitForEvents() - onChange.mockClear() - - // Now changes in dir2 should trigger - await fs.writeFile(path.join(dir2, 'existing.txt'), 'changed-after') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - }) - - test('supports dynamic path removal via handle.unwatch()', async () => { - const dir = path.join(tempDir, 'unwatch-test') - await fs.mkdir(dir) - const file = path.join(dir, 'test.txt') - await fs.writeFile(file, 'initial') - - const onChange = vi.fn() - - const handle = watcher.subscribe({ paths: dir, onChange }) - - await waitForEvents() - - await fs.writeFile(file, 'change1') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - - // Unwatch the directory - handle.unwatch(dir) - onChange.mockClear() - await waitForEvents() - - // Changes should no longer trigger - await fs.writeFile(file, 'change2') - await waitForEvents() - expect(onChange).not.toHaveBeenCalled() - }) - - test('enforces depth constraint', async () => { - const dir = path.join(tempDir, 'depth-test') - const subDir = path.join(dir, 'sub') - await fs.mkdir(subDir, { recursive: true }) - - // Pre-create the file at depth 1 so we can test onChange - const shallowFile = path.join(dir, 'direct.txt') - await fs.writeFile(shallowFile, 'initial') - await fs.writeFile(path.join(subDir, 'shallow.txt'), 'initial') - - const onChange = vi.fn() - - // depth: 1 means only files directly in `dir` (relative path has 1 segment) - watcher.subscribe({ paths: dir, onChange, depth: 1 }) - - await waitForEvents() - onChange.mockClear() - - // Modify a file at depth 1 (directly in dir) — should trigger - await fs.writeFile(shallowFile, 'changed') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - const allPaths = onChange.mock.calls.flatMap((call: [string[]]) => call[0]) - expect(allPaths).toContain(shallowFile) - - onChange.mockClear() - - // Modify a file at depth 2 (in subdir) — should be filtered out - await fs.writeFile(path.join(subDir, 'shallow.txt'), 'changed') - await waitForEvents() - expect(onChange).not.toHaveBeenCalled() - }) - - test('unsubscribe() stops events for that subscription', async () => { - const dir = path.join(tempDir, 'unsub-test') - await fs.mkdir(dir) - const file = path.join(dir, 'test.txt') - await fs.writeFile(file, 'initial') - - const onChange = vi.fn() - - const handle = watcher.subscribe({ paths: dir, onChange }) - - await waitForEvents() - - await fs.writeFile(file, 'change1') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - - handle.unsubscribe() - onChange.mockClear() - - await fs.writeFile(file, 'change2') - await waitForEvents() - expect(onChange).not.toHaveBeenCalled() - }) - - test('close() shuts down the watcher', async () => { - const dir = path.join(tempDir, 'close-test') - await fs.mkdir(dir) - const file = path.join(dir, 'test.txt') - await fs.writeFile(file, 'initial') - - const onChange = vi.fn() - - watcher.subscribe({ paths: dir, onChange }) - - await waitForEvents() - onChange.mockClear() - - await watcher.close() - - await fs.writeFile(file, 'changed') - await waitForEvents() - expect(onChange).not.toHaveBeenCalled() - }) - - test('shared paths only unwatched when no subscription needs them', async () => { - const dir = path.join(tempDir, 'shared-test') - await fs.mkdir(dir) - const file = path.join(dir, 'test.txt') - await fs.writeFile(file, 'initial') - - const onChange1 = vi.fn() - const onChange2 = vi.fn() - - const handle1 = watcher.subscribe({ paths: dir, onChange: onChange1 }) - watcher.subscribe({ paths: dir, onChange: onChange2 }) - - await waitForEvents() - onChange1.mockClear() - onChange2.mockClear() - - // Unsubscribe the first — the second should still get events - handle1.unsubscribe() - - await fs.writeFile(file, 'changed') - await waitForEvents() - - expect(onChange1).not.toHaveBeenCalled() - expect(onChange2).toHaveBeenCalled() - }) - - test('subscribe with same id and same paths is a no-op', async () => { - const dir = path.join(tempDir, 'id-noop-test') - await fs.mkdir(dir) - const file = path.join(dir, 'test.txt') - await fs.writeFile(file, 'initial') - - const onChange = vi.fn() - - const handle1 = watcher.subscribe({ id: 'my-watcher', paths: dir, onChange }) - - await waitForEvents() - onChange.mockClear() - - // Subscribe again with the same id and same paths - const handle2 = watcher.subscribe({ id: 'my-watcher', paths: dir, onChange }) - - // Should return the exact same handle - expect(handle2).toBe(handle1) - - // Events should still work - await fs.writeFile(file, 'changed') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - }) - - test('subscribe with same id but different paths swaps the watched directory', async () => { - const dir1 = path.join(tempDir, 'id-swap-dir1') - const dir2 = path.join(tempDir, 'id-swap-dir2') - await fs.mkdir(dir1) - await fs.mkdir(dir2) - const file1 = path.join(dir1, 'test.txt') - const file2 = path.join(dir2, 'test.txt') - await fs.writeFile(file1, 'initial') - await fs.writeFile(file2, 'initial') - - const onChange = vi.fn() - - watcher.subscribe({ id: 'config-path', paths: dir1, onChange }) - - await waitForEvents() - onChange.mockClear() - - // Verify dir1 is being watched - await fs.writeFile(file1, 'changed') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - onChange.mockClear() - - // Now subscribe with the same id but a different path - watcher.subscribe({ id: 'config-path', paths: dir2, onChange }) - - await waitForEvents() - onChange.mockClear() - - // dir1 should no longer trigger events - await fs.writeFile(file1, 'changed again') - await waitForEvents() - expect(onChange).not.toHaveBeenCalled() - - // dir2 should trigger events - await fs.writeFile(file2, 'changed') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - }) - - test('named and unnamed subscriptions do not interfere', async () => { - const dir = path.join(tempDir, 'named-unnamed-test') - await fs.mkdir(dir) - const file = path.join(dir, 'test.txt') - await fs.writeFile(file, 'initial') - - const onChangeNamed = vi.fn() - const onChangeUnnamed = vi.fn() - - watcher.subscribe({ id: 'named', paths: dir, onChange: onChangeNamed }) - watcher.subscribe({ paths: dir, onChange: onChangeUnnamed }) - - await waitForEvents() - onChangeNamed.mockClear() - onChangeUnnamed.mockClear() - - await fs.writeFile(file, 'changed') - await waitForEvents() - - expect(onChangeNamed).toHaveBeenCalled() - expect(onChangeUnnamed).toHaveBeenCalled() - }) - - test('multiple event types work independently', async () => { - const dir = path.join(tempDir, 'multi-event-test') - await fs.mkdir(dir) - - const onAdd = vi.fn() - const onChange = vi.fn() - const onUnlink = vi.fn() - - watcher.subscribe({ paths: dir, onAdd, onChange, onUnlink }) - - await waitForEvents() - onAdd.mockClear() - onChange.mockClear() - onUnlink.mockClear() - - const file = path.join(dir, 'lifecycle.txt') - await fs.writeFile(file, 'created') - await waitForEvents() - expect(onAdd).toHaveBeenCalled() - - await fs.writeFile(file, 'modified') - await waitForEvents() - expect(onChange).toHaveBeenCalled() - - await fs.unlink(file) - await waitForEvents() - expect(onUnlink).toHaveBeenCalled() - }) -}) diff --git a/packages/dev-utils/src/lib/file-watcher/index.ts b/packages/dev-utils/src/lib/file-watcher/index.ts deleted file mode 100644 index 18978cc..0000000 --- a/packages/dev-utils/src/lib/file-watcher/index.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { createRequire } from 'node:module' -import path from 'node:path' - -import chokidar from 'chokidar' - -import { createDebouncedBatch, ensureArray, pathSetsEqual, type DebouncedBatch } from './util.js' - -const require = createRequire(import.meta.url) - -const DEFAULT_DEBOUNCE_MS = 100 -const BASE_IGNORES = [/\/(node_modules|\.git)\//] - -export type FileWatchEventType = 'add' | 'change' | 'unlink' -export type FileWatchCallback = (paths: string[]) => void - -export interface FileWatchSubscriptionOptions { - /** - * An optional identifier for this subscription. When provided, calling - * `subscribe` again with the same `id` is idempotent: if the paths haven't - * changed, the existing handle is returned as-is. If the paths have changed, - * the old subscription is automatically replaced. - */ - id?: string - - /** - * One or more file or directory paths to watch. - */ - paths: string | string[] - - /** - * Called when a watched file's contents change. - */ - onChange?: FileWatchCallback - - /** - * Called when a new file is created inside a watched directory. - */ - onAdd?: FileWatchCallback - - /** - * Called when a watched file is deleted. - */ - onUnlink?: FileWatchCallback - - /** - * Maximum directory depth to watch. For example, `depth: 1` only watches - * files directly inside the watched directory, not in subdirectories. - */ - depth?: number - - /** - * How long to wait (in milliseconds) before delivering a batch of events. - * Defaults to 100ms. - */ - debounceMs?: number - - /** - * Whether to clear the Node.js `require` cache for changed files before - * delivering the event. Useful for hot-reloading CommonJS modules. - */ - decache?: boolean -} - -export interface FileWatchSubscriptionHandle { - add(paths: string | string[]): void - unwatch(paths: string | string[]): void - unsubscribe(): void -} - -interface Subscription { - id: string - watchedPaths: Set - depth?: number - decache: boolean - batchers: Record -} - -export class FileWatcher { - /** - * The shared chokidar instance that backs all subscriptions. - */ - #watcher: ReturnType - - /** - * Auto-incrementing counter for generating unique internal subscription IDs. - */ - #nextSubscriptionId = 0 - - /** - * Maps subscription IDs to their internal state (watched paths, callbacks, - * debounce queues, etc.). - */ - #subscriptions = new Map() - - /** - * Maps subscription IDs to the handles returned to callers. This is used - * to return the same handle when a named subscription is called again with - * unchanged paths. - */ - #handles = new Map() - - /** - * Reference count for each watched path. A path is only added to chokidar - * when its count goes from 0 to 1, and only removed when it drops back to - * 0. This lets multiple subscriptions share the same underlying watch. - */ - #pathRefCounts = new Map() - - constructor(options?: { ignored?: (string | RegExp)[] }) { - const ignored = [...BASE_IGNORES, ...(options?.ignored ?? [])] - - this.#watcher = chokidar.watch([], { - ignored, - ignoreInitial: true, - }) - - this.#watcher.on('add', (filePath) => { - this.#dispatch('add', filePath) - }) - this.#watcher.on('change', (filePath) => { - this.#dispatch('change', filePath) - }) - this.#watcher.on('unlink', (filePath) => { - this.#dispatch('unlink', filePath) - }) - } - - subscribe(options: FileWatchSubscriptionOptions): FileWatchSubscriptionHandle { - const paths = ensureArray(options.paths) - - // If an `id` was provided and a subscription with that id already exists, - // check whether the paths have changed. If not, return the existing handle. - // If they have, tear down the old subscription and fall through to create - // a new one with the same id. - if (options.id !== undefined) { - const existingSubscription = this.#subscriptions.get(options.id) - const existingHandle = this.#handles.get(options.id) - - if (existingSubscription && existingHandle) { - if (pathSetsEqual(existingSubscription.watchedPaths, paths)) { - return existingHandle - } - - this.#unsubscribe(options.id) - } - } - - const id = options.id ?? String(this.#nextSubscriptionId++) - const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS - - const subscription: Subscription = { - id, - watchedPaths: new Set(paths), - depth: options.depth, - decache: options.decache === true, - batchers: { - add: createDebouncedBatch(options.onAdd, debounceMs), - change: createDebouncedBatch(options.onChange, debounceMs), - unlink: createDebouncedBatch(options.onUnlink, debounceMs), - }, - } - - this.#subscriptions.set(id, subscription) - - // Add paths to chokidar - for (const p of paths) { - this.#addPathRef(p) - } - - const handle: FileWatchSubscriptionHandle = { - add: (newPaths) => { - const normalized = ensureArray(newPaths) - - for (const p of normalized) { - if (!subscription.watchedPaths.has(p)) { - subscription.watchedPaths.add(p) - this.#addPathRef(p) - } - } - }, - unwatch: (removePaths) => { - const normalized = ensureArray(removePaths) - - for (const p of normalized) { - if (subscription.watchedPaths.has(p)) { - subscription.watchedPaths.delete(p) - this.#removePathRef(p) - } - } - }, - unsubscribe: () => { - this.#unsubscribe(id) - }, - } - - this.#handles.set(id, handle) - - return handle - } - - async close(): Promise { - this.#subscriptions.clear() - this.#handles.clear() - this.#pathRefCounts.clear() - await this.#watcher.close() - } - - #dispatch(eventType: FileWatchEventType, filePath: string) { - for (const subscription of this.#subscriptions.values()) { - if (!this.#isPathRelevant(filePath, subscription)) { - continue - } - - if (subscription.decache) { - try { - const decacheFn = require('decache') as (path: string) => void - decacheFn(filePath) - } catch { - // decache may fail for non-CJS modules, ignore - } - } - - subscription.batchers[eventType].push(filePath) - } - } - - #isPathRelevant(filePath: string, subscription: Subscription): boolean { - for (const watchedPath of subscription.watchedPaths) { - // Exact match (file watching) - if (filePath === watchedPath) { - return true - } - - // Directory containment - const relative = path.relative(watchedPath, filePath) - - // If the relative path starts with "..", the file is not inside this directory - if (relative.startsWith('..') || path.isAbsolute(relative)) { - continue - } - - // Check depth constraint - if (subscription.depth !== undefined) { - const depth = relative.split(path.sep).length - if (depth > subscription.depth) { - continue - } - } - - return true - } - - return false - } - - #addPathRef(watchedPath: string) { - const count = this.#pathRefCounts.get(watchedPath) ?? 0 - - if (count === 0) { - this.#watcher.add(watchedPath) - } - - this.#pathRefCounts.set(watchedPath, count + 1) - } - - #removePathRef(watchedPath: string) { - const count = this.#pathRefCounts.get(watchedPath) ?? 0 - - if (count <= 1) { - this.#watcher.unwatch(watchedPath) - this.#pathRefCounts.delete(watchedPath) - } else { - this.#pathRefCounts.set(watchedPath, count - 1) - } - } - - #unsubscribe(id: string) { - const subscription = this.#subscriptions.get(id) - - if (!subscription) { - return - } - - for (const p of subscription.watchedPaths) { - this.#removePathRef(p) - } - - this.#subscriptions.delete(id) - this.#handles.delete(id) - } -} diff --git a/packages/dev-utils/src/lib/file-watcher/util.ts b/packages/dev-utils/src/lib/file-watcher/util.ts deleted file mode 100644 index 8f98ad1..0000000 --- a/packages/dev-utils/src/lib/file-watcher/util.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { debounce } from 'dettle' - -import type { FileWatchCallback } from './index.js' - -export interface DebouncedBatch { - push(path: string): void -} - -export function ensureArray(input: string | string[]): string[] { - return Array.isArray(input) ? input : [input] -} - -export function createDebouncedBatch(callback: FileWatchCallback | undefined, debounceMs: number): DebouncedBatch { - const queue: string[] = [] - - const flush = debounce( - () => { - if (queue.length === 0) { - return - } - - const batch = [...queue] - queue.length = 0 - - callback?.(batch) - }, - debounceMs, - { leading: true }, - ) - - return { - push(filePath: string) { - queue.push(filePath) - flush() - }, - } -} - -export function pathSetsEqual(existing: Set, incoming: string[]): boolean { - if (existing.size !== incoming.length) { - return false - } - - for (const p of incoming) { - if (!existing.has(p)) { - return false - } - } - - return true -} diff --git a/packages/dev-utils/src/lib/geo-location.test.ts b/packages/dev-utils/src/lib/geo-location.test.ts deleted file mode 100644 index e768c8b..0000000 --- a/packages/dev-utils/src/lib/geo-location.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest' -import type { MockedFunction } from 'vitest' - -import { getGeoLocation, mockLocation } from './geo-location.js' -import { MockFetch } from '../test/fetch.js' - -describe('geolocation', () => { - let mockState: { - get: MockedFunction<(key: string) => unknown> - set: MockedFunction<(key: string, value: unknown) => void> - } - let mockFetch: MockFetch - - beforeEach(() => { - vi.clearAllMocks() - mockState = { - get: vi.fn(), - set: vi.fn(), - } - mockFetch = new MockFetch() - }) - - afterEach(() => { - mockFetch.restore() - }) - - describe('getGeoLocation', () => { - test('returns mock location when enabled is false', async () => { - const result = await getGeoLocation({ - enabled: false, - state: mockState, - }) - - expect(result).toEqual(mockLocation) - expect(mockState.get).not.toHaveBeenCalled() - expect(mockState.set).not.toHaveBeenCalled() - expect(mockFetch.fulfilled).toBe(true) - }) - - test('returns cached data when cache is enabled and data is fresh', async () => { - const cachedData = { - city: 'Cached City', - country: { code: 'CA', name: 'Canada' }, - subdivision: { code: 'ON', name: 'Ontario' }, - longitude: -79.3832, - latitude: 43.6532, - timezone: 'America/Toronto', - } - - mockState.get.mockReturnValue({ - data: cachedData, - timestamp: Date.now() - 1000 * 60 * 60, // 1 hour ago - }) - - const result = await getGeoLocation({ - enabled: true, - cache: true, - state: mockState, - }) - - expect(result).toEqual(cachedData) - expect(mockState.get).toHaveBeenCalledWith('geolocation') - expect(mockFetch.fulfilled).toBe(true) - }) - - test('fetches new data when cache is enabled but data is stale', async () => { - const staleData = { - city: 'Stale City', - country: { code: 'CA', name: 'Canada' }, - subdivision: { code: 'ON', name: 'Ontario' }, - longitude: -79.3832, - latitude: 43.6532, - timezone: 'America/Toronto', - } - - const freshData = { - city: 'Fresh City', - country: { code: 'US', name: 'United States' }, - subdivision: { code: 'NY', name: 'New York' }, - longitude: -74.006, - latitude: 40.7128, - timezone: 'America/New_York', - } - - mockState.get.mockReturnValue({ - data: staleData, - timestamp: Date.now() - 1000 * 60 * 60 * 25, // 25 hours ago (stale) - }) - - mockFetch - .get({ - url: 'https://netlifind.netlify.app', - response: new Response(JSON.stringify({ geo: freshData }), { - headers: { 'Content-Type': 'application/json' }, - }), - }) - .inject() - - const result = await getGeoLocation({ - enabled: true, - cache: true, - state: mockState, - }) - - expect(result).toEqual(freshData) - expect(mockState.get).toHaveBeenCalledWith('geolocation') - expect(mockState.set).toHaveBeenCalledWith('geolocation', { - data: freshData, - timestamp: expect.any(Number), - }) - expect(mockFetch.fulfilled).toBe(true) - }) - - test('always fetches new data when cache is disabled', async () => { - const cachedData = { - city: 'Cached City', - country: { code: 'CA', name: 'Canada' }, - subdivision: { code: 'ON', name: 'Ontario' }, - longitude: -79.3832, - latitude: 43.6532, - timezone: 'America/Toronto', - } - - const freshData = { - city: 'Fresh City', - country: { code: 'US', name: 'United States' }, - subdivision: { code: 'NY', name: 'New York' }, - longitude: -74.006, - latitude: 40.7128, - timezone: 'America/New_York', - } - - mockState.get.mockReturnValue({ - data: cachedData, - timestamp: Date.now() - 1000 * 60 * 60, // 1 hour ago (fresh) - }) - - mockFetch - .get({ - url: 'https://netlifind.netlify.app', - response: new Response(JSON.stringify({ geo: freshData }), { - headers: { 'Content-Type': 'application/json' }, - }), - }) - .inject() - - const result = await getGeoLocation({ - enabled: true, - cache: false, - state: mockState, - }) - - expect(result).toEqual(freshData) - expect(mockState.set).toHaveBeenCalledWith('geolocation', { - data: freshData, - timestamp: expect.any(Number), - }) - expect(mockFetch.fulfilled).toBe(true) - }) - - test('returns mock location when API request fails', async () => { - mockState.get.mockReturnValue(undefined) - - mockFetch - .get({ - url: 'https://netlifind.netlify.app', - response: new Error('Network error'), - }) - .inject() - - const result = await getGeoLocation({ - enabled: true, - cache: false, - state: mockState, - }) - - expect(result).toEqual(mockLocation) - expect(mockFetch.fulfilled).toBe(true) - }) - }) -}) diff --git a/packages/dev-utils/src/lib/geo-location.ts b/packages/dev-utils/src/lib/geo-location.ts deleted file mode 100644 index dd6f503..0000000 --- a/packages/dev-utils/src/lib/geo-location.ts +++ /dev/null @@ -1,85 +0,0 @@ -import type { Context } from '@netlify/types' - -import type { LocalState } from './local-state.js' - -export type Geolocation = Context['geo'] - -export const mockLocation: Geolocation = { - city: 'San Francisco', - country: { code: 'US', name: 'United States' }, - subdivision: { code: 'CA', name: 'California' }, - longitude: 0, - latitude: 0, - timezone: 'UTC', -} - -const API_URL = 'https://netlifind.netlify.app' -const STATE_GEO_PROPERTY = 'geolocation' -// 24 hours -const CACHE_TTL = 8.64e7 - -// 10 seconds -const REQUEST_TIMEOUT = 1e4 - -/** - * Returns geolocation data from a remote API, the local cache, or a mock location, depending on the - * specified options. - */ -export const getGeoLocation = async ({ - enabled = true, - cache = true, - state, -}: { - enabled?: boolean - cache?: boolean - state: LocalState -}): Promise => { - // Early return for disabled mode - if (!enabled) { - return mockLocation - } - - const cacheObject = state.get(STATE_GEO_PROPERTY) as { data: Geolocation; timestamp: number } | undefined - - // If we have cached geolocation data and caching is enabled, let's try to use it. - if (cacheObject !== undefined && cache) { - const age = Date.now() - cacheObject.timestamp - - // Let's use the cached data if it's not older than the TTL. - if (age < CACHE_TTL) { - return cacheObject.data - } - } - - // Trying to retrieve geolocation data from the API and caching it locally. - try { - const data = await getGeoLocationFromAPI() - - // Always cache the data for future use - const newCacheObject = { - data, - timestamp: Date.now(), - } - - state.set(STATE_GEO_PROPERTY, newCacheObject) - - return data - } catch { - // We couldn't get geolocation data from the API, so let's return the - // mock location. - return mockLocation - } -} - -/** - * Returns geolocation data from a remote API. - */ -const getGeoLocationFromAPI = async (): Promise => { - const res = await fetch(API_URL, { - method: 'GET', - signal: AbortSignal.timeout(REQUEST_TIMEOUT), - }) - const { geo } = (await res.json()) as { geo: Geolocation } - - return geo -} diff --git a/packages/dev-utils/src/lib/gitignore.ts b/packages/dev-utils/src/lib/gitignore.ts deleted file mode 100644 index f8b9142..0000000 --- a/packages/dev-utils/src/lib/gitignore.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { readFile, stat, writeFile } from 'fs/promises' -import path from 'path' - -import parseIgnore from 'parse-gitignore' - -import type { Logger } from './logger.js' - -const hasGitIgnore = async function (dir: string) { - const gitIgnorePath = path.join(dir, '.gitignore') - - try { - const ignoreStats = await stat(gitIgnorePath) - - return ignoreStats.isFile() - } catch { - return false - } -} - -export const ensureNetlifyIgnore = async (dir: string, logger?: Logger) => { - const gitIgnorePath = path.join(dir, '.gitignore') - const ignoreContent = '# Local Netlify folder\n.netlify\n' - - /* No .gitignore file. Create one and ignore .netlify folder */ - if (!(await hasGitIgnore(dir))) { - await writeFile(gitIgnorePath, ignoreContent, 'utf8') - return false - } - - let gitIgnoreContents - let ignorePatterns - try { - gitIgnoreContents = await readFile(gitIgnorePath, 'utf8') - ignorePatterns = parseIgnore.parse(gitIgnoreContents) - } catch { - // ignore - } - /* Not ignoring .netlify folder. Add to .gitignore */ - if (!ignorePatterns?.patterns.some((pattern) => /(^|\/|\\)\.netlify($|\/|\\)/.test(pattern))) { - logger?.log() - logger?.log('Adding local .netlify folder to .gitignore file...') - const newContents = `${gitIgnoreContents}\n${ignoreContent}` - await writeFile(gitIgnorePath, newContents, 'utf8') - } -} diff --git a/packages/dev-utils/src/lib/global-config.ts b/packages/dev-utils/src/lib/global-config.ts deleted file mode 100644 index ef4464f..0000000 --- a/packages/dev-utils/src/lib/global-config.ts +++ /dev/null @@ -1,101 +0,0 @@ -import crypto from 'node:crypto' -import fs from 'node:fs/promises' -import fss from 'node:fs' -import path from 'node:path' -import * as dot from 'dot-prop' - -import { writeFileSync as writeFileAtomicSync } from 'atomically' - -import { getLegacyPathInHome, getPathInHome } from './paths.js' - -type ConfigStoreOptions> = { - defaults?: T | undefined -} - -export class GlobalConfigStore = Record> { - #storagePath: string - - public constructor(options: ConfigStoreOptions = {}) { - this.#storagePath = getPathInHome(['config.json']) - - if (options.defaults) { - const config = this.getConfig() - this.writeConfig({ ...options.defaults, ...config }) - } - } - - public get all(): T { - return this.getConfig() - } - - public set(key: string, value: unknown): void { - const config = this.getConfig() - const updatedConfig = dot.setProperty(config, key, value) - this.writeConfig(updatedConfig) - } - - public get(key: string): T[typeof key] { - return dot.getProperty(this.getConfig(), key) - } - - private getConfig(): T { - let raw: string - try { - raw = fss.readFileSync(this.#storagePath, 'utf8') - } catch (err) { - if (err instanceof Error && 'code' in err) { - if (err.code === 'ENOENT') { - // File or parent directory does not exist - return {} as T - } - } - throw err - } - - try { - return JSON.parse(raw) as T - } catch { - writeFileAtomicSync(this.#storagePath, '', { mode: 0o0600 }) - return {} as T - } - } - - private writeConfig(value: T) { - fss.mkdirSync(path.dirname(this.#storagePath), { mode: 0o0700, recursive: true }) - writeFileAtomicSync(this.#storagePath, JSON.stringify(value, undefined, '\t'), { mode: 0o0600 }) - } -} - -const globalConfigDefaults = { - /* disable stats from being sent to Netlify */ - telemetryDisabled: false, - /* cliId */ - cliId: crypto.randomUUID(), -} - -// Memoise config result so that we only load it once -let configStore: GlobalConfigStore | undefined - -export const getGlobalConfigStore = async (): Promise => { - if (!configStore) { - // Legacy config file in home ~/.netlify/config.json - const legacyPath = getLegacyPathInHome(['config.json']) - // Read legacy config if exists - let legacyConfig: Record | undefined - try { - legacyConfig = JSON.parse(await fs.readFile(legacyPath, 'utf8')) - } catch { - // ignore error - } - // Use legacy config as default values - const defaults = { ...globalConfigDefaults, ...legacyConfig } - // The id param is only used when not passing `configPath` but the type def requires it - configStore = new GlobalConfigStore({ defaults }) - } - - return configStore -} - -export const resetConfigCache = () => { - configStore = undefined -} diff --git a/packages/dev-utils/src/lib/handler.ts b/packages/dev-utils/src/lib/handler.ts deleted file mode 100644 index 2f201ab..0000000 --- a/packages/dev-utils/src/lib/handler.ts +++ /dev/null @@ -1 +0,0 @@ -export type Handler = (request: Request) => Promise diff --git a/packages/dev-utils/src/lib/headers.ts b/packages/dev-utils/src/lib/headers.ts deleted file mode 100644 index 9cf83cd..0000000 --- a/packages/dev-utils/src/lib/headers.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const headers = { - BlobsInfo: 'x-nf-blobs-info', -} - -export const toMultiValueHeaders = (headers: Headers) => { - const headersObj: Record = {} - for (const [name, value] of headers.entries()) { - if (name in headersObj) { - headersObj[name].push(value) - } else { - headersObj[name] = [value] - } - } - - return headersObj -} diff --git a/packages/dev-utils/src/lib/local-state.ts b/packages/dev-utils/src/lib/local-state.ts deleted file mode 100644 index c0e45e3..0000000 --- a/packages/dev-utils/src/lib/local-state.ts +++ /dev/null @@ -1,125 +0,0 @@ -import fs from 'fs' -import path from 'path' -import process from 'process' - -import { deleteProperty, getProperty, hasProperty, setProperty } from 'dot-prop' -import { file as findUpSync } from 'empathic/find' -import { writeFileSync as writeFileAtomicSync } from 'atomically' - -import { getPathInProject } from './paths.js' - -const STATE_PATH = getPathInProject(['state.json']) -const permissionError = "You don't have access to this file." - -/** - * Finds location of `.netlify/state.json` - */ -const findStatePath = (cwd: string): string => { - const statePath = findUpSync(STATE_PATH, { cwd }) - - if (!statePath) { - return path.join(cwd, STATE_PATH) - } - - return statePath -} - -export class LocalState { - private path: string - - constructor(cwd: string) { - this.path = findStatePath(cwd) - } - - get all() { - try { - // @ts-expect-error TS(2345) FIXME: Argument of type 'Buffer' is not assignable to par... Remove this comment to see the full error message - return JSON.parse(fs.readFileSync(this.path)) - } catch (error) { - // Don't create if it doesn't exist - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - if (error.code === 'ENOENT' || error.code === 'ENOTDIR') { - return {} - } - - // Improve the message of permission errors - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - if (error.code === 'EACCES') { - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - error.message = `${error.message}\n${permissionError}\n` - } - - // Empty the file if it encounters invalid JSON - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - if (error.name === 'SyntaxError') { - writeFileAtomicSync(this.path, '') - return {} - } - - throw error - } - } - - set all(val) { - try { - // Make sure the folder exists as it could have been deleted in the meantime - fs.mkdirSync(path.dirname(this.path), { recursive: true }) - writeFileAtomicSync(this.path, JSON.stringify(val, null, '\t')) - } catch (error) { - // Improve the message of permission errors - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - if (error.code === 'EACCES') { - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - error.message = `${error.message}\n${permissionError}\n` - } - - throw error - } - } - - get size() { - return Object.keys(this.all || {}).length - } - - // @ts-expect-error TS(7006) FIXME: Parameter 'key' implicitly has an 'any' type. - get(key) { - if (key === 'siteId' && process.env.NETLIFY_SITE_ID) { - // TODO figure out cleaner way of grabbing ENV vars - return process.env.NETLIFY_SITE_ID - } - - return getProperty(this.all, key) - } - - // @ts-expect-error TS(7019) FIXME: Rest parameter 'args' implicitly has an 'any[]' ty... Remove this comment to see the full error message - set(...args) { - const [key, val] = args - const config = this.all - - if (args.length === 1) { - Object.entries(key).forEach(([keyPart, value]) => { - setProperty(config, keyPart, value) - }) - } else { - setProperty(config, key, val) - } - - this.all = config - } - - // @ts-expect-error TS(7006) FIXME: Parameter 'key' implicitly has an 'any' type. - has(key) { - return hasProperty(this.all, key) - } - - // @ts-expect-error TS(7006) FIXME: Parameter 'key' implicitly has an 'any' type. - delete(key) { - const config = this.all - deleteProperty(config, key) - this.all = config - } - - clear() { - this.all = {} - } -} diff --git a/packages/dev-utils/src/lib/logger.ts b/packages/dev-utils/src/lib/logger.ts deleted file mode 100644 index b356e14..0000000 --- a/packages/dev-utils/src/lib/logger.ts +++ /dev/null @@ -1,17 +0,0 @@ -import ansis from 'ansis' - -type logFunction = (message?: string) => void - -export type Logger = { - error: logFunction - log: logFunction - warn: logFunction -} - -export const netlifyCommand = ansis.cyanBright - -export const netlifyCyan = ansis.rgb(40, 180, 170) - -export const netlifyBanner = netlifyCyan('⬥ Netlify') - -export const warning = (message: string): string => ansis.yellow(`⚠ Warning: ${message}`) diff --git a/packages/dev-utils/src/lib/memoize.ts b/packages/dev-utils/src/lib/memoize.ts deleted file mode 100644 index 552e546..0000000 --- a/packages/dev-utils/src/lib/memoize.ts +++ /dev/null @@ -1,45 +0,0 @@ -const DEBOUNCE_INTERVAL = 300 - -interface CacheEntry { - enqueued?: boolean - task: Promise - timestamp: number -} - -export type MemoizeCache = Record | undefined> - -interface MemoizeOptions { - cache: MemoizeCache - cacheKey: string - command: () => Promise -} - -// `memoize` will avoid running the same build command multiple times -// until the previous operation has been completed. If another call is made -// within that period, it will be: -// - discarded if it happens before `DEBOUNCE_WAIT` has elapsed; -// - enqueued if it happens after `DEBOUNCE_WAIT` has elapsed. -// This allows us to discard any duplicate filesystem events, while ensuring -// that actual updates happening during the zip operation will be executed -// after it finishes (only the last update will run). - -export const memoize = ({ cache, cacheKey, command }: MemoizeOptions) => { - if (cache[cacheKey] === undefined) { - cache[cacheKey] = { - task: command().finally(() => { - const entry = cache[cacheKey] - - cache[cacheKey] = undefined - - if (entry?.enqueued !== undefined) { - memoize({ cache, cacheKey, command }) - } - }), - timestamp: Date.now(), - } - } else if (Date.now() > cache[cacheKey].timestamp + DEBOUNCE_INTERVAL) { - cache[cacheKey].enqueued = true - } - - return cache[cacheKey].task -} diff --git a/packages/dev-utils/src/lib/paths.ts b/packages/dev-utils/src/lib/paths.ts deleted file mode 100644 index a39b636..0000000 --- a/packages/dev-utils/src/lib/paths.ts +++ /dev/null @@ -1,23 +0,0 @@ -import os from 'os' -import path from 'path' - -import envPaths from 'env-paths' - -const OSBasedPaths = envPaths('netlify', { suffix: '' }) -const NETLIFY_HOME = '.netlify' - -/** - * Deprecated method to get netlify's home config - ~/.netlify/... - * @deprecated - */ -export const getLegacyPathInHome = (paths: string[]) => path.join(os.homedir(), NETLIFY_HOME, ...paths) - -/** - * get a global path on the os base path - */ -export const getPathInHome = (paths: string[]) => path.join(OSBasedPaths.config, ...paths) - -/** - * get a path inside the project folder "NOT WORKSPACE AWARE" - */ -export const getPathInProject = (paths: string[]) => path.join(NETLIFY_HOME, ...paths) diff --git a/packages/dev-utils/src/lib/process.ts b/packages/dev-utils/src/lib/process.ts deleted file mode 100644 index ea43d72..0000000 --- a/packages/dev-utils/src/lib/process.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { platform } from 'node:os' - -import type { ExecaChildProcess } from 'execa' -import { satisfies } from 'semver' - -// 1 second -const SERVER_KILL_TIMEOUT = 1e3 - -export interface ProcessRef { - ps?: ExecaChildProcess -} - -export const killProcess = (ps?: ExecaChildProcess) => { - // If the process is no longer running, there's nothing left to do. - if (!ps || ps.exitCode !== null) { - return - } - - return new Promise((resolve, reject) => { - void ps.on('close', () => { - resolve() - }) - void ps.on('error', reject) - - // On Windows with Node 21+, there's a bug where attempting to kill a child process - // results in an EPERM error. Ignore the error in that case. - // See: https://github.com/nodejs/node/issues/51766 - // We also disable execa's `forceKillAfterTimeout` in this case - // which can cause unhandled rejection. - try { - ps.kill('SIGTERM', { - forceKillAfterTimeout: - platform() === 'win32' && satisfies(process.version, '>=21') ? false : SERVER_KILL_TIMEOUT, - }) - } catch { - // no-op - } - }) -} diff --git a/packages/dev-utils/src/lib/reactive.test.ts b/packages/dev-utils/src/lib/reactive.test.ts deleted file mode 100644 index d4360dc..0000000 --- a/packages/dev-utils/src/lib/reactive.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, expect, test, vi } from 'vitest' - -import { Reactive } from './reactive.js' - -describe('Reactive', () => { - test('get() returns the initial value', () => { - const value = new Reactive({ port: 3000 }) - - expect(value.get()).toEqual({ port: 3000 }) - }) - - test('set() updates the value', () => { - const value = new Reactive({ port: 3000 }) - - value.set({ port: 8080 }) - - expect(value.get()).toEqual({ port: 8080 }) - }) - - test('subscribe() is called when value changes', () => { - const value = new Reactive({ port: 3000 }) - const callback = vi.fn() - - value.subscribe(callback) - value.set({ port: 8080 }) - - expect(callback).toHaveBeenCalledExactlyOnceWith({ port: 8080 }) - }) - - test('multiple subscribers are all notified', () => { - const value = new Reactive('initial') - const callback1 = vi.fn() - const callback2 = vi.fn() - - value.subscribe(callback1) - value.subscribe(callback2) - value.set('updated') - - expect(callback1).toHaveBeenCalledWith('updated') - expect(callback2).toHaveBeenCalledWith('updated') - }) - - test('unsubscribe stops notifications', () => { - const value = new Reactive('initial') - const callback = vi.fn() - - const unsubscribe = value.subscribe(callback) - value.set('first') - expect(callback).toHaveBeenCalledOnce() - - unsubscribe() - value.set('second') - expect(callback).toHaveBeenCalledOnce() - }) - - test('set() notifies even if value is the same reference', () => { - const obj = { port: 3000 } - const value = new Reactive(obj) - const callback = vi.fn() - - value.subscribe(callback) - value.set(obj) - - expect(callback).toHaveBeenCalledOnce() - }) -}) diff --git a/packages/dev-utils/src/lib/reactive.ts b/packages/dev-utils/src/lib/reactive.ts deleted file mode 100644 index 9c041e7..0000000 --- a/packages/dev-utils/src/lib/reactive.ts +++ /dev/null @@ -1,45 +0,0 @@ -type ReactiveSubscriber = (newValue: T) => void - -/** - * A reactive value holder. Wraps a value and notifies subscribers when it - * changes. Consumers call {@link get} to read the current value and - * {@link subscribe} to be notified of updates. - */ -export class Reactive { - #value: T - #subscribers = new Set>() - - constructor(initialValue: T) { - this.#value = initialValue - } - - /** - * Returns the current value. - */ - get(): T { - return this.#value - } - - /** - * Replaces the current value and notifies all subscribers. - */ - set(newValue: T): void { - this.#value = newValue - - for (const callback of this.#subscribers) { - callback(newValue) - } - } - - /** - * Registers a callback that will be called whenever the value changes. - * Returns an unsubscribe function. - */ - subscribe(callback: ReactiveSubscriber): () => void { - this.#subscribers.add(callback) - - return () => { - this.#subscribers.delete(callback) - } - } -} diff --git a/packages/dev-utils/src/lib/reqres.ts b/packages/dev-utils/src/lib/reqres.ts deleted file mode 100644 index b1d9a1a..0000000 --- a/packages/dev-utils/src/lib/reqres.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'node:http' -import { Readable } from 'node:stream' - -const normalizeHeaders = (headers: IncomingHttpHeaders): HeadersInit => { - const result: [string, string][] = [] - - for (const [key, value] of Object.entries(headers)) { - if (Array.isArray(value)) { - result.push([key, value.join(',')]) - } else if (typeof value === 'string') { - result.push([key, value]) - } - } - - return result -} - -export const toWebRequest = (nodeReq: IncomingMessage, urlPath?: string) => { - const { method, headers, url = '' } = nodeReq - const ac = new AbortController() - const origin = `http://${headers.host ?? 'localhost'}` - const fullUrl = new URL(urlPath ?? url, origin) - const webStream = Readable.toWeb(nodeReq) as unknown as ReadableStream - - nodeReq.once('aborted', () => { - ac.abort() - }) - - return new Request(fullUrl.href, { - method, - headers: normalizeHeaders(headers), - body: method === 'GET' || method === 'HEAD' ? null : webStream, - // @ts-expect-error -- Not typed - duplex: 'half', - }) -} - -export const fromWebResponse = async (webRes: Response, res: ServerResponse) => { - res.statusCode = webRes.status - webRes.headers.forEach((value, name) => { - res.setHeader(name, value) - }) - - if (webRes.body) { - const reader = webRes.body.getReader() - const writer = res - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - while (true) { - const { done, value } = await reader.read() - - if (done) { - break - } - - writer.write(value) - } - } - - res.end() -} diff --git a/packages/dev-utils/src/lib/watch-debounced.ts b/packages/dev-utils/src/lib/watch-debounced.ts deleted file mode 100644 index 0e4bd1c..0000000 --- a/packages/dev-utils/src/lib/watch-debounced.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { once } from 'node:events' - -import chokidar from 'chokidar' -import decache from 'decache' -import { debounce } from 'dettle' - -const DEBOUNCE_WAIT = 100 - -interface WatchDebouncedOptions { - depth?: number - ignored?: (string | RegExp)[] - onAdd?: (paths: string[]) => void - onChange?: (paths: string[]) => void - onUnlink?: (paths: string[]) => void -} - -const noOp = () => { - // no-op -} - -/** - * Adds a file watcher to a path or set of paths and debounces the events. - */ -export const watchDebounced = async ( - target: string | string[], - { depth, ignored = [], onAdd = noOp, onChange = noOp, onUnlink = noOp }: WatchDebouncedOptions, -) => { - const baseIgnores = [/\/(node_modules|.git)\//] - const watcher = chokidar.watch(target, { - depth, - ignored: [...baseIgnores, ...ignored], - ignoreInitial: true, - }) - - await once(watcher, 'ready') - - let onChangeQueue: string[] = [] - let onAddQueue: string[] = [] - let onUnlinkQueue: string[] = [] - - const debouncedOnChange = debounce( - () => { - onChange(onChangeQueue) - onChangeQueue = [] - }, - DEBOUNCE_WAIT, - { leading: true }, - ) - const debouncedOnAdd = debounce( - () => { - onAdd(onAddQueue) - onAddQueue = [] - }, - DEBOUNCE_WAIT, - { leading: true }, - ) - const debouncedOnUnlink = debounce( - () => { - onUnlink(onUnlinkQueue) - onUnlinkQueue = [] - }, - DEBOUNCE_WAIT, - { leading: true }, - ) - - watcher - .on('change', (path) => { - decache(path) - onChangeQueue.push(path) - debouncedOnChange() - }) - .on('unlink', (path) => { - decache(path) - onUnlinkQueue.push(path) - debouncedOnUnlink() - }) - .on('add', (path) => { - decache(path) - onAddQueue.push(path) - debouncedOnAdd() - }) - - return watcher -} diff --git a/packages/dev-utils/src/main.ts b/packages/dev-utils/src/main.ts deleted file mode 100644 index 9b87ced..0000000 --- a/packages/dev-utils/src/main.ts +++ /dev/null @@ -1,28 +0,0 @@ -export { Reactive } from './lib/reactive.js' -export { getAPIToken } from './lib/api-token.js' -export { shouldBase64Encode } from './lib/base64.js' -export { renderFunctionErrorPage } from './lib/errors.js' -export { DevEvent, DevEventHandler } from './lib/event.js' -export { type Geolocation, mockLocation, getGeoLocation } from './lib/geo-location.js' -export { ensureNetlifyIgnore } from './lib/gitignore.js' -export { headers, toMultiValueHeaders } from './lib/headers.js' -export { getGlobalConfigStore, GlobalConfigStore, resetConfigCache } from './lib/global-config.js' -export { Handler } from './lib/handler.js' -export { LocalState } from './lib/local-state.js' -export { type Logger, netlifyCommand, netlifyCyan, netlifyBanner, warning } from './lib/logger.js' -export { memoize, MemoizeCache } from './lib/memoize.js' -export { killProcess, type ProcessRef } from './lib/process.js' -export { HTTPServer } from './server/http_server.js' -export { fromWebResponse, toWebRequest } from './lib/reqres.js' -export { - FileWatcher, - type FileWatchSubscriptionHandle, - type FileWatchSubscriptionOptions, -} from './lib/file-watcher/index.js' -export { watchDebounced } from './lib/watch-debounced.js' - -export { EventInspector } from './test/event_inspector.js' -export { MockFetch } from './test/fetch.js' -export { Fixture } from './test/fixture.js' -export { createImageServerHandler, generateImage, getImageResponseSize } from './test/image.js' -export { createMockLogger } from './test/logger.js' diff --git a/packages/dev-utils/src/server/http_server.test.ts b/packages/dev-utils/src/server/http_server.test.ts deleted file mode 100644 index 854740b..0000000 --- a/packages/dev-utils/src/server/http_server.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import { HTTPServer } from './http_server.js' - -describe('HTTP server', () => { - test('Serves requests', async () => { - const server = new HTTPServer(async (req: Request) => { - const url = new URL(req.url) - - return Response.json({ path: url.pathname }) - }) - - const address = await server.start() - - const res1 = await fetch(`${address}/foo`) - expect(res1.status).toBe(200) - expect(await res1.json()).toStrictEqual({ path: '/foo' }) - - const res2 = await fetch(`${address}/bar/baz`) - expect(res2.status).toBe(200) - expect(await res2.json()).toStrictEqual({ path: '/bar/baz' }) - - await server.stop() - }) -}) diff --git a/packages/dev-utils/src/server/http_server.ts b/packages/dev-utils/src/server/http_server.ts deleted file mode 100644 index 145ef46..0000000 --- a/packages/dev-utils/src/server/http_server.ts +++ /dev/null @@ -1,62 +0,0 @@ -import http from 'node:http' - -import { createServerAdapter } from '@whatwg-node/server' - -import { Handler } from '../lib/handler.js' - -/** - * A Node.js HTTP server with support for middleware. - */ -export class HTTPServer { - private url?: string - private handler: Handler - private nodeServer?: http.Server - - constructor(handler: Handler) { - this.handler = handler - } - - async start(port = 0) { - if (this.url) { - return this.url - } - - const adapter = createServerAdapter((request: Request) => this.handler(request)) - const server = http.createServer(adapter) - - this.nodeServer = server - - return new Promise((resolve, reject) => { - server.listen(port, () => { - const address = server.address() - - if (!address || typeof address === 'string') { - return reject(new Error('Server cannot be started on a pipe or Unix socket')) - } - - const url = `http://localhost:${address.port}` - this.url = url - - resolve(url) - }) - }) - } - - async stop() { - const server = this.nodeServer - - if (!server) { - return - } - - await new Promise((resolve, reject) => { - server.close((error?: NodeJS.ErrnoException) => { - if (error) { - return reject(error) - } - - resolve(null) - }) - }) - } -} diff --git a/packages/dev-utils/src/templates/function-error.html b/packages/dev-utils/src/templates/function-error.html deleted file mode 100644 index 80a3cf3..0000000 --- a/packages/dev-utils/src/templates/function-error.html +++ /dev/null @@ -1,316 +0,0 @@ - - - - - Invocation failed - - - - - - - -
-
-
-

- - This - - has crashed -

-

An unhandled error in the function code triggered the following message:

- -
- -
- - -
- -
- - diff --git a/packages/dev-utils/src/test/event_inspector.ts b/packages/dev-utils/src/test/event_inspector.ts deleted file mode 100644 index 20d1855..0000000 --- a/packages/dev-utils/src/test/event_inspector.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { EventEmitter } from 'node:events' - -import type { DevEvent } from '../lib/event.js' - -const DEFAULT_TIMEOUT = 5000 - -interface EventInspectorOptions { - debug?: boolean -} - -export class EventInspector extends EventEmitter { - debug: boolean - events: DevEvent[] - - constructor({ debug }: EventInspectorOptions = {}) { - super() - - this.debug = debug === true - this.events = [] - } - - handleEvent(event: DevEvent) { - this.events.push(event) - - this.emit('eventReceived', event) - } - - waitFor(filter: (event: DevEvent) => boolean, timeoutMs = DEFAULT_TIMEOUT) { - return new Promise((resolve, reject) => { - setTimeout(() => { - reject(new Error(`\`waitFor\` timed out after ${timeoutMs} ms`)) - }, timeoutMs) - - this.on('eventReceived', (event: DevEvent) => { - if (this.debug) { - console.log('[EventInspector] Event received:', event) - } - - if (filter(event)) { - resolve(event) - } - }) - }) - } -} diff --git a/packages/dev-utils/src/test/fetch.ts b/packages/dev-utils/src/test/fetch.ts deleted file mode 100644 index 9589239..0000000 --- a/packages/dev-utils/src/test/fetch.ts +++ /dev/null @@ -1,154 +0,0 @@ -import assert from 'node:assert' -import { Readable } from 'node:stream' -import { ReadableStream } from 'node:stream/web' - -type BodyFunction = (bufferedBody: string | null) => Promise | void -type HeadersFunction = (headers: Record) => Promise | void -type ResponseFunction = () => Promise | Response - -interface ExpectedRequest { - body?: string | BodyFunction - fulfilled: boolean - headers: Record | HeadersFunction - method: string - response: Response | ResponseFunction | Error - url: string -} - -interface ExpectedRequestOptions { - body?: string | BodyFunction - headers?: Record | HeadersFunction - response: Response | ResponseFunction | Error - url: string -} - -export class MockFetch { - originalFetch: typeof globalThis.fetch - requests: ExpectedRequest[] - - constructor() { - this.originalFetch = globalThis.fetch - this.requests = [] - } - - private addExpectedRequest({ - body, - headers = {}, - method, - response, - url, - }: ExpectedRequestOptions & { method: string }) { - this.requests.push({ body, fulfilled: false, headers, method, response, url }) - - return this - } - - delete(options: ExpectedRequestOptions) { - return this.addExpectedRequest({ ...options, method: 'delete' }) - } - - get(options: ExpectedRequestOptions) { - return this.addExpectedRequest({ ...options, method: 'get' }) - } - - head(options: ExpectedRequestOptions) { - return this.addExpectedRequest({ ...options, method: 'head' }) - } - - post(options: ExpectedRequestOptions) { - return this.addExpectedRequest({ ...options, method: 'post' }) - } - - put(options: ExpectedRequestOptions) { - return this.addExpectedRequest({ ...options, method: 'put' }) - } - - get fetch() { - return async (...args: Parameters) => { - const [reqOrURL, options] = args - const url = (reqOrURL instanceof Request ? reqOrURL.url : reqOrURL).toString() - const method = options?.method ?? 'get' - const headers = options?.headers as Record - const match = this.requests.find( - (request) => request.method.toLowerCase() === method.toLowerCase() && request.url === url && !request.fulfilled, - ) - - if (!match) { - throw new Error(`Unexpected fetch call: ${method} ${url}`) - } - - if (typeof match.headers === 'function') { - assert.doesNotThrow(() => (match.headers as HeadersFunction)(headers)) - } else { - for (const key in match.headers) { - assert.equal(headers[key], match.headers[key]) - } - } - - if (match.body !== undefined) { - let requestBody: string | null = null - - if (options?.body) { - if (typeof options.body === 'string') { - requestBody = options.body - } else { - requestBody = await readAsString(Readable.fromWeb(options.body as ReadableStream)) - } - } - - if (typeof match.body === 'string') { - assert.equal(requestBody, match.body) - } else if (typeof match.body === 'function') { - const bodyFn = match.body - - assert.doesNotThrow(() => bodyFn(requestBody)) - } else if (match.body === null) { - assert.equal(options?.body, undefined) - } - } - - match.fulfilled = true - - if (match.response instanceof Error) { - throw match.response - } - - if (typeof match.response === 'function') { - return match.response() - } - - return match.response - } - } - - get fulfilled() { - return this.requests.every((request) => request.fulfilled) - } - - inject() { - globalThis.fetch = this.fetch - - return this - } - - restore() { - globalThis.fetch = this.originalFetch - } -} - -export const readAsString = (input: NodeJS.ReadableStream): Promise => - new Promise((resolve, reject) => { - let buffer = '' - - input.on('data', (chunk) => { - buffer += chunk - }) - - input.on('error', (error) => { - reject(error) - }) - - input.on('end', () => { - resolve(buffer) - }) - }) diff --git a/packages/dev-utils/src/test/fixture.ts b/packages/dev-utils/src/test/fixture.ts deleted file mode 100644 index bbeea8e..0000000 --- a/packages/dev-utils/src/test/fixture.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { exec } from 'node:child_process' -import { promises as fs } from 'node:fs' -import { EOL } from 'node:os' -import { dirname, join } from 'node:path' -import { promisify } from 'node:util' - -import tmp from 'tmp-promise' - -const run = promisify(exec) -export class Fixture { - directory?: tmp.DirectoryResult - sourceDirectory?: string - files: Record - npmDependencies: Record - - constructor() { - this.files = {} - this.npmDependencies = {} - } - - private ensureDirectory() { - if (!this.directory) { - throw new Error("Fixture hasn't been initialized. Did you call `create()`?") - } - - return this.directory.path - } - - private async installNpmDependencies() { - if (Object.keys(this.npmDependencies).length === 0) { - return - } - - const directory = this.ensureDirectory() - const packageJSON = { - name: 'fixture', - version: '0.0.0', - type: 'module', - dependencies: this.npmDependencies, - } - const packageJSONPath = join(directory, 'package.json') - - await fs.writeFile(packageJSONPath, JSON.stringify(packageJSON, null, 2)) - console.debug('Installing npm dependencies in fixture...') - await run('npm install', { cwd: directory }) - console.debug('Installed npm dependencies in fixture') - } - - async create() { - if (!this.directory) { - this.directory = await tmp.dir({ unsafeCleanup: true }) - - // Resolve the canonical path so file watching sees the same form the OS - // reports for events. - this.directory.path = await fs.realpath(this.directory.path) - } - - if (this.sourceDirectory) { - console.debug(`Copying fixture from ${this.sourceDirectory} to ${this.directory.path}`) - await fs.cp(this.sourceDirectory, this.directory.path, { recursive: true }) - console.debug('Copied fixture') - } - - for (const relativePath in this.files) { - const filePath = join(this.directory.path, relativePath) - - await fs.mkdir(dirname(filePath), { recursive: true }) - await fs.writeFile(filePath, this.files[relativePath]) - } - - await this.installNpmDependencies() - - return this.directory.path - } - - async deleteFile(path: string) { - const filePath = join(this.ensureDirectory(), path) - - try { - await fs.rm(filePath, { force: true }) - } catch (error) { - if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { - throw error - } - } - } - - async destroy() { - // There's not much use in cleaning up in CI, plus this fails in some case on Windows images - if (process.env.CI) return - - await fs.rm(this.directory!.path, { force: true, recursive: true }) - } - - fromDirectory(path: string) { - this.sourceDirectory = path - - return this - } - - withFile(path: string, contents: string | Buffer) { - this.files[path] = contents - - return this - } - - withHeadersFile({ - headers = [], - pathPrefix = '', - }: { - headers?: { headers: string[]; path: string }[] - pathPrefix?: string - }) { - const dest = join(pathPrefix, '_headers') - const contents = headers - .map( - ({ headers: headersValues, path: headerPath }) => - `${headerPath}${EOL}${headersValues.map((header) => ` ${header}`).join(EOL)}`, - ) - .join(EOL) - - return this.withFile(dest, contents) - } - - withStateFile(state: object) { - this.files['.netlify/state.json'] = JSON.stringify(state) - - return this - } - - async writeFile(path: string, contents: string) { - const filePath = join(this.ensureDirectory(), path) - - await fs.writeFile(filePath, contents) - } - - withPackages(packages: Record) { - this.npmDependencies = { ...this.npmDependencies, ...packages } - - return this - } -} diff --git a/packages/dev-utils/src/test/image.ts b/packages/dev-utils/src/test/image.ts deleted file mode 100644 index 9d06875..0000000 --- a/packages/dev-utils/src/test/image.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { imageSize } from 'image-size' -import { generateImage as generateImageCallback } from 'js-image-generator' - -/** - * Returns Buffer of a generated random noise jpeg image with the specified width and height. - */ -export async function generateImage(width: number, height: number): Promise { - return new Promise((resolve, reject) => { - generateImageCallback(width, height, 80, (error, image) => { - if (error) { - reject(error) - } else { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - const imageBuffer = image.data as Buffer - - resolve(imageBuffer) - } - }) - }) -} - -/** - * Helper to create a server handler that responds with a random noise image. - */ -export function createImageServerHandler(imageConfigFromURL: (url: URL) => { width: number; height: number } | null) { - return async (request: Request): Promise => { - const url = new URL(request.url) - - const imageConfig = imageConfigFromURL(url) - - if (!imageConfig) { - return new Response('Not Found', { status: 404, headers: { 'Content-Type': 'text/plain' } }) - } - - try { - const imageBuffer = await generateImage(imageConfig.width, imageConfig.height) - return new Response(imageBuffer as BodyInit, { - headers: { - 'Content-Type': 'image/jpeg', - 'Content-Length': imageBuffer.length.toString(), - }, - }) - } catch (error) { - console.log('Error generating image', error) - return new Response('Error generating image', { status: 500 }) - } - } -} - -export async function getImageResponseSize(response: Response) { - if (!response.headers.get('content-type')?.startsWith('image/')) { - throw new Error('Response is not an image') - } - return imageSize(new Uint8Array(await response.arrayBuffer())) -} diff --git a/packages/dev-utils/src/test/logger.ts b/packages/dev-utils/src/test/logger.ts deleted file mode 100644 index 4f8fb69..0000000 --- a/packages/dev-utils/src/test/logger.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Logger } from '../lib/logger.js' - -export const createMockLogger = (): Logger => ({ - log: () => {}, - warn: () => {}, - error: () => {}, -}) diff --git a/packages/dev-utils/tsconfig.json b/packages/dev-utils/tsconfig.json deleted file mode 100644 index 7b592ea..0000000 --- a/packages/dev-utils/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/dev-utils/tsup.config.ts b/packages/dev-utils/tsup.config.ts deleted file mode 100644 index c3b8320..0000000 --- a/packages/dev-utils/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - }, -]) diff --git a/packages/dev/.gitignore b/packages/dev/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/dev/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/dev/CHANGELOG.md b/packages/dev/CHANGELOG.md deleted file mode 100644 index a83e608..0000000 --- a/packages/dev/CHANGELOG.md +++ /dev/null @@ -1,1504 +0,0 @@ -# Changelog - -## [4.18.7](https://github.com/netlify/primitives/compare/dev-v4.18.6...dev-v4.18.7) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.8 to 10.7.9 - * @netlify/dev-utils bumped from 4.4.5 to 4.4.6 - * @netlify/edge-functions-dev bumped from 1.0.19 to 1.0.20 - * @netlify/functions-dev bumped from 1.2.11 to 1.3.0 - * @netlify/headers bumped from 2.1.10 to 2.1.11 - * @netlify/images bumped from 1.3.9 to 1.3.10 - * @netlify/redirects bumped from 3.1.12 to 3.1.13 - * @netlify/runtime bumped from 4.1.24 to 4.1.25 - * @netlify/static bumped from 3.1.9 to 3.1.10 - * devDependencies - * @netlify/types bumped from 2.7.0 to 2.8.0 - -## [4.18.6](https://github.com/netlify/primitives/compare/dev-v4.18.5...dev-v4.18.6) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.7 to 10.7.8 - * @netlify/dev-utils bumped from 4.4.4 to 4.4.5 - * @netlify/edge-functions-dev bumped from 1.0.18 to 1.0.19 - * @netlify/functions-dev bumped from 1.2.10 to 1.2.11 - * @netlify/headers bumped from 2.1.9 to 2.1.10 - * @netlify/images bumped from 1.3.8 to 1.3.9 - * @netlify/redirects bumped from 3.1.11 to 3.1.12 - * @netlify/runtime bumped from 4.1.23 to 4.1.24 - * @netlify/static bumped from 3.1.8 to 3.1.9 - * devDependencies - * @netlify/types bumped from 2.6.0 to 2.7.0 - -## [4.18.5](https://github.com/netlify/primitives/compare/dev-v4.18.4...dev-v4.18.5) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.6 to 10.7.7 - * @netlify/dev-utils bumped from 4.4.3 to 4.4.4 - * @netlify/edge-functions-dev bumped from 1.0.17 to 1.0.18 - * @netlify/functions-dev bumped from 1.2.9 to 1.2.10 - * @netlify/headers bumped from 2.1.8 to 2.1.9 - * @netlify/images bumped from 1.3.7 to 1.3.8 - * @netlify/redirects bumped from 3.1.10 to 3.1.11 - * @netlify/runtime bumped from 4.1.22 to 4.1.23 - * @netlify/static bumped from 3.1.7 to 3.1.8 - -## [4.18.4](https://github.com/netlify/primitives/compare/dev-v4.18.3...dev-v4.18.4) (2026-05-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.5 to 10.7.6 - * @netlify/functions-dev bumped from 1.2.8 to 1.2.9 - * @netlify/runtime bumped from 4.1.21 to 4.1.22 - -## [4.18.3](https://github.com/netlify/primitives/compare/dev-v4.18.2...dev-v4.18.3) (2026-05-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.4 to 10.7.5 - * @netlify/functions-dev bumped from 1.2.7 to 1.2.8 - * @netlify/runtime bumped from 4.1.20 to 4.1.21 - -## [4.18.2](https://github.com/netlify/primitives/compare/dev-v4.18.1...dev-v4.18.2) (2026-05-11) - - -### Bug Fixes - -* **deps:** update netlify packages ([#674](https://github.com/netlify/primitives/issues/674)) ([8179496](https://github.com/netlify/primitives/commit/8179496fad479522f329cc99d03175408bffcb0c)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions-dev bumped from 1.0.16 to 1.0.17 - * @netlify/functions-dev bumped from 1.2.6 to 1.2.7 - -## [4.18.1](https://github.com/netlify/primitives/compare/dev-v4.18.0...dev-v4.18.1) (2026-04-28) - - -### Bug Fixes - -* set NETLIFY_DB_DRIVER to server in dev ([#670](https://github.com/netlify/primitives/issues/670)) ([cedca7a](https://github.com/netlify/primitives/commit/cedca7a6da04154b9c6d6d5347160fd4e8644a20)) - -## [4.18.0](https://github.com/netlify/primitives/compare/dev-v4.17.3...dev-v4.18.0) (2026-04-27) - - -### Features - -* export initializeTrackingTable from @netlify/dev ([#663](https://github.com/netlify/primitives/issues/663)) ([52ac65a](https://github.com/netlify/primitives/commit/52ac65a9065931ab951f65d817b1ad2f788a9f2c)) -* unflag database ([#667](https://github.com/netlify/primitives/issues/667)) ([76d95a1](https://github.com/netlify/primitives/commit/76d95a1de14712f858f24d90a430e9b7bca9f3e7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/database-dev bumped from 0.10.0 to 0.10.1 - -## [4.17.3](https://github.com/netlify/primitives/compare/dev-v4.17.2...dev-v4.17.3) (2026-04-20) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/database-dev bumped from 0.9.0 to 0.10.0 - -## [4.17.2](https://github.com/netlify/primitives/compare/dev-v4.17.1...dev-v4.17.2) (2026-04-20) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/database-dev bumped from 0.8.0 to 0.9.0 - -## [4.17.1](https://github.com/netlify/primitives/compare/dev-v4.17.0...dev-v4.17.1) (2026-04-14) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions-dev bumped from 1.2.5 to 1.2.6 - -## [4.17.0](https://github.com/netlify/primitives/compare/dev-v4.16.5...dev-v4.17.0) (2026-04-13) - - -### Features - -* rename database package ([#649](https://github.com/netlify/primitives/issues/649)) ([bbe80bb](https://github.com/netlify/primitives/commit/bbe80bb31eedb74d08c08f35cd21f1360b9eb41f)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/database-dev bumped from 0.7.0 to 0.8.0 - -## [4.16.5](https://github.com/netlify/primitives/compare/dev-v4.16.4...dev-v4.16.5) (2026-04-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions-dev bumped from 1.2.4 to 1.2.5 - -## [4.16.4](https://github.com/netlify/primitives/compare/dev-v4.16.3...dev-v4.16.4) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.3 to 10.7.4 - * @netlify/dev-utils bumped from 4.4.2 to 4.4.3 - * @netlify/edge-functions-dev bumped from 1.0.15 to 1.0.16 - * @netlify/functions-dev bumped from 1.2.3 to 1.2.4 - * @netlify/headers bumped from 2.1.7 to 2.1.8 - * @netlify/images bumped from 1.3.6 to 1.3.7 - * @netlify/redirects bumped from 3.1.9 to 3.1.10 - * @netlify/runtime bumped from 4.1.19 to 4.1.20 - * @netlify/static bumped from 3.1.6 to 3.1.7 - * devDependencies - * @netlify/types bumped from 2.5.0 to 2.6.0 - -## [4.16.3](https://github.com/netlify/primitives/compare/dev-v4.16.2...dev-v4.16.3) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.2 to 10.7.3 - * @netlify/dev-utils bumped from 4.4.1 to 4.4.2 - * @netlify/edge-functions-dev bumped from 1.0.14 to 1.0.15 - * @netlify/functions-dev bumped from 1.2.2 to 1.2.3 - * @netlify/headers bumped from 2.1.6 to 2.1.7 - * @netlify/images bumped from 1.3.5 to 1.3.6 - * @netlify/redirects bumped from 3.1.8 to 3.1.9 - * @netlify/runtime bumped from 4.1.18 to 4.1.19 - * @netlify/static bumped from 3.1.5 to 3.1.6 - * devDependencies - * @netlify/types bumped from 2.4.0 to 2.5.0 - -## [4.16.2](https://github.com/netlify/primitives/compare/dev-v4.16.1...dev-v4.16.2) (2026-03-13) - - -### Bug Fixes - -* **deps:** update netlify packages ([#626](https://github.com/netlify/primitives/issues/626)) ([a87ba84](https://github.com/netlify/primitives/commit/a87ba84fa23c3a4ff506cd9c3d5f3b5cd78d9f3c)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.4.0 to ^0.4.1 - * @netlify/edge-functions-dev bumped from 1.0.13 to 1.0.14 - * @netlify/functions-dev bumped from 1.2.1 to 1.2.2 - * @netlify/headers bumped from 2.1.5 to 2.1.6 - * @netlify/redirects bumped from 3.1.7 to 3.1.8 - -## [4.16.1](https://github.com/netlify/primitives/compare/dev-v4.16.0...dev-v4.16.1) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.1 to 10.7.2 - * @netlify/dev-utils bumped from 4.4.0 to 4.4.1 - * @netlify/edge-functions-dev bumped from 1.0.12 to 1.0.13 - * @netlify/functions-dev bumped from 1.2.0 to 1.2.1 - * @netlify/headers bumped from 2.1.4 to 2.1.5 - * @netlify/images bumped from 1.3.4 to 1.3.5 - * @netlify/redirects bumped from 3.1.6 to 3.1.7 - * @netlify/runtime bumped from 4.1.17 to 4.1.18 - * @netlify/static bumped from 3.1.4 to 3.1.5 - * devDependencies - * @netlify/types bumped from 2.3.0 to 2.4.0 - -## [4.16.0](https://github.com/netlify/primitives/compare/dev-v4.15.0...dev-v4.16.0) (2026-03-10) - - -### Features - -* **db:** make NetlifyDB fulfill SQLExecutor ([#620](https://github.com/netlify/primitives/issues/620)) ([a91a390](https://github.com/netlify/primitives/commit/a91a390a32a66a0bdd86efaa8574e597abef3b82)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/db-dev bumped from 0.6.0 to 0.7.0 - -## [4.15.0](https://github.com/netlify/primitives/compare/dev-v4.14.1...dev-v4.15.0) (2026-03-10) - - -### Features - -* add `FileWatcher` class ([#607](https://github.com/netlify/primitives/issues/607)) ([1f8bdfc](https://github.com/netlify/primitives/commit/1f8bdfc06e411703cc9338b9cd7dfe3a0c0f4eff)) -* **db-dev:** abstract pg client into interface ([#619](https://github.com/netlify/primitives/issues/619)) ([2c92b2d](https://github.com/netlify/primitives/commit/2c92b2dfdd973255883caad44594dfd470799a6d)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.0 to 10.7.1 - * @netlify/db-dev bumped from 0.5.0 to 0.6.0 - * @netlify/dev-utils bumped from 4.3.3 to 4.4.0 - * @netlify/edge-functions-dev bumped from 1.0.11 to 1.0.12 - * @netlify/functions-dev bumped from 1.1.12 to 1.2.0 - * @netlify/headers bumped from 2.1.3 to 2.1.4 - * @netlify/images bumped from 1.3.3 to 1.3.4 - * @netlify/redirects bumped from 3.1.5 to 3.1.6 - * @netlify/runtime bumped from 4.1.16 to 4.1.17 - * @netlify/static bumped from 3.1.3 to 3.1.4 - -## [4.14.1](https://github.com/netlify/primitives/compare/dev-v4.14.0...dev-v4.14.1) (2026-03-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/db-dev bumped from 0.4.0 to 0.5.0 - -## [4.14.0](https://github.com/netlify/primitives/compare/dev-v4.13.0...dev-v4.14.0) (2026-03-05) - - -### Features - -* **dev:** export db instance on NetlifyDev ([#613](https://github.com/netlify/primitives/issues/613)) ([ff643ff](https://github.com/netlify/primitives/commit/ff643ffb01546498be8c18f0d955d9dd02514ed4)) - -## [4.13.0](https://github.com/netlify/primitives/compare/dev-v4.12.1...dev-v4.13.0) (2026-03-05) - - -### Features - -* **dev:** move @netlify/db-dev to dependency of @netlify/dev ([#611](https://github.com/netlify/primitives/issues/611)) ([8d0d1a1](https://github.com/netlify/primitives/commit/8d0d1a16f18cf5599696097b068a7b12dab10229)) - -## [4.12.1](https://github.com/netlify/primitives/compare/dev-v4.12.0...dev-v4.12.1) (2026-03-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/db-dev bumped from 0.3.0 to 0.4.0 - * peerDependencies - * @netlify/db-dev bumped from 0.2.0 to 0.4.0 - -## [4.12.0](https://github.com/netlify/primitives/compare/dev-v4.11.3...dev-v4.12.0) (2026-03-03) - - -### Features - -* account-based token fetch ([#604](https://github.com/netlify/primitives/issues/604)) ([b772f0d](https://github.com/netlify/primitives/commit/b772f0d96d1b2cb1d313d8397cce5b8b2d4161ae)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.3.8 to ^0.4.0 - -## [4.11.3](https://github.com/netlify/primitives/compare/dev-v4.11.2...dev-v4.11.3) (2026-02-27) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime bumped from 4.1.15 to 4.1.16 - * devDependencies - * @netlify/db-dev bumped from 0.2.0 to 0.3.0 - * peerDependencies - * @netlify/db-dev bumped from 0.2.0 to 0.3.0 - -## [4.11.2](https://github.com/netlify/primitives/compare/dev-v4.11.1...dev-v4.11.2) (2026-02-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#583](https://github.com/netlify/primitives/issues/583)) ([bcd8241](https://github.com/netlify/primitives/commit/bcd824172757fecac5aa91dc36b06163efb63497)) -* fix version of peer dependency ([#592](https://github.com/netlify/primitives/issues/592)) ([3d13332](https://github.com/netlify/primitives/commit/3d133326ad5dd8118aaa9f1f3ca6a1f4da9bbd70)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.3.7 to ^0.3.8 - * @netlify/edge-functions-dev bumped from 1.0.10 to 1.0.11 - * @netlify/functions-dev bumped from 1.1.11 to 1.1.12 - -## [4.11.1](https://github.com/netlify/primitives/compare/dev-v4.11.0...dev-v4.11.1) (2026-02-17) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/db-dev bumped from 1.0.0 to 0.2.0 - * peerDependencies - * @netlify/db-dev bumped from 1.0.0 to 0.2.0 - -## [4.11.0](https://github.com/netlify/primitives/compare/dev-v4.10.0...dev-v4.11.0) (2026-02-16) - - -### Features - -* add `db` package ([#581](https://github.com/netlify/primitives/issues/581)) ([b60a313](https://github.com/netlify/primitives/commit/b60a313bd9ba19fd5deced4736012c3d7c7fe842)) - - -### Bug Fixes - -* make `@netlify/db-dev` module optional ([#588](https://github.com/netlify/primitives/issues/588)) ([e40622b](https://github.com/netlify/primitives/commit/e40622be5804145ee592384c3965b77fa78aa1ba)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.3.6 to ^0.3.7 - * @netlify/blobs bumped from 10.6.0 to 10.7.0 - * @netlify/functions-dev bumped from 1.1.10 to 1.1.11 - * @netlify/redirects bumped from 3.1.4 to 3.1.5 - * @netlify/runtime bumped from 4.1.14 to 4.1.15 - -## [4.10.0](https://github.com/netlify/primitives/compare/dev-v4.9.0...dev-v4.10.0) (2026-02-06) - - -### Features - -* move `getEnvironment` to `runtime-utils` ([#579](https://github.com/netlify/primitives/issues/579)) ([639ba5f](https://github.com/netlify/primitives/commit/639ba5f5d5659bcf96894dc627a87af42c8fc19f)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.5.0 to 10.6.0 - * @netlify/edge-functions-dev bumped from 1.0.9 to 1.0.10 - * @netlify/functions-dev bumped from 1.1.9 to 1.1.10 - * @netlify/runtime bumped from 4.1.13 to 4.1.14 - -## [4.9.0](https://github.com/netlify/primitives/compare/dev-v4.8.8...dev-v4.9.0) (2026-01-28) - - -### Features - -* ai gateway disabled check ([#577](https://github.com/netlify/primitives/issues/577)) ([5c2a8ce](https://github.com/netlify/primitives/commit/5c2a8ce6aa9b324cd44a24c519086855299e780c)) - - -### Bug Fixes - -* **deps:** update netlify packages ([#576](https://github.com/netlify/primitives/issues/576)) ([1c6ff24](https://github.com/netlify/primitives/commit/1c6ff247318b8cdb1961ce76e96fe423a4ec8cd7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.3.5 to ^0.3.6 - * @netlify/edge-functions-dev bumped from 1.0.8 to 1.0.9 - * @netlify/functions-dev bumped from 1.1.8 to 1.1.9 - -## [4.8.8](https://github.com/netlify/primitives/compare/dev-v4.8.7...dev-v4.8.8) (2026-01-19) - - -### Bug Fixes - -* **deps:** update netlify packages ([#566](https://github.com/netlify/primitives/issues/566)) ([184656a](https://github.com/netlify/primitives/commit/184656af871a81bddc69e9133f22bfa945f28ebf)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions-dev bumped from 1.0.7 to 1.0.8 - * @netlify/functions-dev bumped from 1.1.7 to 1.1.8 - -## [4.8.7](https://github.com/netlify/primitives/compare/dev-v4.8.6...dev-v4.8.7) (2025-12-21) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions-dev bumped from 1.1.6 to 1.1.7 - -## [4.8.6](https://github.com/netlify/primitives/compare/dev-v4.8.5...dev-v4.8.6) (2025-12-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.4 to 10.5.0 - * @netlify/functions-dev bumped from 1.1.5 to 1.1.6 - * @netlify/runtime bumped from 4.1.12 to 4.1.13 - -## [4.8.5](https://github.com/netlify/primitives/compare/dev-v4.8.4...dev-v4.8.5) (2025-12-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.3 to 10.4.4 - * @netlify/functions-dev bumped from 1.1.4 to 1.1.5 - * @netlify/runtime bumped from 4.1.11 to 4.1.12 - -## [4.8.4](https://github.com/netlify/primitives/compare/dev-v4.8.3...dev-v4.8.4) (2025-12-08) - - -### Bug Fixes - -* **deps:** update netlify packages ([#557](https://github.com/netlify/primitives/issues/557)) ([60644bf](https://github.com/netlify/primitives/commit/60644bf6863a0ba41d9e73b0d8d1cfa90205c963)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.3.4 to ^0.3.5 - * @netlify/blobs bumped from 10.4.2 to 10.4.3 - * @netlify/dev-utils bumped from 4.3.2 to 4.3.3 - * @netlify/edge-functions-dev bumped from 1.0.6 to 1.0.7 - * @netlify/functions-dev bumped from 1.1.3 to 1.1.4 - * @netlify/headers bumped from 2.1.2 to 2.1.3 - * @netlify/images bumped from 1.3.2 to 1.3.3 - * @netlify/redirects bumped from 3.1.3 to 3.1.4 - * @netlify/runtime bumped from 4.1.10 to 4.1.11 - * @netlify/static bumped from 3.1.2 to 3.1.3 - * devDependencies - * @netlify/types bumped from 2.2.0 to 2.3.0 - -## [4.8.3](https://github.com/netlify/primitives/compare/dev-v4.8.2...dev-v4.8.3) (2025-12-03) - - -### Bug Fixes - -* **deps:** update dependency @netlify/config to v24 ([#415](https://github.com/netlify/primitives/issues/415)) ([5225265](https://github.com/netlify/primitives/commit/52252659d4809f8d9157739431674edb44e960a5)) -* **deps:** update netlify packages ([#549](https://github.com/netlify/primitives/issues/549)) ([ec4fb29](https://github.com/netlify/primitives/commit/ec4fb2978af5cf75c12645ade9f771bc94a796e2)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/ai bumped from ^0.3.3 to ^0.3.4 - * @netlify/blobs bumped from 10.4.1 to 10.4.2 - * @netlify/edge-functions-dev bumped from 1.0.5 to 1.0.6 - * @netlify/functions-dev bumped from 1.1.2 to 1.1.3 - * @netlify/runtime bumped from 4.1.9 to 4.1.10 - -## [4.8.2](https://github.com/netlify/primitives/compare/dev-v4.8.1...dev-v4.8.2) (2025-11-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.0 to 10.4.1 - * @netlify/functions-dev bumped from 1.1.1 to 1.1.2 - * @netlify/runtime bumped from 4.1.8 to 4.1.9 - -## [4.8.1](https://github.com/netlify/primitives/compare/dev-v4.8.0...dev-v4.8.1) (2025-11-14) - - -### Bug Fixes - -* handle HTTP/2 requests with pseudo-headers ([#534](https://github.com/netlify/primitives/issues/534)) ([7b5ce83](https://github.com/netlify/primitives/commit/7b5ce83ca2fb8df59a41dc81921c29566a39a1cb)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.3 to 10.4.0 - * @netlify/dev-utils bumped from 4.3.1 to 4.3.2 - * @netlify/edge-functions-dev bumped from 1.0.4 to 1.0.5 - * @netlify/functions-dev bumped from 1.1.0 to 1.1.1 - * @netlify/headers bumped from 2.1.1 to 2.1.2 - * @netlify/images bumped from 1.3.1 to 1.3.2 - * @netlify/redirects bumped from 3.1.2 to 3.1.3 - * @netlify/runtime bumped from 4.1.7 to 4.1.8 - * @netlify/static bumped from 3.1.1 to 3.1.2 - -## [4.8.0](https://github.com/netlify/primitives/compare/dev-v4.7.1...dev-v4.8.0) (2025-11-07) - - -### Features - -* add AI Gateway support to @netlify/dev for Vite plugin ([#524](https://github.com/netlify/primitives/issues/524)) ([e6823d4](https://github.com/netlify/primitives/commit/e6823d44ade93211f4eee57d131772720d260c78)) - -## [4.7.1](https://github.com/netlify/primitives/compare/dev-v4.7.0...dev-v4.7.1) (2025-11-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/redirects bumped from 3.1.1 to 3.1.2 - -## [4.7.0](https://github.com/netlify/primitives/compare/dev-v4.6.8...dev-v4.7.0) (2025-11-05) - - -### Features - -* implement functions timeout defaults and overrides in dev ([#346](https://github.com/netlify/primitives/issues/346)) ([c17753e](https://github.com/netlify/primitives/commit/c17753ec35bdef076db563fa37c1a4222bd5c149)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/api to v14.0.10 ([#521](https://github.com/netlify/primitives/issues/521)) ([61869e9](https://github.com/netlify/primitives/commit/61869e902052157006031d64089afb90c298b92c)) -* **deps:** update netlify packages ([#515](https://github.com/netlify/primitives/issues/515)) ([67034cc](https://github.com/netlify/primitives/commit/67034cce9f80e35582f328b1990d0f26e7181cff)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.2 to 10.3.3 - * @netlify/dev-utils bumped from 4.3.0 to 4.3.1 - * @netlify/edge-functions-dev bumped from 1.0.3 to 1.0.4 - * @netlify/functions-dev bumped from 1.0.5 to 1.1.0 - * @netlify/headers bumped from 2.1.0 to 2.1.1 - * @netlify/images bumped from 1.3.0 to 1.3.1 - * @netlify/redirects bumped from 3.1.0 to 3.1.1 - * @netlify/runtime bumped from 4.1.6 to 4.1.7 - * @netlify/static bumped from 3.1.0 to 3.1.1 - * devDependencies - * @netlify/types bumped from 2.1.0 to 2.2.0 - -## [4.6.8](https://github.com/netlify/primitives/compare/dev-v4.6.7...dev-v4.6.8) (2025-11-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.1 to 10.3.2 - * @netlify/edge-functions-dev bumped from 1.0.2 to 1.0.3 - * @netlify/functions-dev bumped from 1.0.4 to 1.0.5 - * @netlify/runtime bumped from 4.1.5 to 4.1.6 - -## [4.6.7](https://github.com/netlify/primitives/compare/dev-v4.6.6...dev-v4.6.7) (2025-10-29) - - -### Bug Fixes - -* **deps:** update netlify packages ([#504](https://github.com/netlify/primitives/issues/504)) ([3586853](https://github.com/netlify/primitives/commit/35868533dd9f878b4162685131219419ca33bd8a)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.0 to 10.3.1 - * @netlify/edge-functions-dev bumped from 1.0.1 to 1.0.2 - * @netlify/functions-dev bumped from 1.0.3 to 1.0.4 - * @netlify/runtime bumped from 4.1.4 to 4.1.5 - -## [4.6.6](https://github.com/netlify/primitives/compare/dev-v4.6.5...dev-v4.6.6) (2025-10-27) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.2.1 to 10.3.0 - * @netlify/functions-dev bumped from 1.0.2 to 1.0.3 - * @netlify/runtime bumped from 4.1.3 to 4.1.4 - -## [4.6.5](https://github.com/netlify/primitives/compare/dev-v4.6.4...dev-v4.6.5) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.2.0 to 10.2.1 - * @netlify/functions-dev bumped from 1.0.1 to 1.0.2 - * @netlify/runtime bumped from 4.1.2 to 4.1.3 - -## [4.6.4](https://github.com/netlify/primitives/compare/dev-v4.6.3...dev-v4.6.4) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.1.0 to 10.2.0 - * @netlify/edge-functions-dev bumped from 1.0.0 to 1.0.1 - * @netlify/functions-dev bumped from 1.0.0 to 1.0.1 - * @netlify/runtime bumped from 4.1.1 to 4.1.2 - -## [4.6.3](https://github.com/netlify/primitives/compare/dev-v4.6.2...dev-v4.6.3) (2025-10-19) - - -### Bug Fixes - -* use new `@netlify/edge-functions-dev` package ([4b21e44](https://github.com/netlify/primitives/commit/4b21e44dfad75525d2a8d81dca9932c35de867b1)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions-dev bumped from 0.0.0 to 1.0.0 - -## [4.6.2](https://github.com/netlify/primitives/compare/dev-v4.6.1...dev-v4.6.2) (2025-10-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime bumped from 4.1.0 to 4.1.1 - -## [4.6.1](https://github.com/netlify/primitives/compare/dev-v4.6.0...dev-v4.6.1) (2025-10-14) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions-dev bumped from 0.0.0 to 1.0.0 - -## [4.6.0](https://github.com/netlify/primitives/compare/dev-v4.5.12...dev-v4.6.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.11 to 10.1.0 - * @netlify/dev-utils bumped from 4.2.0 to 4.3.0 - * @netlify/edge-functions bumped from 2.18.2 to 2.19.0 - * @netlify/functions bumped from 4.2.7 to 4.3.0 - * @netlify/headers bumped from 2.0.12 to 2.1.0 - * @netlify/images bumped from 1.2.8 to 1.3.0 - * @netlify/redirects bumped from 3.0.13 to 3.1.0 - * @netlify/runtime bumped from 4.0.16 to 4.1.0 - * @netlify/static bumped from 3.0.11 to 3.1.0 - * devDependencies - * @netlify/types bumped from 2.0.3 to 2.1.0 - -## [4.5.12](https://github.com/netlify/primitives/compare/dev-v4.5.11...dev-v4.5.12) (2025-10-01) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.18.1 to 2.18.2 - * @netlify/functions bumped from 4.2.6 to 4.2.7 - -## [4.5.11](https://github.com/netlify/primitives/compare/dev-v4.5.10...dev-v4.5.11) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.10 to 10.0.11 - * @netlify/dev-utils bumped from 4.1.3 to 4.2.0 - * @netlify/edge-functions bumped from 2.18.0 to 2.18.1 - * @netlify/functions bumped from 4.2.5 to 4.2.6 - * @netlify/headers bumped from 2.0.11 to 2.0.12 - * @netlify/images bumped from 1.2.7 to 1.2.8 - * @netlify/redirects bumped from 3.0.12 to 3.0.13 - * @netlify/runtime bumped from 4.0.15 to 4.0.16 - * @netlify/static bumped from 3.0.10 to 3.0.11 - -## [4.5.10](https://github.com/netlify/primitives/compare/dev-v4.5.9...dev-v4.5.10) (2025-09-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.17.4 to 2.18.0 - -## [4.5.9](https://github.com/netlify/primitives/compare/dev-v4.5.8...dev-v4.5.9) (2025-09-05) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime bumped from 4.0.14 to 4.0.15 - -## [4.5.8](https://github.com/netlify/primitives/compare/dev-v4.5.7...dev-v4.5.8) (2025-08-28) - - -### Bug Fixes - -* **dev:** add support for `dev-server` context ([#438](https://github.com/netlify/primitives/issues/438)) ([793b853](https://github.com/netlify/primitives/commit/793b85333bbdd0959df97ccd8e04bc269f9d3747)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.9 to 10.0.10 - * @netlify/dev-utils bumped from 4.1.2 to 4.1.3 - * @netlify/edge-functions bumped from 2.17.3 to 2.17.4 - * @netlify/functions bumped from 4.2.4 to 4.2.5 - * @netlify/headers bumped from 2.0.10 to 2.0.11 - * @netlify/images bumped from 1.2.6 to 1.2.7 - * @netlify/redirects bumped from 3.0.11 to 3.0.12 - * @netlify/runtime bumped from 4.0.13 to 4.0.14 - * @netlify/static bumped from 3.0.9 to 3.0.10 - * devDependencies - * @netlify/types bumped from 2.0.2 to 2.0.3 - -## [4.5.7](https://github.com/netlify/primitives/compare/dev-v4.5.6...dev-v4.5.7) (2025-08-26) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.17.2 to 2.17.3 - * @netlify/functions bumped from 4.2.3 to 4.2.4 - -## [4.5.6](https://github.com/netlify/primitives/compare/dev-v4.5.5...dev-v4.5.6) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.8 to 10.0.9 - * @netlify/dev-utils bumped from 4.1.1 to 4.1.2 - * @netlify/edge-functions bumped from 2.17.1 to 2.17.2 - * @netlify/functions bumped from 4.2.2 to 4.2.3 - * @netlify/headers bumped from 2.0.9 to 2.0.10 - * @netlify/images bumped from 1.2.5 to 1.2.6 - * @netlify/redirects bumped from 3.0.10 to 3.0.11 - * @netlify/runtime bumped from 4.0.12 to 4.0.13 - * @netlify/static bumped from 3.0.8 to 3.0.9 - -## [4.5.5](https://github.com/netlify/primitives/compare/dev-v4.5.4...dev-v4.5.5) (2025-08-14) - - -### Bug Fixes - -* **deps:** update netlify packages ([#411](https://github.com/netlify/primitives/issues/411)) ([bad2dce](https://github.com/netlify/primitives/commit/bad2dceae8b5e5f56d947ce2332372d148819ccc)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.17.0 to 2.17.1 - * @netlify/functions bumped from 4.2.1 to 4.2.2 - * @netlify/headers bumped from 2.0.8 to 2.0.9 - * @netlify/redirects bumped from 3.0.9 to 3.0.10 - -## [4.5.4](https://github.com/netlify/primitives/compare/dev-v4.5.3...dev-v4.5.4) (2025-08-01) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.16.3 to 2.17.0 - * @netlify/redirects bumped from 3.0.8 to 3.0.9 - -## [4.5.3](https://github.com/netlify/primitives/compare/dev-v4.5.2...dev-v4.5.3) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.7 to 10.0.8 - * @netlify/dev-utils bumped from 4.1.0 to 4.1.1 - * @netlify/edge-functions bumped from 2.16.2 to 2.16.3 - * @netlify/functions bumped from 4.2.0 to 4.2.1 - * @netlify/headers bumped from 2.0.7 to 2.0.8 - * @netlify/images bumped from 1.2.4 to 1.2.5 - * @netlify/redirects bumped from 3.0.7 to 3.0.8 - * @netlify/runtime bumped from 4.0.11 to 4.0.12 - * @netlify/static bumped from 3.0.7 to 3.0.8 - -## [4.5.2](https://github.com/netlify/primitives/compare/dev-v4.5.1...dev-v4.5.2) (2025-07-28) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 4.1.15 to 4.2.0 - -## [4.5.1](https://github.com/netlify/primitives/compare/dev-v4.5.0...dev-v4.5.1) (2025-07-24) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/images bumped from 1.2.3 to 1.2.4 - -## [4.5.0](https://github.com/netlify/primitives/compare/dev-v4.4.6...dev-v4.5.0) (2025-07-23) - - -### Features - -* add actual dev geolocation to functions and edge functions context ([#345](https://github.com/netlify/primitives/issues/345)) ([916c38b](https://github.com/netlify/primitives/commit/916c38b84632b705a1d6ab4bfc6d60bfebd1ed2c)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.6 to 10.0.7 - * @netlify/dev-utils bumped from 4.0.0 to 4.1.0 - * @netlify/edge-functions bumped from 2.16.1 to 2.16.2 - * @netlify/functions bumped from 4.1.14 to 4.1.15 - * @netlify/headers bumped from 2.0.6 to 2.0.7 - * @netlify/images bumped from 1.2.2 to 1.2.3 - * @netlify/redirects bumped from 3.0.6 to 3.0.7 - * @netlify/runtime bumped from 4.0.10 to 4.0.11 - * @netlify/static bumped from 3.0.6 to 3.0.7 - -## [4.4.6](https://github.com/netlify/primitives/compare/dev-v4.4.5...dev-v4.4.6) (2025-07-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 4.1.13 to 4.1.14 - -## [4.4.5](https://github.com/netlify/primitives/compare/dev-v4.4.4...dev-v4.4.5) (2025-07-21) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 4.1.12 to 4.1.13 - -## [4.4.4](https://github.com/netlify/primitives/compare/dev-v4.4.3...dev-v4.4.4) (2025-07-21) - - -### Bug Fixes - -* handle 304 responses from edge functions ([#364](https://github.com/netlify/primitives/issues/364)) ([08e2543](https://github.com/netlify/primitives/commit/08e254325163707a397c8dddc0761df6aad63fd7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.16.0 to 2.16.1 - -## [4.4.3](https://github.com/netlify/primitives/compare/dev-v4.4.2...dev-v4.4.3) (2025-07-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.15.8 to 2.16.0 - -## [4.4.2](https://github.com/netlify/primitives/compare/dev-v4.4.1...dev-v4.4.2) (2025-07-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#333](https://github.com/netlify/primitives/issues/333)) ([0fa1f1e](https://github.com/netlify/primitives/commit/0fa1f1e8d717cbc5c797c19b64b4fa4ffbdaf992)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.5 to 10.0.6 - * @netlify/dev-utils bumped from 3.3.0 to 4.0.0 - * @netlify/edge-functions bumped from 2.15.7 to 2.15.8 - * @netlify/functions bumped from 4.1.11 to 4.1.12 - * @netlify/headers bumped from 2.0.5 to 2.0.6 - * @netlify/images bumped from 1.2.1 to 1.2.2 - * @netlify/redirects bumped from 3.0.5 to 3.0.6 - * @netlify/runtime bumped from 4.0.9 to 4.0.10 - * @netlify/static bumped from 3.0.5 to 3.0.6 - -## [4.4.1](https://github.com/netlify/primitives/compare/dev-v4.4.0...dev-v4.4.1) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.4 to 10.0.5 - * @netlify/dev-utils bumped from 3.2.2 to 3.3.0 - * @netlify/edge-functions bumped from 2.15.6 to 2.15.7 - * @netlify/functions bumped from 4.1.10 to 4.1.11 - * @netlify/headers bumped from 2.0.4 to 2.0.5 - * @netlify/images bumped from 1.2.0 to 1.2.1 - * @netlify/redirects bumped from 3.0.4 to 3.0.5 - * @netlify/runtime bumped from 4.0.8 to 4.0.9 - * @netlify/static bumped from 3.0.4 to 3.0.5 - -## [4.4.0](https://github.com/netlify/primitives/compare/dev-v4.3.8...dev-v4.4.0) (2025-07-15) - - -### Features - -* add `images.remoteURLPatterns` option to `NetlifyDev` ([#348](https://github.com/netlify/primitives/issues/348)) ([606e264](https://github.com/netlify/primitives/commit/606e26475c88a47f41929c5548820f2886094b3a)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/images bumped from 1.1.2 to 1.2.0 - -## [4.3.8](https://github.com/netlify/primitives/compare/dev-v4.3.7...dev-v4.3.8) (2025-07-11) - - -### Bug Fixes - -* pass all required env vars to edge function invocations ([#342](https://github.com/netlify/primitives/issues/342)) ([9b6c286](https://github.com/netlify/primitives/commit/9b6c2863d157a0fbeca35ea0cd55d6f8d0a0acc1)) - -## [4.3.7](https://github.com/netlify/primitives/compare/dev-v4.3.6...dev-v4.3.7) (2025-07-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.3 to 10.0.4 - * @netlify/functions bumped from 4.1.9 to 4.1.10 - * @netlify/runtime bumped from 4.0.7 to 4.0.8 - -## [4.3.6](https://github.com/netlify/primitives/compare/dev-v4.3.5...dev-v4.3.6) (2025-07-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.15.5 to 2.15.6 - -## [4.3.5](https://github.com/netlify/primitives/compare/dev-v4.3.4...dev-v4.3.5) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.2 to 10.0.3 - * @netlify/dev-utils bumped from 3.2.1 to 3.2.2 - * @netlify/edge-functions bumped from 2.15.4 to 2.15.5 - * @netlify/functions bumped from 4.1.8 to 4.1.9 - * @netlify/headers bumped from 2.0.3 to 2.0.4 - * @netlify/images bumped from 1.1.1 to 1.1.2 - * @netlify/redirects bumped from 3.0.3 to 3.0.4 - * @netlify/runtime bumped from 4.0.6 to 4.0.7 - * @netlify/static bumped from 3.0.3 to 3.0.4 - -## [4.3.4](https://github.com/netlify/primitives/compare/dev-v4.3.3...dev-v4.3.4) (2025-06-26) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.15.3 to 2.15.4 - -## [4.3.3](https://github.com/netlify/primitives/compare/dev-v4.3.2...dev-v4.3.3) (2025-06-26) - - -### Bug Fixes - -* **deps:** update netlify packages ([#318](https://github.com/netlify/primitives/issues/318)) ([6710630](https://github.com/netlify/primitives/commit/671063084526b210711971fbae53135e2aeb6e0a)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.1 to 10.0.2 - * @netlify/edge-functions bumped from 2.15.2 to 2.15.3 - * @netlify/functions bumped from 4.1.7 to 4.1.8 - * @netlify/runtime bumped from 4.0.5 to 4.0.6 - -## [4.3.2](https://github.com/netlify/primitives/compare/dev-v4.3.1...dev-v4.3.2) (2025-06-25) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.15.1 to 2.15.2 - * @netlify/functions bumped from 4.1.6 to 4.1.7 - -## [4.3.1](https://github.com/netlify/primitives/compare/dev-v4.3.0...dev-v4.3.1) (2025-06-18) - - -### Bug Fixes - -* clean up edge functions server ([#310](https://github.com/netlify/primitives/issues/310)) ([243f3b4](https://github.com/netlify/primitives/commit/243f3b472d1350eb6a80d8f736385750de8bc0d4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.0 to 10.0.1 - * @netlify/dev-utils bumped from 3.2.0 to 3.2.1 - * @netlify/edge-functions bumped from 2.15.0 to 2.15.1 - * @netlify/functions bumped from 4.1.5 to 4.1.6 - * @netlify/headers bumped from 2.0.2 to 2.0.3 - * @netlify/images bumped from 1.1.0 to 1.1.1 - * @netlify/redirects bumped from 3.0.2 to 3.0.3 - * @netlify/runtime bumped from 4.0.4 to 4.0.5 - * @netlify/static bumped from 3.0.2 to 3.0.3 - -## [4.3.0](https://github.com/netlify/primitives/compare/dev-v4.2.2...dev-v4.3.0) (2025-06-17) - - -### Features - -* add `serverAddress` to request handler ([#308](https://github.com/netlify/primitives/issues/308)) ([fa811f2](https://github.com/netlify/primitives/commit/fa811f24d473d471108f560abc484d17ea11bd70)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.14.5 to 2.15.0 - * @netlify/images bumped from 1.0.0 to 1.1.0 - -## [4.2.2](https://github.com/netlify/primitives/compare/dev-v4.2.1...dev-v4.2.2) (2025-06-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.6 to 10.0.0 - * @netlify/functions bumped from 4.1.4 to 4.1.5 - * @netlify/runtime bumped from 4.0.3 to 4.0.4 - -## [4.2.1](https://github.com/netlify/primitives/compare/dev-v4.2.0...dev-v4.2.1) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.14.4 to 2.14.5 - -## [4.2.0](https://github.com/netlify/primitives/compare/dev-v4.1.4...dev-v4.2.0) (2025-06-06) - - -### Features - -* image cdn support ([#232](https://github.com/netlify/primitives/issues/232)) ([01c844d](https://github.com/netlify/primitives/commit/01c844d82a27a9812be7634219d9bdc69a128985)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.5 to 9.1.6 - * @netlify/dev-utils bumped from 3.1.1 to 3.2.0 - * @netlify/edge-functions bumped from 2.14.3 to 2.14.4 - * @netlify/functions bumped from 4.1.3 to 4.1.4 - * @netlify/headers bumped from 2.0.1 to 2.0.2 - * @netlify/images bumped from 0.0.0 to 1.0.0 - * @netlify/redirects bumped from 3.0.1 to 3.0.2 - * @netlify/runtime bumped from 4.0.2 to 4.0.3 - * @netlify/static bumped from 3.0.1 to 3.0.2 - -## [4.1.4](https://github.com/netlify/primitives/compare/dev-v4.1.3...dev-v4.1.4) (2025-06-06) - - -### Bug Fixes - -* **deps:** update netlify packages ([#288](https://github.com/netlify/primitives/issues/288)) ([cdf9261](https://github.com/netlify/primitives/commit/cdf92610050cafb0c0967eee8bebe76f352ffdb5)) -* **deps:** update netlify packages ([#290](https://github.com/netlify/primitives/issues/290)) ([ca10da6](https://github.com/netlify/primitives/commit/ca10da69a916ef29bb6251822548f9dbefb58d06)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.14.2 to 2.14.3 - * @netlify/functions bumped from 4.1.2 to 4.1.3 - -## [4.1.3](https://github.com/netlify/primitives/compare/dev-v4.1.2...dev-v4.1.3) (2025-06-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.14.1 to 2.14.2 - * @netlify/runtime bumped from 4.0.1 to 4.0.2 - * devDependencies - * @netlify/types bumped from 2.0.1 to 2.0.2 - -## [4.1.2](https://github.com/netlify/primitives/compare/dev-v4.1.1...dev-v4.1.2) (2025-06-03) - - -### Bug Fixes - -* revamp dev and vite plugin logging ([#269](https://github.com/netlify/primitives/issues/269)) ([de9b46c](https://github.com/netlify/primitives/commit/de9b46c1cb1c7b2bf6437ab516134e44203d83b7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.4 to 9.1.5 - * @netlify/dev-utils bumped from 3.1.0 to 3.1.1 - * @netlify/edge-functions bumped from 2.14.0 to 2.14.1 - * @netlify/functions bumped from 4.1.1 to 4.1.2 - * @netlify/headers bumped from 2.0.0 to 2.0.1 - * @netlify/redirects bumped from 3.0.0 to 3.0.1 - * @netlify/runtime bumped from 4.0.0 to 4.0.1 - * @netlify/static bumped from 3.0.0 to 3.0.1 - -## [4.1.1](https://github.com/netlify/primitives/compare/dev-v4.1.0...dev-v4.1.1) (2025-06-03) - - -### Bug Fixes - -* add guard against query param handling ([#272](https://github.com/netlify/primitives/issues/272)) ([14dc44c](https://github.com/netlify/primitives/commit/14dc44c2d7ff97a6ed90c1afcc92d28ae7d6979d)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 4.1.0 to 4.1.1 - -## [4.1.0](https://github.com/netlify/primitives/compare/dev-v4.0.2...dev-v4.1.0) (2025-06-03) - - -### Features - -* accept `IncomingMessage` in handler ([#267](https://github.com/netlify/primitives/issues/267)) ([aa84022](https://github.com/netlify/primitives/commit/aa84022cf9ecb2258dce39b87b0a21ec73524914)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.13.2 to 2.14.0 - -## [4.0.2](https://github.com/netlify/primitives/compare/dev-v4.0.1...dev-v4.0.2) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.13.1 to 2.13.2 - -## [4.0.1](https://github.com/netlify/primitives/compare/dev-v4.0.0...dev-v4.0.1) (2025-06-02) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.13.0 to 2.13.1 - -## [4.0.0](https://github.com/netlify/primitives/compare/dev-v3.0.0...dev-v4.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Features - -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) -* improve error handling in edge functions ([#246](https://github.com/netlify/primitives/issues/246)) ([c0be696](https://github.com/netlify/primitives/commit/c0be6963c8bd9a49bb967040c29580e7facaae03)) -* print alert when using the Netlify Image CDN ([#255](https://github.com/netlify/primitives/issues/255)) ([e17dd37](https://github.com/netlify/primitives/commit/e17dd375b5aa2631b1bd10e63a7cfa9b2ec9aa96)) -* support multiple directories to serve static files ([#253](https://github.com/netlify/primitives/issues/253)) ([153f6ef](https://github.com/netlify/primitives/commit/153f6efda2e681d98753ebd7a1cb487ffc55560b)) - - -### Bug Fixes - -* **deps:** update netlify packages ([#236](https://github.com/netlify/primitives/issues/236)) ([630e675](https://github.com/netlify/primitives/commit/630e675822ece3d4bca58673b0a899f5a6c06bd9)) -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) -* improve static file handler ([#248](https://github.com/netlify/primitives/issues/248)) ([eb6c134](https://github.com/netlify/primitives/commit/eb6c134965a1653b3f3bebd9ec44df334589551e)) -* inject env vars even when unlinked ([#244](https://github.com/netlify/primitives/issues/244)) ([b19d790](https://github.com/netlify/primitives/commit/b19d7901f65360ae2ab72da0f4a56c77b03460da)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.3 to 9.1.4 - * @netlify/dev-utils bumped from 3.0.0 to 3.1.0 - * @netlify/edge-functions bumped from 2.12.0 to 2.13.0 - * @netlify/functions bumped from 4.0.0 to 4.1.0 - * @netlify/headers bumped from 1.0.0 to 2.0.0 - * @netlify/redirects bumped from 2.0.0 to 3.0.0 - * @netlify/runtime bumped from 3.0.0 to 4.0.0 - * @netlify/static bumped from 2.0.0 to 3.0.0 - * devDependencies - * @netlify/types bumped from 2.0.0 to 2.0.1 - -## [3.0.0](https://github.com/netlify/primitives/compare/dev-v2.3.1...dev-v3.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Features - -* add support for headers config ([#200](https://github.com/netlify/primitives/issues/200)) ([dca313e](https://github.com/netlify/primitives/commit/dca313ec82980231724a2d801bcc739df1d27924)) - - -### Bug Fixes - -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.2 to 9.1.3 - * @netlify/dev-utils bumped from 2.2.0 to 3.0.0 - * @netlify/functions bumped from 3.1.10 to 4.0.0 - * @netlify/headers bumped from 0.0.0 to 1.0.0 - * @netlify/redirects bumped from 1.1.4 to 2.0.0 - * @netlify/runtime bumped from 2.2.2 to 3.0.0 - * @netlify/static bumped from 1.1.4 to 2.0.0 - * devDependencies - * @netlify/types bumped from 1.2.0 to 2.0.0 - -## [2.3.1](https://github.com/netlify/primitives/compare/dev-v2.3.0...dev-v2.3.1) (2025-05-27) - - -### Bug Fixes - -* **deps:** update netlify packages ([#185](https://github.com/netlify/primitives/issues/185)) ([4608a20](https://github.com/netlify/primitives/commit/4608a20d3b9e62d5dad10c7c01963c1d68a8cd75)) -* pin monorepo packages ([#205](https://github.com/netlify/primitives/issues/205)) ([353a812](https://github.com/netlify/primitives/commit/353a81275dae3076465daf505c770a9218427376)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 3.1.9 to 3.1.10 - -## [2.3.0](https://github.com/netlify/primitives/compare/dev-v2.2.2...dev-v2.3.0) (2025-05-23) - - -### Features - -* add support for environment variables ([#197](https://github.com/netlify/primitives/issues/197)) ([03878db](https://github.com/netlify/primitives/commit/03878dbfff4e7e379b9d3e4fb6d9d783e66cc2af)) - - -### Bug Fixes - -* pass route to function invocation ([#202](https://github.com/netlify/primitives/issues/202)) ([7bb9396](https://github.com/netlify/primitives/commit/7bb939649dede2fae6642f724e3491dc598621b6)) -* use ephemeral directories to serve functions ([#199](https://github.com/netlify/primitives/issues/199)) ([a749e26](https://github.com/netlify/primitives/commit/a749e2600c1245dbe7f1401ebd020a862cb8f734)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.1 to ^9.1.2 - * @netlify/dev-utils bumped from 2.1.1 to 2.2.0 - * @netlify/functions bumped from 3.1.8 to 3.1.9 - * @netlify/redirects bumped from 1.1.3 to 1.1.4 - * @netlify/runtime bumped from 2.2.1 to 2.2.2 - * @netlify/static bumped from 1.1.3 to 1.1.4 - * devDependencies - * @netlify/types bumped from 1.1.1 to 1.2.0 - -## [2.2.2](https://github.com/netlify/primitives/compare/dev-v2.2.1...dev-v2.2.2) (2025-05-09) - - -### Bug Fixes - -* **deps:** update netlify packages ([#153](https://github.com/netlify/primitives/issues/153)) ([1fd1824](https://github.com/netlify/primitives/commit/1fd1824cd9f398921f006b0ccd538f371935d1fa)) -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.0 to 9.1.1 - * @netlify/dev-utils bumped from 2.1.0 to 2.1.1 - * @netlify/functions bumped from 3.1.7 to 3.1.8 - * @netlify/redirects bumped from 1.1.2 to 1.1.3 - * @netlify/runtime bumped from 2.2.0 to 2.2.1 - * @netlify/static bumped from 1.1.2 to 1.1.3 - * devDependencies - * @netlify/types bumped from 1.1.0 to 1.1.1 - -## [2.2.1](https://github.com/netlify/primitives/compare/dev-v2.2.0...dev-v2.2.1) (2025-05-09) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 3.1.6 to 3.1.7 - -## [2.2.0](https://github.com/netlify/primitives/compare/dev-v2.1.2...dev-v2.2.0) (2025-05-07) - - -### Features - -* add separate package for types ([#175](https://github.com/netlify/primitives/issues/175)) ([bb70188](https://github.com/netlify/primitives/commit/bb7018856ebda7a52ccff291cb306478e2853468)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.0.1 to 9.1.0 - * @netlify/functions bumped from 3.1.5 to 3.1.6 - * @netlify/runtime bumped from 2.1.1 to 2.2.0 - * devDependencies - * @netlify/types bumped from 1.0.0 to 1.1.0 - -## [2.1.2](https://github.com/netlify/primitives/compare/dev-v2.1.1...dev-v2.1.2) (2025-05-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime bumped from 2.1.0 to 2.1.1 - -## [2.1.1](https://github.com/netlify/primitives/compare/dev-v2.1.0...dev-v2.1.1) (2025-05-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 3.1.4 to 3.1.5 - -## [2.1.0](https://github.com/netlify/primitives/compare/dev-v2.0.0...dev-v2.1.0) (2025-05-06) - - -### Features - -* add Vite plugin ([#165](https://github.com/netlify/primitives/issues/165)) ([2ec775e](https://github.com/netlify/primitives/commit/2ec775e29be11138f77f8db73e2a3bcfdbe88934)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.0.0 to 9.0.1 - * @netlify/dev-utils bumped from 2.0.0 to 2.1.0 - * @netlify/functions bumped from 3.1.3 to 3.1.4 - * @netlify/redirects bumped from 1.1.1 to 1.1.2 - * @netlify/runtime bumped from 2.0.0 to 2.1.0 - * @netlify/static bumped from 1.1.1 to 1.1.2 - -## [2.0.0](https://github.com/netlify/primitives/compare/dev-v1.1.2...dev-v2.0.0) (2025-05-02) - - -### ⚠ BREAKING CHANGES - -* The `BlobsServer` class now only exports the `start()` and `stop()` methods. This class is not part of the Netlify Blobs client, and it's mostly used internally by Netlify tooling and by some users for integration tests — if you're just using the methods listed in https://docs.netlify.com/blobs/overview/#api-reference, this change does not apply to you and you can safely upgrade. - -### Features - -* add `start` entry point ([#154](https://github.com/netlify/primitives/issues/154)) ([b23c607](https://github.com/netlify/primitives/commit/b23c607ed3aa5e76279efa773b8c6c4d0dee972c)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 8.2.0 to 9.0.0 - * @netlify/dev-utils bumped from 1.1.0 to 2.0.0 - * @netlify/functions bumped from 3.1.2 to 3.1.3 - * @netlify/redirects bumped from 1.1.0 to 1.1.1 - * @netlify/runtime bumped from 1.0.0 to 2.0.0 - * @netlify/static bumped from 1.1.0 to 1.1.1 - -## [1.1.2](https://github.com/netlify/primitives/compare/dev-v1.1.1...dev-v1.1.2) (2025-04-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 3.1.1 to 3.1.2 - -## [1.1.1](https://github.com/netlify/primitives/compare/dev-v1.1.0...dev-v1.1.1) (2025-04-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 3.1.0 to 3.1.1 - -## [1.1.0](https://github.com/netlify/primitives/compare/dev-v1.0.0...dev-v1.1.0) (2025-04-16) - - -### Features - -* move primitives into monorepo ([#101](https://github.com/netlify/primitives/issues/101)) ([93b72b1](https://github.com/netlify/primitives/commit/93b72b1364022e45cbd87814dc6aa235f1e1c83e)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 1.0.0 to 1.1.0 - * @netlify/functions bumped from 2.8.2 to 3.1.0 - * @netlify/redirects bumped from 1.0.0 to 1.1.0 - * @netlify/static bumped from 1.0.0 to 1.1.0 diff --git a/packages/dev/README.md b/packages/dev/README.md deleted file mode 100644 index 05448d2..0000000 --- a/packages/dev/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# @netlify/dev - -`@netlify/dev` is a local emulator for the Netlify production environment. While it can be used directly by advanced -users, it is primarily designed as a foundational library for higher-level tools like the -[Netlify CLI](https://docs.netlify.com/cli/get-started/) and the -[Netlify Vite Plugin](https://docs.netlify.com/integrations/vite/overview/). - -It provides a local request pipeline that mimics the Netlify platform’s request handling, including support for -Functions, Blobs, Static files, Redirects, and Image CDN. - -## 📦 Installation - -```bash -npm install @netlify/dev -``` - -or - -```bash -yarn add @netlify/dev -``` - -## 🚀 Usage - -You can use `@netlify/dev` to emulate the Netlify runtime in your own development tooling or custom integrations: - -```ts -import { NetlifyDev } from '@netlify/dev' - -const devServer = new NetlifyDev({ - blobs: { enabled: true }, - edgeFunctions: { enabled: true }, - environmentVariables: { enabled: true }, - functions: { enabled: true }, - redirects: { enabled: true }, - staticFiles: { - enabled: true, - // OPTIONAL: additional directories containing static files to serve - // Your `projectRoot` (see below) and your site's `publish` dir are served by default - directories: ['public'], - }, - - // OPTIONAL: base dir (https://docs.netlify.com/configure-builds/overview/#definitions) - // Defaults to current working directory - projectRoot: 'site', - // OPTIONAL: if your local dev setup has its own HTTP server (e.g. Vite), set its address here - serverAddress: 'http://localhost:1234', -}) - -await devServer.start() - -const response = await devServer.handle(new Request('http://localhost:8888/path'), { - // An optional callback that will be called with every header (key and value) coming from header rules. - // See https://docs.netlify.com/routing/headers/ - headersCollector: (key: string, value: string) => console.log(key, value), -}) - -console.log(await response.text()) - -await devServer.stop() -``` - -## 🧪 Contributing and feedback - -This module is **experimental**, and we welcome feedback and contributions. Feel free to open issues or pull requests if -you encounter bugs or have suggestions. diff --git a/packages/dev/package.json b/packages/dev/package.json deleted file mode 100644 index d03e806..0000000 --- a/packages/dev/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@netlify/dev", - "version": "4.18.7", - "description": "Emulation of the Netlify environment for local development", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json" - }, - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/dev" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@netlify/api": "^14.0.18", - "@netlify/types": "2.8.0", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "@netlify/ai": "^0.4.1", - "@netlify/blobs": "10.7.9", - "@netlify/config": "^24.5.0", - "@netlify/database-dev": "0.10.1", - "@netlify/dev-utils": "4.4.6", - "@netlify/edge-functions-dev": "1.0.20", - "@netlify/functions-dev": "1.3.0", - "@netlify/headers": "2.1.11", - "@netlify/images": "1.3.10", - "@netlify/redirects": "3.1.13", - "@netlify/runtime": "4.1.25", - "@netlify/static": "3.1.10", - "ulid": "^3.0.0" - } -} diff --git a/packages/dev/src/lib/env.ts b/packages/dev/src/lib/env.ts deleted file mode 100644 index 344af49..0000000 --- a/packages/dev/src/lib/env.ts +++ /dev/null @@ -1,397 +0,0 @@ -import type { NetlifyAPI } from '@netlify/api' -import type { EnvironmentVariables } from '@netlify/types' - -export type EnvironmentVariableSource = 'account' | 'addons' | 'configFile' | 'general' | 'internal' | 'ui' - -/** - * Supported values for the user-provided env `context` option. - * These all match possible `context` values returned by the Envelope API. - * Note that a user may also specify a branch name with the special `branch:my-branch-name` format. - */ -export const SUPPORTED_CONTEXTS = ['all', 'production', 'deploy-preview', 'branch-deploy', 'dev', 'dev-server'] as const - -/** - * Additional aliases for the user-provided env `context` option. - */ -const SUPPORTED_CONTEXT_ALIASES = { - dp: 'deploy-preview', - prod: 'production', -} -/** - * Supported values for the user-provided env `scope` option. - * These exactly match possible `scope` values returned by the Envelope API. - * Note that `any` is also supported. - */ -export const ALL_ENVELOPE_SCOPES = ['builds', 'functions', 'runtime', 'post_processing'] as const - -export type EnvironmentVariable = { - sources: EnvironmentVariableSource[] - value: string - scopes?: (typeof ALL_ENVELOPE_SCOPES)[] -} - -export type InjectedEnvironmentVariable = { - isInternal: boolean - originalValue: string | undefined - overriddenSources: string[] - usedSource: string - value: string -} - -interface InjectEnvironmentVariablesOptions { - accountSlug?: string - baseVariables: Record - envAPI: EnvironmentVariables - netlifyAPI?: NetlifyAPI - siteID?: string -} - -/** - * Inject user-defined environment variables (from various sources, see `@netlify/config`) - * into the provided `envAPI` (which may be a proxy to `process.env`, affecting the current proc), - * if `siteID` and `accountSlug` are provided. - * @see {@link https://github.com/netlify/build/blob/8b7583e1890636bd64b54e20aee40ae5365edeaf/packages/config/src/env/main.ts#L92} - * - * This also injects and returns the documented runtime env vars: - * @see {@link https://docs.netlify.com/functions/environment-variables/#functions} - * - * @return Metadata about all injected environment variables - */ -export const injectEnvVariables = async ({ - accountSlug, - baseVariables = {}, - envAPI, - netlifyAPI, - siteID, -}: InjectEnvironmentVariablesOptions) => { - const results: Record = {} - - let variables = baseVariables - - if (netlifyAPI && siteID && accountSlug) { - variables = await getEnvelopeEnv({ - accountId: accountSlug, - api: netlifyAPI, - env: baseVariables, - siteId: siteID, - }) - } - - // Inject env vars which come from multiple `source`s and have been collected from - // `@netlify/config` and/or Envelope. These have not been populated on the actual env yet. - for (const [key, variable] of Object.entries(variables)) { - const existsInProcess = envAPI.has(key) - const [usedSource, ...overriddenSources] = existsInProcess ? ['process', ...variable.sources] : variable.sources - const isInternal = variable.sources.includes('internal') - const result: InjectedEnvironmentVariable = { - isInternal, - originalValue: envAPI.get(key), - overriddenSources, - usedSource, - value: variable.value, - } - - if (!existsInProcess || isInternal) { - envAPI.set(key, variable.value) - } - - results[key] = result - } - - return results -} - -// TODO(serhalp) Netlify API is incorrect - the returned scope is `post_processing`, not `post-processing` -type EnvelopeEnvVarScope = - | Exclude>[number]['scopes']>[number], 'post-processing'> - | 'post_processing' -type EnvelopeEnvVar = Awaited>[number] & { - scopes: EnvelopeEnvVarScope[] -} -type EnvelopeEnvVarContext = NonNullable[number]['context']> -export type EnvelopeEnvVarValue = { - /** - * The deploy context of the this env var value - */ - context?: EnvelopeEnvVarContext - /** - * For parameterized contexts (i.e. only `branch`), context parameter (i.e. the branch name) - */ - context_parameter?: string | undefined - /** - * The value of the environment variable for this context. Note that this appears to be an empty string - * when the env var is not set for this context. - */ - value?: string | undefined -} - -export type EnvelopeItem = { - // FIXME(serhalp) Netlify API types claim this is optional. Investigate and fix here or there. - key: string - scopes: EnvelopeEnvVarScope[] - values: EnvelopeEnvVarValue[] -} - -// AFAICT, Envelope uses only `post_processing` on returned env vars; the CLI documents and expects -// only `post-processing` as a valid user-provided scope; the code handles both everywhere. Consider -// explicitly normalizing and dropping undocumented support for user-provided `post_processing`. -type SupportedScope = EnvelopeEnvVarScope | 'post_processing' | 'any' - -type ContextOrBranch = string - -/** - * Normalizes a user-provided "context". Note that this may be the special `branch:my-branch-name` format. - * - * - If this is a supported alias of a context, it will be normalized to the canonical context. - * - Valid canonical contexts are returned as is. - * - If this starts with `branch:`, it will be normalized to the branch name. - * - * @param context A user-provided context, context alias, or a string in the `branch:my-branch-name` format. - * - * @returns The normalized context name or just the branch name - */ -export const normalizeContext = (context: string): ContextOrBranch => { - if (!context) { - return context - } - - context = context.toLowerCase() - if (context in SUPPORTED_CONTEXT_ALIASES) { - context = SUPPORTED_CONTEXT_ALIASES[context as keyof typeof SUPPORTED_CONTEXT_ALIASES] - } - const forbiddenContexts = SUPPORTED_CONTEXTS.map((ctx) => `branch:${ctx}`) - if (forbiddenContexts.includes(context)) { - throw new Error(`The context ${context} includes a reserved keyword and is not allowed`) - } - return context.replace(/^branch:/, '') -} - -/** - * Finds a matching environment variable value for a given context - * @private - */ -export const getValueForContext = ( - /** - * An array of environment variable values from Envelope - */ - values: EnvelopeEnvVarValue[], - /** - * The deploy context or branch of the environment variable value - */ - contextOrBranch: ContextOrBranch, -): EnvelopeEnvVarValue | undefined => { - const isSupportedContext = (SUPPORTED_CONTEXTS as readonly string[]).includes(contextOrBranch) - if (!isSupportedContext) { - const valueMatchingAsBranch = values.find((val) => val.context_parameter === contextOrBranch) - // This is a `branch` context, which is an override, so it takes precedence - if (valueMatchingAsBranch != null) { - return valueMatchingAsBranch - } - const valueMatchingContext = values.find((val) => val.context === 'all' || val.context === 'branch-deploy') - return valueMatchingContext ?? undefined - } - const valueMatchingAsContext = values.find((val) => val.context === 'all' || val.context === contextOrBranch) - return valueMatchingAsContext ?? undefined -} - -/** - * Finds environment variables that match a given source - * @param env - The dictionary of environment variables - * @param source - The source of the environment variable - * @returns The dictionary of env vars that match the given source - */ -export const filterEnvBySource = ( - env: Record, - source: EnvironmentVariableSource, -): typeof env => Object.fromEntries(Object.entries(env).filter(([, variable]) => variable.sources[0] === source)) - -const fetchEnvelopeItems = async function ({ - accountId, - api, - key, - siteId, -}: { - accountId: string - api: NetlifyAPI - key: string - siteId?: string | undefined -}): Promise { - if (accountId === undefined) { - return [] - } - try { - // if a single key is passed, fetch that single env var - if (key) { - const envelopeItem = await api.getEnvVar({ accountId, key, siteId }) - // See FIXME(serhalp) above - return [envelopeItem as EnvelopeItem] - } - // otherwise, fetch the entire list of env vars - const envelopeItems = await api.getEnvVars({ accountId, siteId }) - // See FIXME(serhalp) above - return envelopeItems as EnvelopeItem[] - } catch { - // Collaborators aren't allowed to read shared env vars, - // so return an empty array silently in that case - return [] - } -} - -/** - * Filters and sorts data from Envelope by a given context and/or scope - * @param context - The deploy context or branch of the environment variable value - * @param envelopeItems - An array of environment variables from the Envelope service - * @param scope - The scope of the environment variables - * @param source - The source of the environment variable - * @returns A dicionary in the following format: - * { - * FOO: { - * context: 'dev', - * scopes: ['builds', 'functions'], - * sources: ['ui'], - * value: 'bar', - * }, - * BAZ: { - * context: 'branch', - * branch: 'staging', - * scopes: ['runtime'], - * sources: ['account'], - * value: 'bang', - * }, - * } - */ -export const formatEnvelopeData = ({ - context = 'dev', - envelopeItems = [], - scope = 'any', - source, -}: { - context?: ContextOrBranch - envelopeItems: EnvelopeItem[] - scope?: SupportedScope - source: string -}): Record< - string, - { - context: ContextOrBranch - branch: string | undefined - scopes: string[] - sources: string[] - value: string - } -> => - envelopeItems - // filter by context - .filter(({ values }) => Boolean(getValueForContext(values, context))) - // filter by scope - .filter(({ scopes }) => (scope === 'any' ? true : scopes.includes(scope))) - // sort alphabetically, case insensitive - .sort((left, right) => (left.key.toLowerCase() < right.key.toLowerCase() ? -1 : 1)) - // format the data - .reduce((acc, cur) => { - const val = getValueForContext(cur.values, context) - if (val === undefined) { - throw new TypeError(`failed to locate environment variable value for ${context} context`) - } - const { context: itemContext, context_parameter: branch, value } = val - return { - ...acc, - [cur.key]: { - context: itemContext, - branch, - scopes: cur.scopes, - sources: [source], - value, - }, - } - }, {}) - -/** - * Collects env vars from multiple sources and arranges them in the correct order of precedence - * - * @returns An object of environment variables keys and their metadata - */ -const getEnvelopeEnv = async ({ - accountId, - api, - context = 'dev', - env, - key = '', - raw = false, - scope = 'any', - siteId, -}: { - accountId: string - api: NetlifyAPI - context?: ContextOrBranch | undefined - env: Record - key?: string | undefined - raw?: boolean | undefined - scope?: SupportedScope | undefined - siteId: string -}) => { - const [accountEnvelopeItems, siteEnvelopeItems] = await Promise.all([ - fetchEnvelopeItems({ api, accountId, key }), - fetchEnvelopeItems({ api, accountId, key, siteId }), - ]) - - const accountEnv = formatEnvelopeData({ context, envelopeItems: accountEnvelopeItems, scope, source: 'account' }) - const siteEnv = formatEnvelopeData({ context, envelopeItems: siteEnvelopeItems, scope, source: 'ui' }) - - if (raw) { - const entries = Object.entries({ ...accountEnv, ...siteEnv }) - return entries.reduce( - (obj, [envVarKey, metadata]) => ({ - ...obj, - [envVarKey]: metadata.value, - }), - {}, - ) - } - - const generalEnv = filterEnvBySource(env, 'general') - const internalEnv = filterEnvBySource(env, 'internal') - const addonsEnv = filterEnvBySource(env, 'addons') - const configFileEnv = filterEnvBySource(env, 'configFile') - - // filter out configFile env vars if a non-configFile scope is passed - const includeConfigEnvVars = /any|builds|post[-_]processing/.test(scope) - - // Sources of environment variables, in ascending order of precedence. - return { - ...generalEnv, - ...accountEnv, - ...(includeConfigEnvVars ? addonsEnv : {}), - ...siteEnv, - ...(includeConfigEnvVars ? configFileEnv : {}), - ...internalEnv, - } -} - -/** - * Returns a human-readable, comma-separated list of scopes - * @param scopes An array of scopes - * @returns A human-readable, comma-separated list of scopes - */ -export const getHumanReadableScopes = (scopes?: EnvelopeEnvVarScope[]): string => { - const HUMAN_SCOPES = ['Builds', 'Functions', 'Runtime', 'Post processing'] - const SCOPES_MAP = { - builds: HUMAN_SCOPES[0], - functions: HUMAN_SCOPES[1], - runtime: HUMAN_SCOPES[2], - post_processing: HUMAN_SCOPES[3], - // TODO(serhalp) I believe this isn't needed, as `post-processing` is a user-provided - // CLI option, not a scope returned by the Envelope API. - 'post-processing': HUMAN_SCOPES[3], - } - if (!scopes) { - // if `scopes` is not available, the env var comes from netlify.toml - // env vars specified in netlify.toml are present in the `builds` and `post_processing` scope - return 'Builds, Post processing' - } - if (scopes.length === Object.keys(HUMAN_SCOPES).length) { - // shorthand instead of listing every available scope - return 'All' - } - return scopes.map((scope) => SCOPES_MAP[scope]).join(', ') -} diff --git a/packages/dev/src/lib/fs.ts b/packages/dev/src/lib/fs.ts deleted file mode 100644 index 7741b91..0000000 --- a/packages/dev/src/lib/fs.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { promises as fs } from 'node:fs' - -export const isDirectory = async (path: string) => { - try { - const stat = await fs.stat(path) - - return stat.isDirectory() - } catch { - // no-op - } - - return false -} - -export const isFile = async (path: string) => { - try { - const stat = await fs.stat(path) - - return stat.isFile() - } catch { - // no-op - } - - return false -} diff --git a/packages/dev/src/lib/reqres.ts b/packages/dev/src/lib/reqres.ts deleted file mode 100644 index 602df1e..0000000 --- a/packages/dev/src/lib/reqres.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { IncomingMessage } from 'node:http' -import { Readable } from 'node:stream' - -export const normalizeHeaders = (request: IncomingMessage) => { - const result: [string, string][] = [] - let headers = request.headers - - // Handle HTTP/2 pseudo-headers: https://www.rfc-editor.org/rfc/rfc9113.html#name-request-pseudo-header-field - // In certain versions of Node.js, the built-in `Request` constructor from undici throws - // if a header starts with a colon. - if (request.httpVersionMajor >= 2) { - headers = { ...headers } - delete headers[':authority'] - delete headers[':method'] - delete headers[':path'] - delete headers[':scheme'] - } - - for (const [key, value] of Object.entries(headers)) { - if (Array.isArray(value)) { - result.push([key, value.join(',')]) - } else if (typeof value === 'string') { - result.push([key, value]) - } - } - - return result -} - -export const getNormalizedRequest = (input: Request, requestID: string, removeBody?: boolean) => { - const method = input.method.toUpperCase() - const headers = input.headers - headers.set('x-nf-request-id', requestID) - - return new Request(input.url, { - body: method === 'GET' || method === 'HEAD' || removeBody ? null : input.body, - // @ts-expect-error Not typed! - duplex: 'half', - headers, - method, - }) -} - -export const getNormalizedRequestFromNodeRequest = ( - input: IncomingMessage, - requestID: string, - removeBody?: boolean, -) => { - const { headers, url = '' } = input - const origin = `http://${headers.host ?? 'localhost'}` - const fullUrl = new URL(url, origin) - const method = input.method?.toUpperCase() ?? 'GET' - const body = - input.method === 'GET' || input.method === 'HEAD' || removeBody - ? null - : (Readable.toWeb(input) as unknown as ReadableStream) - - const normalizedHeaders = normalizeHeaders(input) - normalizedHeaders.push(['x-nf-request-id', requestID]) - - return new Request(fullUrl, { - body, - // @ts-expect-error Not typed! - duplex: 'half', - headers: normalizedHeaders, - method, - }) -} diff --git a/packages/dev/src/lib/request_id.ts b/packages/dev/src/lib/request_id.ts deleted file mode 100644 index e5752ee..0000000 --- a/packages/dev/src/lib/request_id.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ulid } from 'ulid' - -export const generateRequestID = () => ulid() diff --git a/packages/dev/src/lib/runtime.ts b/packages/dev/src/lib/runtime.ts deleted file mode 100644 index 9ea5db9..0000000 --- a/packages/dev/src/lib/runtime.ts +++ /dev/null @@ -1,81 +0,0 @@ -import path from 'node:path' -import process from 'node:process' - -import { BlobsServer } from '@netlify/blobs/server' -import { startRuntime } from '@netlify/runtime' -import type { NetlifyGlobal } from '@netlify/types' - -interface GetRuntimeOptions { - blobs: boolean - blobsToken?: string - deployID: string - projectRoot: string - siteID: string -} - -const restoreEnvironment = (snapshot: Record) => { - for (const key in snapshot) { - if (snapshot[key] === undefined) { - delete process.env[key] - } else { - process.env[key] = snapshot[key] - } - } -} - -export const getRuntime = async ({ blobs, deployID, projectRoot, siteID }: GetRuntimeOptions) => { - const blobsToken = Math.random().toString().slice(2) - const blobsServer = blobs - ? new BlobsServer({ - directory: path.join(projectRoot, '.netlify', 'blobs-serve'), - token: blobsToken, - }) - : null - const blobsServerDetails = await blobsServer?.start() - - const envSnapshot: Record = {} - const env: NetlifyGlobal['env'] = { - delete: (key: string) => { - envSnapshot[key] = envSnapshot[key] || process.env[key] - - delete process.env[key] - }, - get: (key: string) => process.env[key], - has: (key: string) => Boolean(process.env[key]), - set: (key: string, value: string) => { - envSnapshot[key] = envSnapshot[key] || process.env[key] - - process.env[key] = value - }, - toObject: () => process.env as Record, - } - - startRuntime({ - blobs: blobsServerDetails - ? { - edgeURL: `http://localhost:${blobsServerDetails.port}`, - uncachedEdgeURL: `http://localhost:${blobsServerDetails.port}`, - primaryRegion: 'us-east-2', - token: blobsToken, - } - : undefined, - cache: { - getCacheAPIContext: () => null, - purgeToken: '', - }, - deployID, - env, - getRequestContext: () => null, - siteID, - }) - - return { - env, - envSnapshot, - stop: async () => { - restoreEnvironment(envSnapshot) - - await blobsServer?.stop() - }, - } -} diff --git a/packages/dev/src/main.test.ts b/packages/dev/src/main.test.ts deleted file mode 100644 index 4f3db88..0000000 --- a/packages/dev/src/main.test.ts +++ /dev/null @@ -1,1109 +0,0 @@ -import { readFile } from 'node:fs/promises' -import { IncomingMessage } from 'node:http' -import { Socket } from 'node:net' -import { resolve } from 'node:path' - -import { createImageServerHandler, Fixture, generateImage, getImageResponseSize, HTTPServer } from '@netlify/dev-utils' -import { afterEach, describe, expect, test, vi } from 'vitest' - -import { isFile } from './lib/fs.js' -import { NetlifyDev } from './main.js' - -import { withMockApi } from '../test/mock-api.js' - -describe('Handling requests', () => { - afterEach(() => { - vi.unstubAllEnvs() - }) - - test('Handles HTTP/2 Node.js requests', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/index.html', 'Hello from static file') - const directory = await fixture.create() - const dev = new NetlifyDev({ - projectRoot: directory, - geolocation: { enabled: false }, - }) - await dev.start() - - const nodeReq = new IncomingMessage(new Socket()) - nodeReq.httpVersionMajor = 2 - nodeReq.httpVersionMinor = 0 - nodeReq.method = 'GET' - nodeReq.url = '/index.html' - nodeReq.headers = { - accept: 'text/html', - host: 'example.netlify.app', - 'user-agent': 'test-agent', - // These four HTTP/2 pseudo request headers are required per the HTTP/2 spec: - // https://www.rfc-editor.org/rfc/rfc9113.html#name-request-pseudo-header-field - // These show up here like any other header on Node.js IncomingMessage objects, - ':method': 'GET', - ':path': '/index.html', - ':scheme': 'https', - ':authority': 'example.netlify.app', - } - const result = await dev.handleAndIntrospectNodeRequest(nodeReq) - - expect(result?.response.ok).toBe(true) - expect(await result?.response.text()).toBe('Hello from static file') - - await dev.stop() - await fixture.destroy() - }) - - describe('No linked site', () => { - test('Same-site rewrite to a static file', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/_redirects', `/from /to 200`) - .withFile('public/to.html', `to.html`) - const directory = await fixture.create() - const req = new Request('https://site.netlify/from') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - await dev.stop() - - expect(await res?.text()).toBe('to.html') - - await fixture.destroy() - }) - - test('Same-site rewrite to a static file (shadowed)', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/_redirects', `/from /to 200`) - .withFile('public/from.html', `from.html`) - .withFile('public/to.html', `to.html`) - const directory = await fixture.create() - const req = new Request('https://site.netlify/from') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - await dev.stop() - - expect(await res?.text()).toBe('from.html') - - await fixture.destroy() - }) - - test('Same-site rewrite to a static file (forced)', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/_redirects', `/from /to 200!`) - .withFile('public/from.html', `from.html`) - .withFile('public/to.html', `to.html`) - const directory = await fixture.create() - const req = new Request('https://site.netlify/from') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - await dev.stop() - - expect(await res?.text()).toBe('to.html') - - await fixture.destroy() - }) - - test('Headers rules matching a static file are applied', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - [[headers]] - for = "/hello.txt" - [headers.values] - "Vary" = "User-Agent" - `, - ) - .withHeadersFile({ - pathPrefix: 'public', - headers: [{ path: '/hello.txt', headers: ['Cache-Control: max-age=42'] }], - }) - .withFile('public/hello.txt', 'Hello from hello.txt') - .withFile('public/another-path.txt', 'Hello from another-path.txt') - const directory = await fixture.create() - const req = new Request('https://site.netlify/hello.txt') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - await dev.start() - - const matchRes = await dev.handle(req) - - await dev.stop() - - expect(await matchRes?.text()).toBe('Hello from hello.txt') - expect(Object.fromEntries(matchRes?.headers.entries() ?? [])).toMatchObject({ - 'cache-control': 'max-age=42', - vary: 'User-Agent', - }) - - const noMatchRes = await dev.handle(new Request('https://site.netlify/another-path.txt')) - expect(await noMatchRes?.text()).toBe('Hello from another-path.txt') - expect(Object.fromEntries(noMatchRes?.headers.entries() ?? [])).not.toMatchObject({ - 'cache-control': 'max-age=42', - vary: 'User-Agent', - }) - - await fixture.destroy() - }) - - test('Headers rules matching target of a rewrite to a static file are applied', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - [[headers]] - for = "/from" - [headers.values] - "X-Custom" = "value for from rule" - "X-Custom-From" = "another value for from rule" - [[headers]] - for = "/to.txt" - [headers.values] - "X-Custom" = "value for to rule" - `, - ) - .withFile('public/_redirects', `/from /to.txt 200`) - .withFile('public/to.txt', `to.txt content`) - const directory = await fixture.create() - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - await dev.start() - - const directRes = await dev.handle(new Request('https://site.netlify/to.txt')) - expect(await directRes?.text()).toBe('to.txt content') - expect(directRes?.headers.get('X-Custom')).toBe('value for to rule') - expect(directRes?.headers.get('X-Custom-From')).toBeNull() - - const rewriteRes = await dev.handle(new Request('https://site.netlify/from')) - expect(await rewriteRes?.text()).toBe('to.txt content') - expect(rewriteRes?.headers.get('X-Custom')).toBe('value for to rule') - expect(rewriteRes?.headers.get('X-Custom-From')).toBeNull() - - await dev.stop() - await fixture.destroy() - }) - - test('Headers rules matching a static file that shadows a function are applied', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - [[headers]] - for = "/shadowed-path.html" - [headers.values] - "X-Custom-Header" = "custom-value" - `, - ) - .withFile('public/shadowed-path.html', 'Hello from the static file') - .withFile( - 'netlify/functions/shadowed-path.mjs', - `export default async () => new Response("Hello from the function"); - export const config = { path: "/shadowed-path.html", preferStatic: true }; - `, - ) - const directory = await fixture.create() - const req = new Request('https://site.netlify/shadowed-path.html') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - await dev.start() - - const res = await dev.handle(req) - expect(await res?.text()).toBe('Hello from the static file') - expect(Object.fromEntries(res?.headers.entries() ?? [])).toMatchObject({ - 'x-custom-header': 'custom-value', - }) - - await dev.stop() - await fixture.destroy() - }) - - test('Headers rules matching an unshadowed function on a custom path are not applied', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - [[headers]] - for = "/hello.html" - [headers.values] - "X-Custom-Header" = "custom-value" - `, - ) - .withFile('public/hello.html', 'Hello from the static file') - .withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Hello from the function"); - export const config = { path: "/hello.html" }; - `, - ) - const directory = await fixture.create() - const req = new Request('https://site.netlify/hello.html') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - await dev.start() - - const res = await dev.handle(req) - expect(await res?.text()).toBe('Hello from the function') - expect(res?.headers.get('x-custom-header')).toBeNull() - - await dev.stop() - await fixture.destroy() - }) - - // TODO(FRB-1834): Implement this test when edge functions are supported - test.todo('Headers rules matching a path are not applied to edge function responses') - - test('Invoking a function, updating its contents and invoking it again', async () => { - let fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/hello.html', `hello.html`) - .withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Hello from function"); export const config = { path: "/hello" };`, - ) - const directory = await fixture.create() - const req = new Request('https://site.netlify/hello?param1=value1') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res1 = await dev.handle(req) - - expect(await res1?.text()).toBe('Hello from function') - - fixture = fixture.withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("A new hello from function"); export const config = { path: "/hello" };`, - ) - - await fixture.create() - - const res2 = await dev.handle(req) - - expect(await res2?.text()).toBe('A new hello from function') - - await dev.stop() - await fixture.destroy() - }) - - test('Invoking a function on a custom path, shadowed by a static file', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/hello.html', `hello.html`) - .withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Hello from function"); export const config = { path: "/hello", preferStatic: true };`, - ) - const directory = await fixture.create() - const req = new Request('https://site.netlify/hello') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - expect(await res?.text()).toBe('hello.html') - - await dev.stop() - await fixture.destroy() - }) - - test('Rewrite to a function on a custom path', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile('public/_redirects', `/from /hello 200!`) - .withFile('public/hello.html', `hello.html`) - .withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Hello from function"); export const config = { path: "/hello" };`, - ) - const directory = await fixture.create() - const req = new Request('https://site.netlify/from') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - expect(await res?.text()).toBe('Hello from function') - - await dev.stop() - await fixture.destroy() - }) - - test('Invoking a function that interacts with Blobs', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/functions/hello.mjs', - `import { getStore } from "@netlify/blobs"; - export default async () => { - const store = getStore("my-store"); - - await store.set("my-key", "Hello from blob"); - - const value = await store.get("my-key"); - - return new Response(value); - }; - export const config = { path: "/hello" };`, - ) - .withFile( - '.gitignore', - `# Some comment - dir1/ - !dir1/foo`, - ) - .withPackages({ - '@netlify/blobs': '8.2.0', - }) - const directory = await fixture.create() - - const gitIgnorePath = resolve(directory, '.gitignore') - expect(await isFile(gitIgnorePath)).toBe(true) - - const gitIgnoresPre = (await readFile(gitIgnorePath, 'utf8')).split('\n').map((line) => line.trim()) - expect(gitIgnoresPre).toContain('# Some comment') - expect(gitIgnoresPre).toContain('dir1/') - expect(gitIgnoresPre).toContain('!dir1/foo') - - const req = new Request('https://site.netlify/hello') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - expect(await res?.text()).toBe('Hello from blob') - - const gitIgnoresPost = (await readFile(gitIgnorePath, 'utf8')).split('\n').map((line) => line.trim()) - expect(gitIgnoresPost).toContain('# Some comment') - expect(gitIgnoresPost).toContain('dir1/') - expect(gitIgnoresPost).toContain('!dir1/foo') - expect(gitIgnoresPost).toContain('# Local Netlify folder') - expect(gitIgnoresPost).toContain('.netlify') - - await dev.stop() - await fixture.destroy() - }) - - test.todo('Invoking a function that interacts with the Cache API', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/functions/hello.mjs', - `export default async () => { - const cache = await caches.open("my-cache"); - - await cache.put("https://example.com", new Response("Cached response")); - - return new Response("Hello world"); - }; - export const config = { path: "/hello" };`, - ) - const directory = await fixture.create() - const req = new Request('https://site.netlify/hello') - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - expect(await res?.text()).toBe('Hello world') - - await dev.stop() - await fixture.destroy() - }) - - test('Image CDN requests are supported', async () => { - const IMAGE_WIDTH = 800 - const IMAGE_HEIGHT = 400 - - const remoteServer = new HTTPServer( - createImageServerHandler(() => { - return { width: IMAGE_WIDTH, height: IMAGE_HEIGHT } - }), - ) - - const remoteServerAddress = await remoteServer.start() - - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[images] - remote_images = [ - "^${remoteServerAddress}/allowed/.*" - ] - - [[redirects]] - from = "/image-cdn-rewrite" - to = "/.netlify/images?url=:url&w=:width" - status = 200 - - [redirects.query] - url = ":url" - w = ":width"`, - ) - .withFile('local/image.jpg', await generateImage(IMAGE_WIDTH, IMAGE_HEIGHT)) - - const directory = await fixture.create() - - const dev = new NetlifyDev({ - projectRoot: directory, - edgeFunctions: { - // disable edge functions to avoid relying on edge functions handling spinning up internal server - // for local images - enabled: false, - }, - images: { - remoteURLPatterns: [`^${remoteServerAddress}/allowed-via-option/.*`], - }, - }) - - await dev.start() - - const localImageRequest = new Request( - `https://site.netlify/.netlify/images?url=${encodeURIComponent('local/image.jpg')}&w=100`, - ) - const localImageResponse = await dev.handle(localImageRequest) - expect(localImageResponse?.ok).toBe(true) - expect(localImageResponse?.headers.get('content-type')).toMatch(/^image\//) - expect(await getImageResponseSize(localImageResponse ?? new Response('No @netlify/dev response'))).toMatchObject({ - width: 100, - height: 50, - }) - - const allowedRemoteImageRequest = new Request( - `https://site.netlify/.netlify/images?url=${encodeURIComponent(`${remoteServerAddress}/allowed/image`)}&w=100`, - ) - const allowedRemoteImageResponse = await dev.handle(allowedRemoteImageRequest) - expect(allowedRemoteImageResponse?.ok).toBe(true) - expect(allowedRemoteImageResponse?.headers.get('content-type')).toMatch(/^image\//) - expect( - await getImageResponseSize(allowedRemoteImageResponse ?? new Response('No @netlify/dev response')), - ).toMatchObject({ width: 100, height: 50 }) - - const allowedRemoteImage2Request = new Request( - `https://site.netlify/.netlify/images?url=${encodeURIComponent(`${remoteServerAddress}/allowed-via-option/image`)}&w=100`, - ) - const allowedRemoteImage2Response = await dev.handle(allowedRemoteImage2Request) - expect(allowedRemoteImage2Response?.ok).toBe(true) - expect(allowedRemoteImage2Response?.headers.get('content-type')).toMatch(/^image\//) - expect( - await getImageResponseSize(allowedRemoteImage2Response ?? new Response('No @netlify/dev response')), - ).toMatchObject({ width: 100, height: 50 }) - - const notAllowedRemoteImageRequest = new Request( - `https://site.netlify/.netlify/images?url=${encodeURIComponent(`${remoteServerAddress}/not-allowed/image`)}&w=100`, - ) - const notAllowedRemoteImageResponse = await dev.handle(notAllowedRemoteImageRequest) - expect(notAllowedRemoteImageResponse?.status).toBe(403) - - const rewriteImageRequest = new Request( - `https://site.netlify/image-cdn-rewrite?url=${encodeURIComponent('local/image.jpg')}&w=100`, - ) - const rewriteImageResponse = await dev.handle(rewriteImageRequest) - expect(rewriteImageResponse?.ok).toBe(true) - expect(rewriteImageResponse?.headers.get('content-type')).toMatch(/^image\//) - expect( - await getImageResponseSize(rewriteImageResponse ?? new Response('No @netlify/dev response')), - ).toMatchObject({ width: 100, height: 50 }) - - await remoteServer.stop() - await dev.stop() - await fixture.destroy() - }) - - test('Invoking an edge function', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - [context.dev.environment] - MY_TOKEN = "value from dev context" - [context.deploy-preview.environment] - MY_OTHER_TOKEN = "value from deploy preview context" - `, - ) - .withFile( - 'netlify/functions/hello.mjs', - `export default async (req, context) => new Response("Hello from function"); - - export const config = { path: "/hello/:a/*" };`, - ) - .withFile( - 'netlify/edge-functions/passthrough.mjs', - `export default async (req, context) => { - const res = await context.next(); - const text = await res.text(); - - return new Response(text.toUpperCase(), res); - }; - - export const config = { path: "/hello/passthrough/*" };`, - ) - .withFile( - 'netlify/edge-functions/terminate.mjs', - `export default async (req, context) => Response.json({ - runtimeEnv: { - NETLIFY_BLOBS_CONTEXT: Netlify.env.get("NETLIFY_BLOBS_CONTEXT"), - }, - platformEnv: { - DEPLOY_ID: Netlify.env.get("DEPLOY_ID"), - }, - configEnv: { - MY_TOKEN: Netlify.env.get("MY_TOKEN"), - MY_OTHER_TOKEN: Netlify.env.get("MY_OTHER_TOKEN"), - }, - parentProcessEnv: { - SOME_ZSH_THING_MAYBE: Netlify.env.get("SOME_ZSH_THING_MAYBE"), - }, - geo: context.geo, - params: context.params, - path: context.path, - server: context.server, - site: context.site, - url: context.url, - }); - - export const config = { path: "/hello/terminate/*" };`, - ) - .withFile( - 'netlify/edge-functions/bodyless-response.mjs', - `export default async (req, context) => { - return new Response(null, { status: 304 }); - }; - - export const config = { path: "/bodyless-response" };`, - ) - const directory = await fixture.create() - - vi.stubEnv('SOME_ZSH_THING_MAYBE', 'value on developer machine') - - const dev = new NetlifyDev({ - apiToken: 'token', - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - const { serverAddress } = await dev.start() - - const req1 = new Request('https://site.netlify/hello/passthrough/two/three') - const res1 = await dev.handle(req1) - - expect(await res1?.text()).toBe('HELLO FROM FUNCTION') - - const req2 = new Request('https://site.netlify/hello/terminate/two/three') - const res2 = await dev.handle(req2) - const req2URL = new URL('/hello/terminate/two/three', serverAddress) - - expect(await res2?.json()).toStrictEqual({ - // Env vars emulating the EF runtime are present - runtimeEnv: { - NETLIFY_BLOBS_CONTEXT: expect.stringMatching(/\w+/) as unknown, - }, - // Env vars emulating the EF runtime are present - // Note that these originate from `@netlify/config` - platformEnv: { - DEPLOY_ID: '0', - }, - // Envs var set in `netlify.toml` for `dev` context only are passed to EFs - configEnv: { - MY_TOKEN: 'value from dev context', - // MY_OTHER_TOKEN is not present - }, - parentProcessEnv: { - // SOME_ZSH_THING_MAYBE is not present - }, - - geo: { - city: 'San Francisco', - country: { - code: 'US', - name: 'United States', - }, - latitude: 0, - longitude: 0, - subdivision: { - code: 'CA', - name: 'California', - }, - timezone: 'UTC', - }, - params: { - '0': 'two/three', - }, - server: { - region: 'dev', - }, - site: { - url: serverAddress, - }, - url: req2URL.toString(), - }) - - const req3 = new Request('https://site.netlify/bodyless-response') - const res3 = await dev.handle(req3) - - expect(res3?.status).toBe(304) - - await dev.stop() - await fixture.destroy() - }) - }) - - describe('With linked site', () => { - const siteInfo = { - id: 'site_id', - name: 'site-name', - account_slug: 'test-account', - build_settings: { env: {} }, - } - const routes = [ - { path: 'sites/site_id', response: siteInfo }, - { path: 'sites/site_id/service-instances', response: [] }, - { - path: 'accounts', - response: [{ slug: siteInfo.account_slug }], - }, - { - path: 'accounts/test-account/env', - response: [ - { - key: 'WITH_DEV_OVERRIDE', - scopes: ['builds', 'functions', 'runtime'], - values: [ - { context: 'dev' as const, value: 'value from dev context' }, - { context: 'production' as const, value: 'value from production context' }, - { context: 'all' as const, value: 'value from all context' }, - ], - }, - { - key: 'WITHOUT_DEV_OVERRIDE', - scopes: ['builds', 'functions', 'runtime'], - values: [ - { context: 'branch-deploy' as const, value: 'value from branch-deploy context' }, - { context: 'production' as const, value: 'value from production context' }, - { context: 'all' as const, value: 'value from all context' }, - ], - }, - ], - }, - ] - - test('Invoking a function', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/functions/hello.mjs', - `export default async (req, context) => Response.json({ - env: { - WITH_DEV_OVERRIDE: Netlify.env.get("WITH_DEV_OVERRIDE"), - WITHOUT_DEV_OVERRIDE: Netlify.env.get("WITHOUT_DEV_OVERRIDE") - }, - geo: context.geo, - params: context.params, - path: context.path, - server: context.server, - site: context.site, - url: context.url - }); - - export const config = { path: "/hello/:a/*" };`, - ) - .withStateFile({ siteId: 'site_id' }) - const directory = await fixture.create() - const req = new Request('https://site.netlify/hello/one/two/three') - - await withMockApi(routes, async (context) => { - const dev = new NetlifyDev({ - apiURL: context.apiUrl, - apiToken: 'token', - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const res = await dev.handle(req) - - await dev.stop() - - expect(await res?.json()).toStrictEqual({ - env: { - WITH_DEV_OVERRIDE: 'value from dev context', - WITHOUT_DEV_OVERRIDE: 'value from all context', - }, - geo: { - city: 'San Francisco', - country: { - code: 'US', - name: 'United States', - }, - latitude: 0, - longitude: 0, - subdivision: { - code: 'CA', - name: 'California', - }, - timezone: 'UTC', - }, - params: { - '0': 'two/three', - a: 'one', - }, - path: '/hello/:a/*', - server: { - region: 'dev', - }, - site: { - id: 'site_id', - name: 'site-name', - }, - url: 'https://site.netlify/hello/one/two/three', - }) - }) - - await fixture.destroy() - }) - - test('Invoking an edge function', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - [context.dev.environment] - MY_TOKEN = "value from dev context" - [context.deploy-preview.environment] - MY_OTHER_TOKEN = "value from deploy preview context" - `, - ) - .withFile( - 'netlify/functions/hello.mjs', - `export default async (req, context) => new Response("Hello from function"); - - export const config = { path: "/hello/:a/*" };`, - ) - .withFile( - 'netlify/edge-functions/passthrough.mjs', - `export default async (req, context) => { - const res = await context.next(); - const text = await res.text(); - - return new Response(text.toUpperCase(), res); - }; - - export const config = { path: "/hello/passthrough/*" };`, - ) - .withFile( - 'netlify/edge-functions/terminate.mjs', - `export default async (req, context) => Response.json({ - siteEnv: { - WITH_DEV_OVERRIDE: Netlify.env.get("WITH_DEV_OVERRIDE"), - WITHOUT_DEV_OVERRIDE: Netlify.env.get("WITHOUT_DEV_OVERRIDE"), - }, - runtimeEnv: { - NETLIFY_BLOBS_CONTEXT: Netlify.env.get("NETLIFY_BLOBS_CONTEXT"), - }, - platformEnv: { - DEPLOY_ID: Netlify.env.get("DEPLOY_ID"), - }, - configEnv: { - MY_TOKEN: Netlify.env.get("MY_TOKEN"), - MY_OTHER_TOKEN: Netlify.env.get("MY_OTHER_TOKEN"), - }, - parentProcessEnv: { - SOME_ZSH_THING_MAYBE: Netlify.env.get("SOME_ZSH_THING_MAYBE"), - }, - geo: context.geo, - params: context.params, - path: context.path, - server: context.server, - site: context.site, - url: context.url, - }); - - export const config = { path: "/hello/terminate/*" };`, - ) - .withStateFile({ siteId: 'site_id' }) - const directory = await fixture.create() - - await withMockApi(routes, async (context) => { - vi.stubEnv('SOME_ZSH_THING_MAYBE', 'value on developer machine') - - const dev = new NetlifyDev({ - apiURL: context.apiUrl, - apiToken: 'token', - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - const { serverAddress } = await dev.start() - - const req1 = new Request('https://site.netlify/hello/passthrough/two/three') - const res1 = await dev.handle(req1) - - expect(await res1?.text()).toBe('HELLO FROM FUNCTION') - - const req2 = new Request('https://site.netlify/hello/terminate/two/three') - const res2 = await dev.handle(req2) - const req2URL = new URL('/hello/terminate/two/three', serverAddress) - - expect(await res2?.json()).toStrictEqual({ - // Env vars set on the site ("UI") are passed to EFs - siteEnv: { - WITH_DEV_OVERRIDE: 'value from dev context', - WITHOUT_DEV_OVERRIDE: 'value from all context', - }, - // Env vars emulating the EF runtime are present - // TODO(serhalp): Test conditionally injected `NETLIFY_PURGE_API_TOKEN` - // TODO(serhalp): Finish implementing and test conditionally injected `BRANCH` - runtimeEnv: { - NETLIFY_BLOBS_CONTEXT: expect.stringMatching(/\w+/) as unknown, - }, - // Env vars emulating the EF runtime are present - // Note that these originate from `@netlify/config` - platformEnv: { - DEPLOY_ID: '0', - }, - // Envs var set in `netlify.toml` for `dev` context only are passed to EFs - configEnv: { - MY_TOKEN: 'value from dev context', - // MY_OTHER_TOKEN is not present - }, - parentProcessEnv: { - // SOME_ZSH_THING_MAYBE is not present - }, - // TODO(serhalp): Implement and test support for `.env.*` files (exists in CLI) - - geo: { - city: 'San Francisco', - country: { - code: 'US', - name: 'United States', - }, - latitude: 0, - longitude: 0, - subdivision: { - code: 'CA', - name: 'California', - }, - timezone: 'UTC', - }, - params: { - '0': 'two/three', - }, - // TODO: This doesn't exist in edge functions but it should. - // path: '/hello/terminate/*', - server: { - region: 'dev', - }, - site: { - id: 'site_id', - name: 'site-name', - url: serverAddress, - }, - url: req2URL.toString(), - }) - - await dev.stop() - }) - - await fixture.destroy() - }) - - test('Invoking a function that shadows a static file and introspecting the result', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/functions/greeting.mjs', - `export default async (req, context) => new Response(context.params.greeting + ", friend!"); - - export const config = { path: "/:greeting", preferStatic: true };`, - ) - .withFile('public/hello.html', 'Hello') - .withStateFile({ siteId: 'site_id' }) - const directory = await fixture.create() - - await withMockApi(routes, async (context) => { - const dev = new NetlifyDev({ - apiURL: context.apiUrl, - apiToken: 'token', - projectRoot: directory, - edgeFunctions: {}, - geolocation: { - enabled: false, - }, - }) - - await dev.start() - - const req1 = new Request('https://site.netlify/hi') - const res1 = await dev.handleAndIntrospect(req1) - - expect(await res1?.response.text()).toBe('hi, friend!') - expect(res1?.type).toBe('function') - - const req2 = new Request('https://site.netlify/hello') - const res2 = await dev.handleAndIntrospect(req2) - - expect(await res2?.response.text()).toBe('Hello') - expect(res2?.type).toBe('static') - - await dev.stop() - }) - - await fixture.destroy() - }) - }) -}) diff --git a/packages/dev/src/main.ts b/packages/dev/src/main.ts deleted file mode 100644 index 23999cf..0000000 --- a/packages/dev/src/main.ts +++ /dev/null @@ -1,743 +0,0 @@ -import { promises as fs } from 'node:fs' -import { IncomingMessage } from 'node:http' -import path from 'node:path' -import process from 'node:process' - -import { parseAIGatewayContext, setupAIGateway } from '@netlify/ai/bootstrap' -import { resolveConfig } from '@netlify/config' -import { - ensureNetlifyIgnore, - FileWatcher, - getAPIToken, - getGeoLocation, - type Geolocation, - LocalState, - type Logger, - HTTPServer, - Reactive, -} from '@netlify/dev-utils' -import { EdgeFunctionsHandler } from '@netlify/edge-functions-dev' -import { FunctionsHandler } from '@netlify/functions-dev' -import { HeadersHandler, type HeadersCollector } from '@netlify/headers' -import { ImageHandler } from '@netlify/images' -import { RedirectsHandler } from '@netlify/redirects' -import { StaticHandler } from '@netlify/static' -import { NetlifyDB } from '@netlify/database-dev' - -export { applyMigrations, initializeTrackingTable, resetDatabase } from '@netlify/database-dev' -export type { SQLExecutor } from '@netlify/database-dev' - -import { InjectedEnvironmentVariable, injectEnvVariables } from './lib/env.js' -import { isDirectory, isFile } from './lib/fs.js' -import { getNormalizedRequest, getNormalizedRequestFromNodeRequest } from './lib/reqres.js' -import { generateRequestID } from './lib/request_id.js' -import { getRuntime } from './lib/runtime.js' - -export interface Features { - /** - * Configuration options for Netlify Blobs. - * - * {@link} https://docs.netlify.com/blobs/overview/ - */ - blobs?: { - enabled?: boolean - } - - /** - * Configuration options for Netlify Database. - * - * {@link} https://docs.netlify.com/build/data-and-storage/netlify-database/ - */ - database?: { - enabled?: boolean - } - - /** - * Configuration options for environment variables. - * - * {@link} https://docs.netlify.com/edge-functions/overview/ - */ - edgeFunctions?: { - enabled?: boolean - } - - /** - * Configuration options for environment variables. - * - * {@link} https://docs.netlify.com/environment-variables/overview/ - */ - environmentVariables?: { - enabled?: boolean - } - - /** - * Configuration options for Netlify Functions. - * - * {@link} https://docs.netlify.com/functions/overview/ - */ - functions?: { - enabled?: boolean - } - - /** - * Configuration options for geolocation data used by Functions and Edge Functions. - * - * {@link} https://docs.netlify.com/build/edge-functions/api/#geo - */ - geolocation?: { - enabled?: boolean - - /** - * Cache the result of the API call. When disabled, the location is retrieved - * each time. - * - * {@default} true - */ - cache?: boolean - } - - /** - * Configuration options for Netlify response headers. - * - * {@link} https://docs.netlify.com/routing/headers/ - */ - headers?: { - enabled?: boolean - } - - /** - * Configuration options for Netlify Image CDN. - * - * {@link} https://docs.netlify.com/image-cdn/overview/ - */ - images?: { - enabled?: boolean - - /** - * Allowed URL patterns for remote images, described as an array of regular - * expression strings. This list will be merged with the `remote_images` - * configuration property. - * - * {@link} https://docs.netlify.com/image-cdn/overview/#remote-path - */ - remoteURLPatterns?: string[] - } - - /** - * Configuration options for Netlify redirects and rewrites. - * - * {@link} https://docs.netlify.com/routing/redirects/ - */ - redirects?: { - enabled?: boolean - } - - /** - * Configuration options for serving static files. - */ - staticFiles?: { - enabled?: boolean - - /** - * Additional list of directories where static files can be found. The - * `publish` directory configured on your site will be used automatically. - */ - directories?: string[] - } - - /** - * Configuration options for Netlify AI Gateway. - * - * {@link} https://docs.netlify.com/ai/overview/ - */ - aiGateway?: { - enabled?: boolean - } -} - -interface NetlifyDevOptions extends Features { - apiURL?: string - apiToken?: string - logger?: Logger - projectRoot?: string - skipGitignore?: boolean - - /** - * If your local development setup has its own HTTP server (e.g. Vite), set - * its address here. - */ - serverAddress?: string | null -} - -const notFoundHandler = async () => new Response('Not found', { status: 404 }) - -type Config = Awaited> - -interface HandleOptions { - /** - * An optional callback that will be called with every header (key and value) - * coming from header rules. - * - * {@link} https://docs.netlify.com/routing/headers/ - */ - headersCollector?: HeadersCollector - - /** - * If your local development setup has its own HTTP server (e.g. Vite), you - * can supply its address here. It will override any value defined in the - * top-level `serverAddress` setting. - */ - serverAddress?: string -} - -export type ResponseType = 'edge-function' | 'function' | 'image' | 'redirect' | 'static' - -export class NetlifyDev { - #apiHost?: string - #apiScheme?: string - #apiToken?: string - #cleanupJobs: (() => Promise)[] - #edgeFunctionsHandler?: EdgeFunctionsHandler - #functionsHandler?: FunctionsHandler - #geolocationConfig?: NetlifyDevOptions['geolocation'] - #functionsServePath: string - #config?: Config - #features: { - aiGateway: boolean - blobs: boolean - database: boolean - edgeFunctions: boolean - environmentVariables: boolean - functions: boolean - geolocation: boolean - headers: boolean - images: boolean - redirects: boolean - static: boolean - } - #db?: NetlifyDB - #headersHandler?: HeadersHandler - #imageRemoteURLPatterns: string[] - #imageHandler?: ImageHandler - #logger: Logger - #projectRoot: string - #redirectsHandler?: RedirectsHandler - #serverAddress?: string | null - #siteID?: string - #staticHandler?: StaticHandler - #staticHandlerAdditionalDirectories: string[] - #skipGitignore: boolean - - constructor(options: NetlifyDevOptions) { - if (options.apiURL) { - const apiURL = new URL(options.apiURL) - - this.#apiHost = apiURL.host - this.#apiScheme = apiURL.protocol.slice(0, -1) - } - - const projectRoot = options.projectRoot ?? process.cwd() - - this.#apiToken = options.apiToken - this.#cleanupJobs = [] - this.#geolocationConfig = options.geolocation - this.#features = { - aiGateway: options.aiGateway?.enabled !== false, - blobs: options.blobs?.enabled !== false, - database: options.database?.enabled !== false, - edgeFunctions: options.edgeFunctions?.enabled !== false, - environmentVariables: options.environmentVariables?.enabled !== false, - functions: options.functions?.enabled !== false, - geolocation: options.geolocation?.enabled !== false, - headers: options.headers?.enabled !== false, - images: options.images?.enabled !== false, - redirects: options.redirects?.enabled !== false, - static: options.staticFiles?.enabled !== false, - } - this.#functionsServePath = path.join(projectRoot, '.netlify', 'functions-serve') - this.#imageRemoteURLPatterns = options.images?.remoteURLPatterns ?? [] - this.#logger = options.logger ?? globalThis.console - this.#serverAddress = options.serverAddress - this.#projectRoot = projectRoot - this.#staticHandlerAdditionalDirectories = options.staticFiles?.directories ?? [] - this.#skipGitignore = options.skipGitignore ?? false - } - - private getServerAddress(requestServerAddress?: string) { - if (requestServerAddress) { - return requestServerAddress - } - - if (typeof this.#serverAddress === 'string') { - return this.#serverAddress - } - - throw new Error('Server address is not defined') - } - - /** - * Runs a request through the Netlify request chain and returns a `Response` - * if there's a match. We must not disturb the incoming request unless we - * know we will be returning a response, so this method takes a read-only - * request that is safe to access (used for matching) and a getter for the - * actual request (used for handling matches). - * - * @param readRequest Read-only version of the request (without a body) - * @param getWriteRequest Getter for the actual request (with a body) - * @param destPath Destination directory for compiled files - * @param options Options object - * @returns - */ - private async handleInEphemeralDirectory( - readRequest: Request, - getWriteRequest: () => Request, - destPath: string, - options: HandleOptions = {}, - ): Promise<{ response: Response; type: ResponseType } | undefined> { - const serverAddress = this.getServerAddress(options.serverAddress) - - // Try to match the request against the different steps in our request chain. - // - // https://docs.netlify.com/platform/request-chain/ - - // 1. Check if the request matches an edge function. Handles edge functions - // with both modes of cache (manual and off) by running them serially. - const edgeFunctionMatch = await this.#edgeFunctionsHandler?.match(readRequest) - if (edgeFunctionMatch) { - return { - response: await edgeFunctionMatch.handle(getWriteRequest(), serverAddress), - type: 'edge-function', - } - } - - // 2. Check if the request matches an image. - const imageMatch = this.#imageHandler?.match(readRequest) - if (imageMatch) { - const response = await imageMatch.handle(serverAddress) - return { response, type: 'image' } - } - - // 3. Check if the request matches a function. - const functionMatch = await this.#functionsHandler?.match(readRequest, destPath) - if (functionMatch) { - // If the function prefers static files, check if there is a static match - // and, if so, return that - if (functionMatch.preferStatic) { - const staticMatch = await this.#staticHandler?.match(readRequest) - - if (staticMatch) { - const response = await staticMatch.handle() - - await this.#headersHandler?.apply(readRequest, response, options.headersCollector) - - return { response, type: 'static' } - } - } - - // Let the function handle the request. - return { response: await functionMatch.handle(getWriteRequest()), type: 'function' } - } - - // 4. Check if the request matches a redirect rule. - const redirectMatch = await this.#redirectsHandler?.match(readRequest) - if (redirectMatch) { - const redirectRequest = new Request(redirectMatch.target) - // If the redirect rule matches Image CDN, we'll serve it. - const imageMatch = this.#imageHandler?.match(redirectRequest) - if (imageMatch) { - const response = await imageMatch.handle(serverAddress) - return { response, type: 'image' } - } - - // If the redirect rule matches a function, we'll serve it. The exception - // is if the function prefers static files, which in this case means that - // we'll follow the redirect rule. - const functionMatch = await this.#functionsHandler?.match(redirectRequest, destPath) - if (functionMatch && !functionMatch.preferStatic) { - return { - response: await functionMatch.handle(getWriteRequest()), - type: 'function', - } - } - - const response = await this.#redirectsHandler?.handle( - getWriteRequest(), - redirectMatch, - async (maybeStaticFile: Request) => { - const staticMatch = await this.#staticHandler?.match(maybeStaticFile) - if (!staticMatch) { - return - } - - return async () => { - const response = await staticMatch.handle() - - await this.#headersHandler?.apply(new Request(redirectMatch.target), response, options.headersCollector) - - return response - } - }, - ) - if (response) { - return { response, type: 'redirect' } - } - } - - // 5. Check if the request matches a static file. - const staticMatch = await this.#staticHandler?.match(readRequest) - if (staticMatch) { - const response = await staticMatch.handle() - - await this.#headersHandler?.apply(readRequest, response, options.headersCollector) - - return { response, type: 'static' } - } - } - - private async getConfig() { - const configFilePath = path.resolve(this.#projectRoot, 'netlify.toml') - const configFileExists = await isFile(configFilePath) - const config = await resolveConfig({ - config: configFileExists ? configFilePath : undefined, - context: 'dev', - cwd: process.cwd(), - host: this.#apiHost, - offline: !this.#siteID, - mode: 'cli', - repositoryRoot: this.#projectRoot, - scheme: this.#apiScheme, - siteId: this.#siteID, - token: this.#apiToken, - }) - - return config - } - - /** - * Runs a `Request` through the Netlify request chain. If there is a match, - * it returns the resulting `Response` object; if not, it returns `undefined`. - */ - async handle(request: Request, options: HandleOptions = {}) { - const result = await this.handleAndIntrospect(request, options) - - return result?.response - } - - /** - * Runs a `Request` through the Netlify request chain. If there is a match, - * it returns an object with the resulting `Response` object and information - * about the match; if not, it returns `undefined`. - */ - async handleAndIntrospect(request: Request, options: HandleOptions = {}) { - await fs.mkdir(this.#functionsServePath, { recursive: true }) - - const destPath = await fs.mkdtemp(path.join(this.#functionsServePath, `_`)) - const requestID = generateRequestID() - const matchRequest = getNormalizedRequest(request, requestID, true) - const getHandleRequest = () => getNormalizedRequest(request, requestID, false) - - try { - return await this.handleInEphemeralDirectory(matchRequest, getHandleRequest, destPath, options) - } finally { - try { - await fs.rm(destPath, { force: true, recursive: true }) - } catch {} - } - } - - /** - * Runs a Node.js `IncomingMessage` through the Netlify request chain. If - * there is a match, it returns an object with the resulting `Response` - * object and information about the match; if not, it returns `undefined`. - */ - async handleAndIntrospectNodeRequest(request: IncomingMessage, options: HandleOptions = {}) { - await fs.mkdir(this.#functionsServePath, { recursive: true }) - - const destPath = await fs.mkdtemp(path.join(this.#functionsServePath, `_`)) - const requestID = generateRequestID() - const matchRequest = getNormalizedRequestFromNodeRequest(request, requestID, true) - const getHandleRequest = () => getNormalizedRequestFromNodeRequest(request, requestID, false) - - try { - return await this.handleInEphemeralDirectory(matchRequest, getHandleRequest, destPath, options) - } finally { - try { - await fs.rm(destPath, { force: true, recursive: true }) - } catch {} - } - } - - get siteIsLinked() { - return Boolean(this.#siteID) - } - - async start() { - if (!this.#skipGitignore) { - await ensureNetlifyIgnore(this.#projectRoot, this.#logger) - } - - this.#apiToken = this.#apiToken ?? (await getAPIToken()) - - const state = new LocalState(this.#projectRoot) - const siteID = state.get('siteId') - this.#siteID = siteID - - const config = await this.getConfig() - this.#config = config - - const reactiveConfig = new Reactive(config) - - const fileWatcher = new FileWatcher() - this.#cleanupJobs.push(() => fileWatcher.close()) - - // Watch the config file and re-resolve when it changes. - if (config.configPath) { - const reloadConfig = () => { - void (async () => { - try { - const newConfig = await this.getConfig() - this.#config = newConfig - reactiveConfig.set(newConfig) - } catch (error) { - this.#logger.warn(`Failed to reload config: ${String(error)}`) - } - })() - } - - fileWatcher.subscribe({ - id: 'netlify-config', - paths: config.configPath, - onChange: reloadConfig, - onAdd: reloadConfig, - onUnlink: reloadConfig, - }) - } - - const runtime = await getRuntime({ - blobs: this.#features.blobs, - deployID: '0', - projectRoot: this.#projectRoot, - siteID: siteID ?? '0', - }) - - this.#cleanupJobs.push(() => runtime.stop()) - - if (this.#features.database) { - try { - const dbDirectory = path.join(this.#projectRoot, '.netlify', 'db') - const db = new NetlifyDB({ directory: dbDirectory }) - const connectionString = await db.start() - - runtime.env.set('NETLIFY_DB_URL', connectionString) - runtime.env.set('NETLIFY_DB_DRIVER', 'server') - - state.set('dbConnectionString', connectionString) - - this.#db = db - this.#cleanupJobs.push(async () => { - await db.stop() - state.delete('dbConnectionString') - }) - } catch (error) { - this.#db = undefined - this.#logger.warn(`Failed to start Netlify Database locally: ${String(error)}`) - } - } - - // Check if AI Gateway is disabled at account level (setting passed to site level capabilities) - if (this.#features.aiGateway && config?.siteInfo?.capabilities?.ai_gateway_disabled) { - this.#features.aiGateway = false - } - - // Bootstrap AI Gateway: Fetch AI Gateway tokens and inject them into env - if (this.#features.aiGateway && this.#features.environmentVariables && config?.api) { - await setupAIGateway({ - api: config.api, - env: config.env || {}, - siteID, - siteURL: config.siteInfo?.url, - accountID: config.siteInfo?.account_id, - siteHasDeploy: !!config.siteInfo?.published_deploy, - }) - - // Inject AI_GATEWAY into process.env via runtime - if (config.env.AI_GATEWAY) { - runtime.env.set('AI_GATEWAY', config.env.AI_GATEWAY.value) - - // Parse and inject AI Gateway env vars - const aiGatewayContext = parseAIGatewayContext(config.env.AI_GATEWAY.value) - if (aiGatewayContext) { - runtime.env.set('NETLIFY_AI_GATEWAY_KEY', aiGatewayContext.token) - runtime.env.set('NETLIFY_AI_GATEWAY_URL', aiGatewayContext.url) - - if (aiGatewayContext.envVars) { - for (const envVar of aiGatewayContext.envVars) { - runtime.env.set(envVar.key, aiGatewayContext.token) - runtime.env.set(envVar.url, aiGatewayContext.url) - } - } - } - } - } - - let serverAddress: string | undefined - - // If a custom server has been provided, use it. If not, we must stand up - // a new one, since it's required for communication with edge functions - // and local images support for Image CDN. - if (typeof this.#serverAddress === 'string') { - serverAddress = this.#serverAddress - } else if (this.#serverAddress !== null && (this.#features.edgeFunctions || this.#features.images)) { - const passthroughServer = new HTTPServer(async (req) => { - const res = await this.handle(req) - - return res ?? new Response(null, { status: 404 }) - }) - - this.#cleanupJobs.push(() => passthroughServer.stop()) - - serverAddress = await passthroughServer.start() - this.#serverAddress = serverAddress - } - - let envVariables: Record = {} - - if (this.#features.environmentVariables) { - // TODO: Use proper types for this. - envVariables = await injectEnvVariables({ - accountSlug: config?.siteInfo?.account_slug, - baseVariables: config?.env || {}, - envAPI: runtime.env, - netlifyAPI: config?.api, - siteID, - }) - } - - let geolocation: Geolocation | undefined - - if (this.#features.edgeFunctions) { - const edgeFunctionsEnv = { - // User-defined env vars + documented runtime env vars - ...Object.entries(envVariables).reduce>( - (acc, [key, variable]) => ({ - ...acc, - [key]: variable.value, - }), - {}, - ), - // Add runtime env vars that we've set ourselves so far. These are "internal" env vars, - // part of the runtime emulation. They've already been populated on this process's env, which - // is needed to make other dev features work. These are different than the "documented" runtime - // env vars, in that they are implementation details, needed to make our features work. - ...Object.keys(runtime.envSnapshot).reduce>( - (acc, key) => ({ - ...acc, - [key]: runtime.env.get(key) ?? '', - }), - {}, - ), - } - - geolocation ??= await getGeoLocation({ - enabled: this.#features.geolocation, - cache: this.#geolocationConfig?.cache ?? true, - state, - }) - - const edgeFunctionsHandler = new EdgeFunctionsHandler({ - configDeclarations: this.#config?.config.edge_functions ?? [], - directories: [this.#config?.config.build.edge_functions].filter(Boolean) as string[], - env: edgeFunctionsEnv, - geolocation, - logger: this.#logger, - siteID, - siteName: config?.siteInfo.name, - }) - this.#edgeFunctionsHandler = edgeFunctionsHandler - - this.#cleanupJobs.push(() => edgeFunctionsHandler.stop()) - } - - if (this.#features.functions) { - const userFunctionsPath = - this.#config?.config.functionsDirectory ?? path.join(this.#projectRoot, 'netlify/functions') - const userFunctionsPathExists = await isDirectory(userFunctionsPath) - - geolocation ??= await getGeoLocation({ - enabled: this.#features.geolocation, - cache: this.#geolocationConfig?.cache ?? true, - state, - }) - - this.#functionsHandler = new FunctionsHandler({ - config: reactiveConfig, - destPath: this.#functionsServePath, - fileWatcher, - geolocation, - projectRoot: this.#projectRoot, - settings: {}, - siteId: this.#siteID, - userFunctionsPath: userFunctionsPathExists ? userFunctionsPath : undefined, - }) - } - - if (this.#features.headers) { - this.#headersHandler = new HeadersHandler({ - configPath: this.#config?.configPath, - configHeaders: this.#config?.config.headers, - projectDir: this.#projectRoot, - publishDir: this.#config?.config.build.publish ?? undefined, - logger: this.#logger, - }) - } - - if (this.#features.redirects) { - this.#redirectsHandler = new RedirectsHandler({ - configPath: this.#config?.configPath, - configRedirects: this.#config?.config.redirects, - jwtRoleClaim: '', - jwtSecret: '', - notFoundHandler, - projectDir: this.#projectRoot, - }) - } - - if (this.#features.static) { - this.#staticHandler = new StaticHandler({ - directory: [ - this.#config?.config.build.publish ?? this.#projectRoot, - ...this.#staticHandlerAdditionalDirectories, - ], - }) - } - - if (this.#features.images) { - const remoteImages = [...(this.#config?.config?.images?.remote_images ?? []), ...this.#imageRemoteURLPatterns] - - this.#imageHandler = new ImageHandler({ - imagesConfig: { - remote_images: remoteImages, - }, - logger: this.#logger, - }) - } - - return { - serverAddress, - } - } - - get db(): NetlifyDB | undefined { - return this.#db - } - - async stop() { - await Promise.allSettled(this.#cleanupJobs.map((task) => task())) - } - - public getEnabledFeatures(): string[] { - return Object.entries(this.#features) - .filter(([_, enabled]) => enabled) - .map(([feature]) => feature) - } -} diff --git a/packages/dev/test/mock-api.ts b/packages/dev/test/mock-api.ts deleted file mode 100644 index e15a573..0000000 --- a/packages/dev/test/mock-api.ts +++ /dev/null @@ -1,136 +0,0 @@ -import type { IncomingHttpHeaders } from 'http' -import { isDeepStrictEqual } from 'util' - -import { HTTPServer } from '@netlify/dev-utils' - -export interface Route { - method?: 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT' | 'HEAD' | 'OPTIONS' | 'all' - path: string - response?: ((req: Request, res: Response) => Promise | Response) | Record | unknown[] - requestBody?: any - status?: number -} - -interface MockApiOptions { - routes: Route[] - silent?: boolean -} - -export interface MockApi { - apiUrl: string - clearRequests: () => void - requests: { path: string; body: unknown; method: string; headers: IncomingHttpHeaders }[] - server: HTTPServer - close: () => Promise -} - -export interface MockApiTestContext { - apiUrl: string - requests: MockApi['requests'] -} - -// Replace mock-api.js with this once everything migrated - -const addRequest = async (requests: MockApi['requests'], request: Request) => { - const url = new URL(request.url) - const headers: IncomingHttpHeaders = {} - request.headers.forEach((value, key) => { - headers[key] = value - }) - - requests.push({ - path: url.pathname, - body: await request - .clone() - .json() - .catch(() => undefined), - method: request.method, - headers, - }) -} - -const clearRequests = (requests: unknown[]) => { - // We cannot create a new array, as the reference of this array is used in tests - requests.length = 0 -} - -export const startMockApi = async ({ routes, silent }: MockApiOptions): Promise => { - const requests: MockApi['requests'] = [] - const server = new HTTPServer(async (req: Request): Promise => { - const url = new URL(req.url) - const path = url.pathname.replace('/api/v1/', '') - const matchedRoute = routes.find( - (route) => route.path === path && (!route.method || route.method.toLowerCase() === req.method.toLowerCase()), - ) - - if (!matchedRoute) { - if (!silent) { - console.warn(`Route not found: (${req.method.toUpperCase()}) ${url.pathname}`) - } - return new Response(JSON.stringify({ message: 'Not found' }), { - status: 404, - headers: { 'Content-Type': 'application/json' }, - }) - } - - const { response = {}, requestBody, status = 200 } = matchedRoute - - if (requestBody !== undefined) { - const body = await req.json() - if (!isDeepStrictEqual(requestBody, body)) { - return new Response(JSON.stringify({ message: `Request body doesn't match` }), { - status: 500, - headers: { 'Content-Type': 'application/json' }, - }) - } - } - - addRequest(requests, req) - - if (typeof response === 'function') { - const customResponse = await response(req, new Response()) - return customResponse || new Response(null, { status: 204 }) - } - - let responseBody = response - if (status === 404 && typeof response === 'object' && !Array.isArray(response)) { - responseBody = { ...response, message: 'Not found' } - } - - return new Response(JSON.stringify(responseBody), { - status, - headers: { 'Content-Type': 'application/json' }, - }) - }) - - const address = await server.start() - - return { - server, - apiUrl: `${address}/api/v1`, - requests, - clearRequests: clearRequests.bind(null, requests), - async close() { - await server.stop() - }, - } -} - -type MockAPIContext = { - apiUrl: string - requests: { path: string; body: unknown; method: string; headers: IncomingHttpHeaders }[] -} - -export const withMockApi = async ( - routes: Route[], - factory: (context: MockAPIContext) => void | Promise, - silent = false, -) => { - let mockApi: Awaited> | undefined - try { - mockApi = await startMockApi({ routes, silent }) - await factory({ apiUrl: mockApi.apiUrl, requests: mockApi.requests }) - } finally { - await mockApi?.server.stop() - } -} diff --git a/packages/dev/tsconfig.json b/packages/dev/tsconfig.json deleted file mode 100644 index 15d51fb..0000000 --- a/packages/dev/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "rootDir": ".", - "moduleResolution": "nodenext", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/dev/tsup.config.ts b/packages/dev/tsup.config.ts deleted file mode 100644 index c5ce64e..0000000 --- a/packages/dev/tsup.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - format: ['cjs', 'esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - external: ['@netlify/ai'], - }, -]) diff --git a/packages/dev/vitest.config.ts b/packages/dev/vitest.config.ts deleted file mode 100644 index 3fb7c50..0000000 --- a/packages/dev/vitest.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - // Some of this package's tests are slow on Windows - testTimeout: 20_000, - }, -}) diff --git a/packages/edge-functions/.gitignore b/packages/edge-functions/.gitignore deleted file mode 100644 index 520d181..0000000 --- a/packages/edge-functions/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist/ -dev/src/deno/bootstrap.mjs diff --git a/packages/edge-functions/dev/CHANGELOG.md b/packages/edge-functions/dev/CHANGELOG.md deleted file mode 100644 index b70b480..0000000 --- a/packages/edge-functions/dev/CHANGELOG.md +++ /dev/null @@ -1,207 +0,0 @@ -# Changelog - -## [1.0.20](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.19...edge-functions-dev-v1.0.20) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.5 to 4.4.6 - * @netlify/edge-functions bumped from 3.0.7 to 3.0.8 - -## [1.0.19](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.18...edge-functions-dev-v1.0.19) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.4 to 4.4.5 - * @netlify/edge-functions bumped from 3.0.6 to 3.0.7 - -## [1.0.18](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.17...edge-functions-dev-v1.0.18) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.3 to 4.4.4 - -## [1.0.17](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.16...edge-functions-dev-v1.0.17) (2026-05-11) - - -### Bug Fixes - -* **deps:** update netlify packages ([#674](https://github.com/netlify/primitives/issues/674)) ([8179496](https://github.com/netlify/primitives/commit/8179496fad479522f329cc99d03175408bffcb0c)) - -## [1.0.16](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.15...edge-functions-dev-v1.0.16) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.2 to 4.4.3 - * @netlify/edge-functions bumped from 3.0.5 to 3.0.6 - -## [1.0.15](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.14...edge-functions-dev-v1.0.15) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.1 to 4.4.2 - * @netlify/edge-functions bumped from 3.0.4 to 3.0.5 - -## [1.0.14](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.13...edge-functions-dev-v1.0.14) (2026-03-13) - - -### Bug Fixes - -* **deps:** update netlify packages ([#626](https://github.com/netlify/primitives/issues/626)) ([a87ba84](https://github.com/netlify/primitives/commit/a87ba84fa23c3a4ff506cd9c3d5f3b5cd78d9f3c)) - -## [1.0.13](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.12...edge-functions-dev-v1.0.13) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.0 to 4.4.1 - * @netlify/edge-functions bumped from 3.0.3 to 3.0.4 - -## [1.0.12](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.11...edge-functions-dev-v1.0.12) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.3 to 4.4.0 - -## [1.0.11](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.10...edge-functions-dev-v1.0.11) (2026-02-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#583](https://github.com/netlify/primitives/issues/583)) ([bcd8241](https://github.com/netlify/primitives/commit/bcd824172757fecac5aa91dc36b06163efb63497)) - -## [1.0.10](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.9...edge-functions-dev-v1.0.10) (2026-02-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.2.1 to 2.3.0 - -## [1.0.9](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.8...edge-functions-dev-v1.0.9) (2026-01-28) - - -### Bug Fixes - -* **deps:** update netlify packages ([#576](https://github.com/netlify/primitives/issues/576)) ([1c6ff24](https://github.com/netlify/primitives/commit/1c6ff247318b8cdb1961ce76e96fe423a4ec8cd7)) - -## [1.0.8](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.7...edge-functions-dev-v1.0.8) (2026-01-19) - - -### Bug Fixes - -* **deps:** update netlify packages ([#566](https://github.com/netlify/primitives/issues/566)) ([184656a](https://github.com/netlify/primitives/commit/184656af871a81bddc69e9133f22bfa945f28ebf)) - -## [1.0.7](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.6...edge-functions-dev-v1.0.7) (2025-12-08) - - -### Bug Fixes - -* **deps:** update netlify packages ([#557](https://github.com/netlify/primitives/issues/557)) ([60644bf](https://github.com/netlify/primitives/commit/60644bf6863a0ba41d9e73b0d8d1cfa90205c963)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.2 to 4.3.3 - * @netlify/edge-functions bumped from 3.0.2 to 3.0.3 - -## [1.0.6](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.5...edge-functions-dev-v1.0.6) (2025-12-03) - - -### Bug Fixes - -* **deps:** update netlify packages ([#549](https://github.com/netlify/primitives/issues/549)) ([ec4fb29](https://github.com/netlify/primitives/commit/ec4fb2978af5cf75c12645ade9f771bc94a796e2)) - -## [1.0.5](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.4...edge-functions-dev-v1.0.5) (2025-11-14) - - -### Bug Fixes - -* **deps:** update dependency @netlify/edge-bundler to ^14.8.7 ([#541](https://github.com/netlify/primitives/issues/541)) ([6fee541](https://github.com/netlify/primitives/commit/6fee541e05d67920ce500aafd8e7788c303bb7c0)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.1 to 4.3.2 - -## [1.0.4](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.3...edge-functions-dev-v1.0.4) (2025-11-05) - - -### Bug Fixes - -* **deps:** update netlify packages ([#515](https://github.com/netlify/primitives/issues/515)) ([67034cc](https://github.com/netlify/primitives/commit/67034cce9f80e35582f328b1990d0f26e7181cff)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.0 to 4.3.1 - * @netlify/edge-functions bumped from 3.0.1 to 3.0.2 - -## [1.0.3](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.2...edge-functions-dev-v1.0.3) (2025-11-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/runtime-utils bumped from 2.2.0 to 2.2.1 - -## [1.0.2](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.1...edge-functions-dev-v1.0.2) (2025-10-29) - - -### Bug Fixes - -* **deps:** update netlify packages ([#504](https://github.com/netlify/primitives/issues/504)) ([3586853](https://github.com/netlify/primitives/commit/35868533dd9f878b4162685131219419ca33bd8a)) - -## [1.0.1](https://github.com/netlify/primitives/compare/edge-functions-dev-v1.0.0...edge-functions-dev-v1.0.1) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 3.0.0 to 3.0.1 - -## 1.0.0 (2025-10-19) - - -### ⚠ BREAKING CHANGES - -* split edge-functions package - -### Features - -* split edge-functions package ([495c76d](https://github.com/netlify/primitives/commit/495c76d9933a8da15bfe754ccdbf80fcf815538f)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/edge-functions bumped from 2.19.0 to 3.0.0 diff --git a/packages/edge-functions/dev/bootstrap-bundle.mjs b/packages/edge-functions/dev/bootstrap-bundle.mjs deleted file mode 100644 index 5039d1d..0000000 --- a/packages/edge-functions/dev/bootstrap-bundle.mjs +++ /dev/null @@ -1,15 +0,0 @@ -import * as esbuild from 'npm:esbuild' -import { denoPlugins } from 'jsr:@luca/esbuild-deno-loader@^0.11.1' - -const [entryPoint, outfile] = Deno.args - -await esbuild.build({ - bundle: true, - entryPoints: [entryPoint], - format: 'esm', - minify: true, - outfile, - plugins: denoPlugins(), -}) - -await esbuild.stop() diff --git a/packages/edge-functions/dev/package.json b/packages/edge-functions/dev/package.json deleted file mode 100644 index 91d813a..0000000 --- a/packages/edge-functions/dev/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@netlify/edge-functions-dev", - "version": "1.0.20", - "description": "Local emulation for Netlify Edge Functions", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/node/main.js", - "exports": { - ".": { - "types": "./dist/node/main.d.ts", - "default": "./dist/node/main.js" - } - }, - "types": "./dist/node/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "dev": "tsup-node --watch" - }, - "keywords": [ - "netlify", - "edge functions" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/edge-functions/dev" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/edge-bundler": "^14.10.1", - "@netlify/edge-functions": "3.0.8", - "@netlify/edge-functions-bootstrap": "2.16.0", - "@netlify/runtime-utils": "2.3.0", - "get-port": "^7.1.0" - }, - "devDependencies": { - "execa": "^8.0.1", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - } -} diff --git a/packages/edge-functions/dev/src/deno/config.mjs b/packages/edge-functions/dev/src/deno/config.mjs deleted file mode 100644 index c6b24ad..0000000 --- a/packages/edge-functions/dev/src/deno/config.mjs +++ /dev/null @@ -1,55 +0,0 @@ -// @ts-check - -/** - * @typedef {import('./workers/types.ts').ConfigRequestMessage} ConfigRequestMessage - * @typedef {import('./workers/types.ts').Message} Message - */ - -/** - * @param {Record} functions - */ -export function getConfigs(functions) { - return new Promise((resolve, reject) => { - const worker = new Worker(new URL('./workers/config.mjs', import.meta.url).href, { - type: 'module', - }) - - worker.postMessage( - /** @type {ConfigRequestMessage} */ ({ - type: 'configRequest', - data: { functions }, - }), - ) - - worker.onmessage = (e) => { - const message = /** @type {Message} */ (e.data) - - if (message.type === 'configResponse') { - const { configs, errors } = message.data - - for (const functionName in errors) { - const prefix = `Failed to parse edge function \`${functionName}\`:` - const error = new Error(`${prefix} ${errors[functionName].message}`) - - if (errors[functionName].name) { - error.name = errors[functionName].name - } - - error.stack = `${prefix} ${error.stack}` - - reject(error) - - return - } - - resolve(configs) - - return - } - } - - worker.onerror = (e) => { - reject(e) - } - }) -} diff --git a/packages/edge-functions/dev/src/deno/errors.mjs b/packages/edge-functions/dev/src/deno/errors.mjs deleted file mode 100644 index 01d7c97..0000000 --- a/packages/edge-functions/dev/src/deno/errors.mjs +++ /dev/null @@ -1,28 +0,0 @@ -// @ts-check - -/** - * @param {unknown} error - */ -export const getErrorResponse = (error) => { - const errorData = - error instanceof Error - ? { - name: error.name, - message: error.message, - stack: error.stack, - cause: String(error.cause), - } - : String(error) - - return Response.json( - { - error: errorData, - }, - { - headers: { - 'x-nf-uncaught-error': '1', - }, - status: 500, - }, - ) -} diff --git a/packages/edge-functions/dev/src/deno/invoke.mjs b/packages/edge-functions/dev/src/deno/invoke.mjs deleted file mode 100644 index 7a08067..0000000 --- a/packages/edge-functions/dev/src/deno/invoke.mjs +++ /dev/null @@ -1,109 +0,0 @@ -// @ts-check - -/** - * @typedef {import('./workers/types.ts').Message} Message - */ - -/** - * Spawns a `Worker` to invoke a chain of edge functions. It serializes the - * `Request` into a worker message and uses the messages it receives back to - * construct a `Response`. - * - * @param {Request} req - * @param {Record} functions - * @param {number} requestTimeout - */ -export function invoke(req, functions, requestTimeout) { - return new Promise(async (resolve, reject) => { - const worker = new Worker(new URL('./workers/runner.mjs', import.meta.url).href, { - type: 'module', - }) - - /** @type {Response | null} */ - let response = null - /** @type {ReadableStreamDefaultController | null} */ - let streamController = null - /** @type {ReadableStream | null} */ - let stream = null - - const timeoutCheck = setTimeout(() => { - if (!response) { - reject( - new Error( - 'An edge function took too long to produce a response. Refer to https://ntl.fyi/ef-limits for information about limits.', - ), - ) - } - }, requestTimeout) - - worker.onmessage = (e) => { - const message = /** @type {Message} */ (e.data) - - switch (message.type) { - case 'responseChunk': { - streamController && streamController.enqueue(message.data.chunk) - - break - } - - case 'responseStart': { - if (message.data.hasBody) { - stream = new ReadableStream({ - start(controller) { - streamController = controller - }, - cancel() { - streamController = null - worker.terminate() - }, - }) - } - - response = new Response(stream, { - headers: message.data.headers, - status: message.data.status, - }) - - clearTimeout(timeoutCheck) - - resolve(response) - - break - } - - case 'responseEnd': { - streamController?.close() - worker.terminate() - - clearTimeout(timeoutCheck) - - if (!response) { - reject(new Error('There was an error in producing the edge function response')) - - return - } - - resolve(response) - } - } - } - - worker.onerror = (e) => { - clearTimeout(timeoutCheck) - - reject(e) - } - - worker.postMessage({ - type: 'request', - data: { - body: await req.arrayBuffer(), - functions, - headers: Object.fromEntries(req.headers.entries()), - method: req.method, - timeout: requestTimeout, - url: req.url, - }, - }) - }) -} diff --git a/packages/edge-functions/dev/src/deno/server.mjs b/packages/edge-functions/dev/src/deno/server.mjs deleted file mode 100644 index 8c3868b..0000000 --- a/packages/edge-functions/dev/src/deno/server.mjs +++ /dev/null @@ -1,73 +0,0 @@ -// @ts-check - -/** - * @typedef {import('../shared/types.ts').RunOptions} RunOptions - */ - -import { getErrorResponse } from './errors.mjs' - -import { getConfigs } from './config.mjs' -import { invoke } from './invoke.mjs' - -/** - * Starts an HTTP server on the provided port. The server acts as a proxy that - * handles edge function invocations. - * - * @param {RunOptions} options - */ -export const serveLocal = ({ denoPort: port, requestTimeout }) => { - const serveOptions = { - // Adding a no-op listener to avoid the default one, which prints a message - // we don't want. - onListen() {}, - port, - } - - /** @type {Record} */ - let functions = {} - - /** - * @param {Request} request - */ - const server = Deno.serve(serveOptions, async (/** @type {Request} */ request) => { - const url = new URL(request.url) - const method = request.method.toUpperCase() - - // This custom method represents an introspection request that will make - // the Deno server take a list of functions, import them, and return their - // configs. - if (method === 'NETLIFYCONFIG') { - const functionsParam = url.searchParams.get('functions') - - // This is the list of all the functions found in the project. - /** @type {Record} */ - const availableFunctions = functionsParam ? JSON.parse(decodeURIComponent(functionsParam)) : {} - - functions = availableFunctions - - try { - const configs = await getConfigs(availableFunctions) - - return Response.json(configs) - } catch (error) { - return getErrorResponse(error) - } - } - - if (Object.keys(functions).length === 0) { - return new Response(null, { status: 404 }) - } - - try { - return await invoke(request, functions, requestTimeout) - } catch (error) { - return getErrorResponse(error) - } - }) - - return server.finished -} - -const runOptions = JSON.parse(Deno.args[0]) - -await serveLocal(runOptions) diff --git a/packages/edge-functions/dev/src/deno/workers/config.mjs b/packages/edge-functions/dev/src/deno/workers/config.mjs deleted file mode 100644 index eed100c..0000000 --- a/packages/edge-functions/dev/src/deno/workers/config.mjs +++ /dev/null @@ -1,52 +0,0 @@ -// @ts-check -/// - -/** - * @typedef {import('../../shared/types.ts').SerializedError} SerializedError - * @typedef {import('./types.ts').ConfigResponseMessage} ConfigResponseMessage - * @typedef {import('./types.ts').Message} Message - */ - -/** @type {DedicatedWorkerGlobalScope} */ -// @ts-ignore We are inside a worker, so the global scope is `DedicatedWorkerGlobalScope`. -const worker = globalThis - -worker.addEventListener('message', async (e) => { - const message = /** @type {Message} */ (e.data) - - if (message.type === 'configRequest') { - /** @type {Record} */ - const configs = {} - - /** @type {Record} */ - const errors = {} - - const imports = Object.entries(message.data.functions).map(async ([name, path]) => { - try { - const func = await import(path) - - configs[name] = func.config ?? {} - } catch (error) { - if (error instanceof Error) { - errors[name] = { - message: error.message, - name: error.name, - stack: error.stack, - } - } else { - errors[name] = { - message: String(error), - } - } - } - }) - - await Promise.allSettled(imports) - - worker.postMessage(/** @type {ConfigResponseMessage} */ ({ type: 'configResponse', data: { configs, errors } })) - - return - } - - throw new Error('Unsupported message') -}) diff --git a/packages/edge-functions/dev/src/deno/workers/runner.mjs b/packages/edge-functions/dev/src/deno/workers/runner.mjs deleted file mode 100644 index aba3111..0000000 --- a/packages/edge-functions/dev/src/deno/workers/runner.mjs +++ /dev/null @@ -1,86 +0,0 @@ -// @ts-check -/// -import { handleRequest } from '../bootstrap.mjs' - -/** - * @typedef {import('./types.ts').Message} Message - * @typedef {import('./types.ts').RunResponseStartMessage} RunResponseStartMessage - * @typedef {import('./types.ts').RunResponseChunkMessage} RunResponseChunkMessage - * @typedef {import('./types.ts').RunResponseEndMessage} RunResponseEndMessage - */ - -const consoleLog = globalThis.console.log -/** @type {Map} */ -const fetchRewrites = new Map() - -/** @type {DedicatedWorkerGlobalScope} */ -// @ts-ignore We are inside a worker, so the global scope is `DedicatedWorkerGlobalScope`. -const worker = globalThis - -worker.addEventListener('message', async (e) => { - const message = /** @type {Message} */ (e.data) - - if (message.type === 'request') { - const body = message.data.method === 'GET' || message.data.method === 'HEAD' ? undefined : message.data.body - const req = new Request(message.data.url, { - body, - headers: message.data.headers, - method: message.data.method, - }) - - /** @type {Record} */ - const functions = {} - - const imports = Object.entries(message.data.functions).map(async ([name, path]) => { - const func = await import(path) - - functions[name] = func.default - }) - - await Promise.allSettled(imports) - - const res = await handleRequest(req, functions, { - // @ts-ignore TODO: Figure out why `fetchRewrites` is not being picked up - // as part of the type. - fetchRewrites, - rawLogger: consoleLog, - requestTimeout: message.data.timeout, - }) - - worker.postMessage( - /** @type {RunResponseStartMessage} */ ({ - type: 'responseStart', - data: { - headers: Object.fromEntries(res.headers.entries()), - status: res.status, - hasBody: Boolean(res.body), - }, - }), - ) - - const reader = res.body?.getReader() - if (reader) { - while (true) { - const { done, value } = await reader.read() - if (done) { - break - } - - // @ts-expect-error TODO: Figure out type mismatch. - worker.postMessage( - /** @type {RunResponseChunkMessage} */ ({ - type: 'responseChunk', - data: { chunk: value }, - }), - [value.buffer], - ) - } - } - - worker.postMessage(/** @type {RunResponseEndMessage} */ ({ type: 'responseEnd' })) - - return - } - - throw new Error('Unsupported message') -}) diff --git a/packages/edge-functions/dev/src/deno/workers/types.ts b/packages/edge-functions/dev/src/deno/workers/types.ts deleted file mode 100644 index f22a66a..0000000 --- a/packages/edge-functions/dev/src/deno/workers/types.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { SerializedError } from '../../shared/types.ts' - -/** - * A message that asks a worker to retrieve the configuration objects for a set - * of functions. - */ -export interface ConfigRequestMessage { - type: 'configRequest' - data: { - functions: Record - } -} - -/** - * A message produced by a worker that contains the configuration objects for a - * set of functions. - */ -export interface ConfigResponseMessage { - type: 'configResponse' - data: { - configs: Record - errors: Record - } -} - -/** - * A message that asks a worker to run a chain of edge functions for a given - * request, serialized in the `data` field. - */ -export interface RunRequestMessage { - type: 'request' - data: { - body: ArrayBuffer - functions: Record - headers: Record - method: string - timeout: number - url: string - } -} - -/** - * A message produced by a worker that represents the beginning of a `Response` - * object, holding the headers and the status code. - */ -export interface RunResponseStartMessage { - type: 'responseStart' - data: { - headers: Record - status: number - hasBody: boolean - } -} - -/** - * A message produced by a worker that holds a chunk of a `Response` body. - */ -export interface RunResponseChunkMessage { - type: 'responseChunk' - data: { - chunk: Uint8Array | undefined - } -} - -/** - * A message produced by a worker that represents the end of a `Response` body. - */ -export interface RunResponseEndMessage { - type: 'responseEnd' -} - -export type Message = - | ConfigRequestMessage - | ConfigResponseMessage - | RunRequestMessage - | RunResponseChunkMessage - | RunResponseEndMessage - | RunResponseStartMessage diff --git a/packages/edge-functions/dev/src/node/headers.ts b/packages/edge-functions/dev/src/node/headers.ts deleted file mode 100644 index a4971c7..0000000 --- a/packages/edge-functions/dev/src/node/headers.ts +++ /dev/null @@ -1,24 +0,0 @@ -export const headers = { - BlobsInfo: 'x-nf-blobs-info', - DeployID: 'x-nf-deploy-id', - DeployContext: 'x-nf-deploy-context', - FeatureFlags: 'x-nf-feature-flags', - ForwardedHost: 'x-forwarded-host', - ForwardedProtocol: 'x-forwarded-proto', - Functions: 'x-nf-edge-functions', - InvocationMetadata: 'x-nf-edge-functions-metadata', - Geo: 'x-nf-geo', - Passthrough: 'x-nf-passthrough', - PassthroughHost: 'x-nf-passthrough-host', - PassthroughProtocol: 'x-nf-passthrough-proto', - IP: 'x-nf-client-connection-ip', - Site: 'X-NF-Site-Info', - DebugLogging: 'x-nf-debug-logging', - Account: 'x-nf-account-info', - RequestID: 'x-nf-request-id', - AvailableFunctions: 'x-nf-available-edge-functions', - FunctionDeclarations: 'x-nf-edge-functions-declarations', - UncaughtError: 'x-nf-uncaught-error', - - AcceptEncoding: 'accept-encoding', -} diff --git a/packages/edge-functions/dev/src/node/main.test.ts b/packages/edge-functions/dev/src/node/main.test.ts deleted file mode 100644 index 8e6f4a4..0000000 --- a/packages/edge-functions/dev/src/node/main.test.ts +++ /dev/null @@ -1,338 +0,0 @@ -import path from 'node:path' - -import { describe, expect, test, beforeAll, afterAll } from 'vitest' - -import { Fixture, HTTPServer } from '@netlify/dev-utils' -import { EdgeFunctionsHandler } from './main.js' - -describe('`EdgeFunctionsHandler`', () => { - let serverAddress: string - let server: HTTPServer - - const geolocation = { - city: 'San Francisco', - country: { code: 'US', name: 'United States' }, - subdivision: { code: 'CA', name: 'California' }, - longitude: 0, - latitude: 0, - timezone: 'UTC', - } - - beforeAll(async () => { - server = new HTTPServer(async () => new Response('From origin')) - - serverAddress = await server.start() - }) - - afterAll(async () => { - await server.stop() - }) - - test('Runs an edge function', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/edge-functions/echo.mjs', - `export default async (req, context) => Response.json({ - env: { - VAR_1: Netlify.env.get("VAR_1"), - VAR_2: Netlify.env.get("VAR_2") - }, - geo: context.geo, - params: context.params, - path: context.path, - server: context.server, - site: context.site, - url: context.url - }); - - export const config = { path: "/echo" };`, - ) - - const directory = await fixture.create() - const handler = new EdgeFunctionsHandler({ - configDeclarations: [], - directories: [path.resolve(directory, 'netlify/edge-functions')], - env: { - VAR_1: 'value1', - VAR_2: 'value2', - }, - geolocation, - logger: console, - siteID: '123', - siteName: 'test', - }) - - const req = new Request('https://site.netlify/echo') - req.headers.set('x-nf-request-id', 'req-id') - - const match = await handler.match(req) - expect(match).toBeTruthy() - - const res = await match?.handle(req, serverAddress) - - expect(await res?.json()).toStrictEqual({ - env: { VAR_1: 'value1', VAR_2: 'value2' }, - geo: { - city: 'San Francisco', - country: { code: 'US', name: 'United States' }, - subdivision: { code: 'CA', name: 'California' }, - longitude: 0, - latitude: 0, - timezone: 'UTC', - }, - params: {}, - server: { region: 'dev' }, - site: { id: '123', name: 'test', url: serverAddress }, - url: `${serverAddress}/echo`, - }) - - await fixture.destroy() - }) - - test('Runs an edge function with a passthrough call', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/edge-functions/echo.mjs', - `export default async (req, context) => { - const res = await context.next(); - const text = await res.text(); - - return new Response(text.toUpperCase(), res); - } - - export const config = { path: "/yell" };`, - ) - - const directory = await fixture.create() - const handler = new EdgeFunctionsHandler({ - configDeclarations: [], - directories: [path.resolve(directory, 'netlify/edge-functions')], - env: { - VAR_1: 'value1', - VAR_2: 'value2', - }, - geolocation, - logger: console, - siteID: '123', - siteName: 'test', - }) - - const req = new Request('https://site.netlify/yell') - req.headers.set('x-nf-request-id', 'req-id') - - const match = await handler.match(req) - expect(match).toBeTruthy() - - const res = await match?.handle(req, serverAddress) - - expect(await res?.text()).toStrictEqual('FROM ORIGIN') - - await fixture.destroy() - }) - - test('Runs an edge function with an npm package', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/edge-functions/slugify.mjs', - `import slugify from 'slugify' - - export default async (req) => { - const text = new URL(req.url).searchParams.get('text') || '' - const slug = slugify(text, { lower: true }) - - return Response.json({ slug }) - } - - export const config = { path: "/slugify" };`, - ) - .withPackages({ - slugify: '^1.6.0', - }) - - const directory = await fixture.create() - const handler = new EdgeFunctionsHandler({ - configDeclarations: [], - directories: [path.resolve(directory, 'netlify/edge-functions')], - env: { - VAR_1: 'value1', - VAR_2: 'value2', - }, - geolocation, - logger: console, - siteID: '123', - siteName: 'test', - }) - - const req = new Request('https://site.netlify/slugify?text=Hello World') - req.headers.set('x-nf-request-id', 'req-id') - - const match = await handler.match(req) - expect(match).toBeTruthy() - - const res = await match?.handle(req, serverAddress) - - expect(await res?.json()).toStrictEqual({ - slug: 'hello-world', - }) - - await fixture.destroy() - }) - - test('Runs an edge function with header conditions', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/edge-functions/echo.mjs', - `export default async (req, context) => new Response("Hello from edge function"); - - export const config = { - path: "/echo", - header: { - "x-present": true, - "x-absent": false, - "x-match": "something" - } - };`, - ) - - const directory = await fixture.create() - const handler = new EdgeFunctionsHandler({ - configDeclarations: [], - directories: [path.resolve(directory, 'netlify/edge-functions')], - env: {}, - geolocation, - logger: console, - siteID: '123', - siteName: 'test', - }) - - const req1 = new Request('https://site.netlify/echo') - req1.headers.set('x-nf-request-id', 'req-id') - expect(await handler.match(req1)).toBeFalsy() - - const req2 = new Request('https://site.netlify/echo') - req2.headers.set('x-nf-request-id', 'req-id') - req2.headers.set('x-present', '1') - req2.headers.set('x-match', 'something good') - expect(await handler.match(req2)).toBeTruthy() - - const req3 = new Request('https://site.netlify/echo') - req3.headers.set('x-nf-request-id', 'req-id') - req3.headers.set('x-present', '1') - req3.headers.set('x-absent', '1') - req3.headers.set('x-match', 'something good') - expect(await handler.match(req3)).toBeFalsy() - - await fixture.destroy() - }) - - test('Throws an error when the edge function has unparseable code', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/edge-functions/unparseable.mjs', - `export default async () => new Response("Hello"); - - // This is the problem! - export const config = { path: "/unparseable };`, - ) - - const directory = await fixture.create() - const handler = new EdgeFunctionsHandler({ - configDeclarations: [], - directories: [path.resolve(directory, 'netlify/edge-functions')], - env: {}, - geolocation, - logger: console, - requestTimeout: 1_000, - siteID: '123', - siteName: 'test', - }) - - const req = new Request('https://site.netlify/unparseable') - req.headers.set('x-nf-request-id', 'req-id') - - const match = await handler.match(req) - expect(match).toBeTruthy() - - const res = await match?.handle(req, serverAddress) - - expect(res?.status).toBe(500) - expect(await res?.text()).toContain('Failed to parse edge function `unparseable`') - - await fixture.destroy() - }) - - test('Aborts an invocation if the function takes too long to produce a response', async () => { - const fixture = new Fixture() - .withFile( - 'netlify.toml', - `[build] - publish = "public" - `, - ) - .withFile( - 'netlify/edge-functions/slow.mjs', - `export default async () => { - await new Promise(resolve => setTimeout(resolve, 2_000)); - - return new Response("Done"); - }; - - export const config = { path: "/slow" };`, - ) - - const directory = await fixture.create() - const handler = new EdgeFunctionsHandler({ - configDeclarations: [], - directories: [path.resolve(directory, 'netlify/edge-functions')], - env: {}, - geolocation, - logger: console, - requestTimeout: 1_000, - siteID: '123', - siteName: 'test', - }) - - const req = new Request('https://site.netlify/slow') - req.headers.set('x-nf-request-id', 'req-id') - - const match = await handler.match(req) - expect(match).toBeTruthy() - - const res = await match?.handle(req, serverAddress) - - expect(res?.status).toBe(500) - expect(await res?.text()).toContain('An edge function took too long to produce a response') - - await fixture.destroy() - }) -}) diff --git a/packages/edge-functions/dev/src/node/main.ts b/packages/edge-functions/dev/src/node/main.ts deleted file mode 100644 index ca98cf6..0000000 --- a/packages/edge-functions/dev/src/node/main.ts +++ /dev/null @@ -1,407 +0,0 @@ -import path from 'node:path' -import { fileURLToPath, pathToFileURL } from 'node:url' - -import { - type Logger, - renderFunctionErrorPage, - killProcess, - type Geolocation, - type ProcessRef, -} from '@netlify/dev-utils' -import { - find, - generateManifest, - mergeDeclarations, - DenoBridge, - Declaration, - EdgeFunction, - FunctionConfig, -} from '@netlify/edge-bundler' -import { base64Encode } from '@netlify/runtime-utils' -import getAvailablePort from 'get-port' - -import type { RunOptions, SerializedError } from '../shared/types.js' -import { headers } from './headers.js' - -interface EdgeFunctionsHandlerOptions { - configDeclarations: Declaration[] - directories: string[] - env: Record - geolocation: Geolocation - logger: Logger - requestTimeout?: number - siteID?: string - siteName?: string -} - -const denoRunPath = path.resolve(fileURLToPath(import.meta.url), '../../deno/server.mjs') -const DENO_SERVER_POLL_INTERVAL = 50 -const DENO_SERVER_POLL_TIMEOUT = 3000 -const LOCAL_HOST = '127.0.0.1' - -// The timeout imposed by the edge nodes. It's important to keep this in place -// as a fallback in case we're unable to patch `fetch` to add our own here. -// https://github.com/netlify/stargate/blob/b5bc0eeb79bbbad3a8a6f41c7c73f1bcbcb8a9c8/proxy/deno/edge.go#L77 -const UPSTREAM_REQUEST_TIMEOUT = 37_000 - -// The overall timeout should be at most the limit imposed by the edge nodes -// minus a buffer that gives us enough time to send back a response. -const REQUEST_TIMEOUT = UPSTREAM_REQUEST_TIMEOUT - 1_000 - -export type EdgeFunctionsMatch = Awaited> - -export class EdgeFunctionsHandler { - private configDeclarations: Declaration[] - private denoServerProcess?: ProcessRef - private directories: string[] - private geolocation: Geolocation - private initialization: ReturnType - private initialized: boolean - private stopped: boolean - private logger: Logger - private requestTimeout: number - private siteID?: string - private siteName?: string - - constructor(options: EdgeFunctionsHandlerOptions) { - this.configDeclarations = options.configDeclarations - this.directories = options.directories - this.geolocation = options.geolocation - this.initialization = this.initialize({ - ...options.env, - DENO_REGION: 'dev', - }) - this.initialized = false - this.stopped = false - this.logger = options.logger - this.requestTimeout = options.requestTimeout ?? REQUEST_TIMEOUT - this.siteID = options.siteID - this.siteName = options.siteName - } - - /** - * Retrieves the in-source configuration objects for a set of edge functions. - * The evaluation of the functions and the retrieval of the configs must take - * place in Deno, but all the logic for processing those configurations and - * merging them with other sources lives in Node.js. To keep a single source - * of truth, we make a request to the Deno server with a special method that - * instructs the handler to evaluate the functions and return their configs, - * which are then returned by this method. - */ - private async getFunctionConfigs(denoPort: number, functions: Record) { - const url = new URL(`http://${LOCAL_HOST}:${denoPort.toString()}`) - url.searchParams.set('functions', encodeURIComponent(JSON.stringify(functions))) - - const res = await fetch(url, { - method: 'NETLIFYCONFIG', - }) - const data = (await res.json()) as unknown - - if (res.ok) { - return { configs: data as Record } - } - - return { error: (data as { error: SerializedError }).error } - } - - /** - * Returns the list of edge functions that should run for a given request. - * It computes both the names of the edge functions that should run as well - * as the invocation metadata object that must be included in the request. - */ - private getFunctionsForRequest( - req: Request, - availableFunctions: EdgeFunction[], - functionConfigs: Record, - ) { - const url = new URL(req.url) - const declarations = mergeDeclarations(this.configDeclarations, functionConfigs, {}, []) - const { manifest } = generateManifest({ - declarations, - userFunctionConfig: functionConfigs, - functions: availableFunctions, - }) - const matchingFunctionNames: string[] = [] - const routeIndexes: number[] = [] - const routes = [...manifest.routes, ...manifest.post_cache_routes] - - routes.forEach((route, index) => { - if (route.methods && route.methods.length !== 0 && !route.methods.includes(req.method)) { - return - } - - const pattern = new RegExp(route.pattern) - if (!pattern.test(url.pathname)) { - return - } - - if (route.headers) { - const headerMatches = Object.entries(route.headers).every(([headerName, headerMatch]) => { - const requestHeaderValue = req.headers.get(headerName) - - if (headerMatch?.matcher === 'exists') { - return requestHeaderValue !== null - } - - if (headerMatch?.matcher === 'missing') { - return requestHeaderValue === null - } - - if (requestHeaderValue && headerMatch?.matcher === 'regex') { - const pattern = new RegExp(headerMatch.pattern) - - return pattern.test(requestHeaderValue.split(', ').join(',')) - } - - return false - }) - - if (!headerMatches) { - return - } - } - - const isExcludedForFunction = manifest.function_config[route.function]?.excluded_patterns?.some((pattern) => - new RegExp(pattern).test(url.pathname), - ) - if (isExcludedForFunction) { - return - } - - const isExcludedForRoute = route.excluded_patterns.some((pattern) => new RegExp(pattern).test(url.pathname)) - if (isExcludedForRoute) { - return - } - - matchingFunctionNames.push(route.function) - routeIndexes.push(index) - }) - - const invocationMetadata = { - function_config: manifest.function_config, - req_routes: routeIndexes, - routes: routes.map((route) => ({ - function: route.function, - path: route.path, - pattern: route.pattern, - })), - } - - return { functionNames: matchingFunctionNames, invocationMetadata } - } - - /** - * Runs a request through the edge functions handler. The request may or may - * not match any edge functions: if it does, this method takes ownership of - * the request and returns the corresponding response; if it doesn't, the - * method returns `undefined`. - */ - async match(request: Request) { - if (request.headers.has(headers.Passthrough)) { - return - } - - const functions = await find(this.directories) - if (functions.length === 0) { - return - } - - const functionsMap = functions.reduce>( - (acc, { name, path }) => ({ - ...acc, - [name]: pathToFileURL(path).toString(), - }), - {}, - ) - - const initMessage = setTimeout(() => { - if (this.initialized) { - return - } - - this.logger.log( - 'Setting up the Netlify Edge Functions environment. This may take up to a couple of minutes, depending on your internet connection.', - ) - }, 5_000) - - const { denoPort, success } = await this.initialization - if (!success) { - clearTimeout(initMessage) - - return - } - - const acceptsHTML = Boolean(request.headers.get('accept')?.includes('text/html')) - const { configs, error } = await this.getFunctionConfigs(denoPort, functionsMap) - if (error) { - return { handle: () => this.renderError(JSON.stringify({ error }), acceptsHTML) } - } - - const { functionNames, invocationMetadata } = this.getFunctionsForRequest(request, functions, configs) - if (functionNames.length === 0) { - return - } - - return { - handle: async (request: Request, originServerAddress: string) => { - const originURL = new URL(originServerAddress) - - const url = new URL(request.url) - url.hostname = LOCAL_HOST - url.port = denoPort.toString() - url.protocol = 'http:' - - request.headers.set(headers.AcceptEncoding, 'identity') - request.headers.set(headers.AvailableFunctions, JSON.stringify(functionsMap)) - request.headers.set(headers.DeployContext, 'dev') - request.headers.set(headers.DeployID, '0') - request.headers.set(headers.ForwardedHost, `localhost:${originURL.port}`) - request.headers.set(headers.ForwardedProtocol, `http:`) - request.headers.set(headers.Functions, functionNames.join(',')) - request.headers.set(headers.Geo, base64Encode(this.geolocation)) - request.headers.set(headers.InvocationMetadata, base64Encode(invocationMetadata)) - request.headers.set(headers.IP, LOCAL_HOST) - request.headers.set(headers.Passthrough, 'passthrough') - request.headers.set(headers.PassthroughHost, `localhost:${originURL.port}`) - request.headers.set(headers.PassthroughProtocol, 'http:') - - const site = { - id: this.siteID, - name: this.siteName, - url: originServerAddress, - } - - request.headers.set(headers.Site, base64Encode(site)) - - // Proxying the request to the Deno server. - const response = await fetch(url, request) - - const isUncaughtError = response.headers.has(headers.UncaughtError) - if (isUncaughtError) { - return await this.renderError(await response.text(), acceptsHTML) - } - - return response - }, - } - } - - /** - * Initializes the Deno server where the edge functions will run. - */ - private async initialize(env: Record) { - let success = true - - const processRef: ProcessRef = {} - this.denoServerProcess = processRef - - // If we ran the server on a random port, we wouldn't know how to reach it. - // Compute the port upfront and pass it on to the server. - const denoPort = await getAvailablePort() - const denoBridge = new DenoBridge({ - // TODO: Remove this override once `@netlify/edge-bundler` has been - // updated to require Deno 2.x. - versionRange: '^2.2.4', - }) - const runOptions: RunOptions = { - denoPort, - requestTimeout: this.requestTimeout, - } - const denoFlags: string[] = ['--allow-scripts', '--quiet', '--no-lock'] - const script = `import('${pathToFileURL(denoRunPath).toString()}');` - - try { - await denoBridge.runInBackground(['eval', ...denoFlags, script, JSON.stringify(runOptions)], processRef, { - env, - extendEnv: false, - pipeOutput: true, - }) - if (this.stopped) { - await killProcess(processRef.ps) - this.denoServerProcess = undefined - success = false - } - } catch (error) { - success = false - - this.logger.error(`An error occurred while setting up the Netlify Edge Functions environment: ${String(error)}`) - } - - if (success) { - // The Promise above will resolve as soon as we start the command, but we - // must wait for it to actually listen for requests. - await this.waitForDenoServer(denoPort) - } - - this.initialized = true - - return { - denoPort, - success, - } - } - - private async renderError(errorBuffer: string, acceptsHTML: boolean): Promise { - const status = 500 - const { - error: { message, name, stack = '' }, - } = JSON.parse(errorBuffer) as { error: Error } - - if (!acceptsHTML) { - return new Response(`${name}: ${message}\n ${stack}`, { status }) - } - - const formattedError = JSON.stringify({ - errorType: name, - errorMessage: message, - trace: stack.split('\\n'), - }) - const errorBody = await renderFunctionErrorPage(formattedError, 'edge function') - - return new Response(errorBody, { - headers: { - 'Content-Type': 'text/html', - }, - status, - }) - } - - private async waitForDenoServer(port: number, count = 1): Promise { - try { - await fetch(`http://${LOCAL_HOST}:${port.toString()}`, { - method: 'HEAD', - }) - } catch { - // If we've already stopped the server, swallow the error. - if (!this.denoServerProcess) { - return - } - - if ((count + 1) * DENO_SERVER_POLL_INTERVAL > DENO_SERVER_POLL_TIMEOUT) { - throw new Error('Could not establish a connection to the Netlify Edge Functions local development server') - } - - await new Promise((resolve) => setTimeout(resolve, DENO_SERVER_POLL_INTERVAL)) - - return this.waitForDenoServer(port, count + 1) - } - } - - async stop() { - if (this.stopped) return - this.stopped = true - if (!this.denoServerProcess?.ps) { - return - } - - const { ps } = this.denoServerProcess - - this.denoServerProcess = undefined - - try { - await killProcess(ps) - } catch {} - } -} - -export { type Declaration } from '@netlify/edge-bundler' diff --git a/packages/edge-functions/dev/src/shared/types.ts b/packages/edge-functions/dev/src/shared/types.ts deleted file mode 100644 index 4752601..0000000 --- a/packages/edge-functions/dev/src/shared/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface RunOptions { - denoPort: number - requestTimeout: number -} - -export interface SerializedError { - message: string - name?: string - stack?: string -} diff --git a/packages/edge-functions/dev/tsconfig.json b/packages/edge-functions/dev/tsconfig.json deleted file mode 100644 index c8b61a2..0000000 --- a/packages/edge-functions/dev/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "node", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/edge-functions/dev/tsup.config.ts b/packages/edge-functions/dev/tsup.config.ts deleted file mode 100644 index 83e071b..0000000 --- a/packages/edge-functions/dev/tsup.config.ts +++ /dev/null @@ -1,49 +0,0 @@ -import fs from 'node:fs/promises' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import { argv } from 'node:process' - -import { getURL } from '@netlify/edge-functions-bootstrap/version' -import { execa } from 'execa' -import { defineConfig } from 'tsup' - -const __filename = fileURLToPath(import.meta.url) - -const BOOTSTRAP_FILENAME = 'bootstrap.mjs' - -export default defineConfig({ - clean: true, - outDir: 'dist/node', - entry: ['src/node/main.ts'], - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - - // Using a custom function to copy the contents of the `deno` directory and - // preserve the original structure, so that the relative path to the worker - // files is consistent. - onSuccess: async () => { - const bootstrapURL = await getURL() - const denoPath = path.resolve(path.dirname(__filename), 'src', 'deno') - const distPath = path.resolve(path.dirname(__filename), 'dist') - - await fs.cp(denoPath, path.resolve(distPath, 'deno'), { recursive: true }) - - // We need to bundle the bootstrap layer with the package because Deno - // does not support HTTP imports when inside a `node_modules` directory. - const distBootstrapPath = path.resolve(distPath, 'deno', BOOTSTRAP_FILENAME) - await execa('deno', ['run', '--allow-all', '--no-lock', 'bootstrap-bundle.mjs', bootstrapURL, distBootstrapPath], { - stdio: 'inherit', - }) - - // In addition to putting the bootstrap file in `dist`, we must also - // put it in the source directory so that the reference to the bootstrap - // file still works in tests and local development. This is not great. At - // least we're gitignoring the file so that it doesn't end up in version - // control. - await fs.cp(distBootstrapPath, path.resolve(denoPath, BOOTSTRAP_FILENAME)) - }, -}) diff --git a/packages/edge-functions/prod/CHANGELOG.md b/packages/edge-functions/prod/CHANGELOG.md deleted file mode 100644 index 3ba28a1..0000000 --- a/packages/edge-functions/prod/CHANGELOG.md +++ /dev/null @@ -1,395 +0,0 @@ -# Changelog - -## [3.0.8](https://github.com/netlify/primitives/compare/edge-functions-v3.0.7...edge-functions-v3.0.8) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.7.0 to 2.8.0 - -## [3.0.7](https://github.com/netlify/primitives/compare/edge-functions-v3.0.6...edge-functions-v3.0.7) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.6.0 to 2.7.0 - -## [3.0.6](https://github.com/netlify/primitives/compare/edge-functions-v3.0.5...edge-functions-v3.0.6) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.5.0 to 2.6.0 - -## [3.0.5](https://github.com/netlify/primitives/compare/edge-functions-v3.0.4...edge-functions-v3.0.5) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.4.0 to 2.5.0 - -## [3.0.4](https://github.com/netlify/primitives/compare/edge-functions-v3.0.3...edge-functions-v3.0.4) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.3.0 to 2.4.0 - -## [3.0.3](https://github.com/netlify/primitives/compare/edge-functions-v3.0.2...edge-functions-v3.0.3) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.2.0 to 2.3.0 - -## [3.0.2](https://github.com/netlify/primitives/compare/edge-functions-v3.0.1...edge-functions-v3.0.2) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.1.0 to 2.2.0 - -## [3.0.1](https://github.com/netlify/primitives/compare/edge-functions-v3.0.0...edge-functions-v3.0.1) (2025-10-22) - - -### Bug Fixes - -* **types:** allow `global.Netlify` declaration merging ([#494](https://github.com/netlify/primitives/issues/494)) ([bd39b15](https://github.com/netlify/primitives/commit/bd39b15ee03ba88362ccd3a83f61530c03b2ceaa)) - -## [3.0.0](https://github.com/netlify/primitives/compare/edge-functions-v2.19.0...edge-functions-v3.0.0) (2025-10-19) - - -### ⚠ BREAKING CHANGES - -* split edge-functions package - -### Features - -* split edge-functions package ([495c76d](https://github.com/netlify/primitives/commit/495c76d9933a8da15bfe754ccdbf80fcf815538f)) - -## [2.19.0](https://github.com/netlify/primitives/compare/edge-functions-v2.18.2...edge-functions-v2.19.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.2.0 to 4.3.0 - * @netlify/runtime-utils bumped from 2.1.0 to 2.2.0 - * @netlify/types bumped from 2.0.3 to 2.1.0 - -## [2.18.2](https://github.com/netlify/primitives/compare/edge-functions-v2.18.1...edge-functions-v2.18.2) (2025-10-01) - - -### Bug Fixes - -* add extra types for ratelimiting ([#464](https://github.com/netlify/primitives/issues/464)) ([6d9fe05](https://github.com/netlify/primitives/commit/6d9fe053bf3f99f33fd9a44f3a2457e8da9fbc4e)) - -## [2.18.1](https://github.com/netlify/primitives/compare/edge-functions-v2.18.0...edge-functions-v2.18.1) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.3 to 4.2.0 - -## [2.18.0](https://github.com/netlify/primitives/compare/edge-functions-v2.17.4...edge-functions-v2.18.0) (2025-09-17) - - -### Features - -* add AI gateway ([#450](https://github.com/netlify/primitives/issues/450)) ([aece659](https://github.com/netlify/primitives/commit/aece65980d8a016dffa24fa3e91ef0f0630ef5f8)) - -## [2.17.4](https://github.com/netlify/primitives/compare/edge-functions-v2.17.3...edge-functions-v2.17.4) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.2 to 4.1.3 - * @netlify/types bumped from 2.0.2 to 2.0.3 - -## [2.17.3](https://github.com/netlify/primitives/compare/edge-functions-v2.17.2...edge-functions-v2.17.3) (2025-08-26) - - -### Bug Fixes - -* **deps:** update dependency @netlify/edge-functions-bootstrap to ^2.16.0 ([#410](https://github.com/netlify/primitives/issues/410)) ([4ddfeec](https://github.com/netlify/primitives/commit/4ddfeec097be72e2939a9dca303cb094a0af00af)) - -## [2.17.2](https://github.com/netlify/primitives/compare/edge-functions-v2.17.1...edge-functions-v2.17.2) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.1 to 4.1.2 - -## [2.17.1](https://github.com/netlify/primitives/compare/edge-functions-v2.17.0...edge-functions-v2.17.1) (2025-08-14) - - -### Bug Fixes - -* **deps:** update netlify packages ([#411](https://github.com/netlify/primitives/issues/411)) ([bad2dce](https://github.com/netlify/primitives/commit/bad2dceae8b5e5f56d947ce2332372d148819ccc)) - -## [2.17.0](https://github.com/netlify/primitives/compare/edge-functions-v2.16.3...edge-functions-v2.17.0) (2025-08-01) - - -### Features - -* accept `IncomingMessage` in handler ([#267](https://github.com/netlify/primitives/issues/267)) ([aa84022](https://github.com/netlify/primitives/commit/aa84022cf9ecb2258dce39b87b0a21ec73524914)) -* add `serverAddress` to request handler ([#308](https://github.com/netlify/primitives/issues/308)) ([fa811f2](https://github.com/netlify/primitives/commit/fa811f24d473d471108f560abc484d17ea11bd70)) -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) -* improve error handling in edge functions ([#246](https://github.com/netlify/primitives/issues/246)) ([c0be696](https://github.com/netlify/primitives/commit/c0be6963c8bd9a49bb967040c29580e7facaae03)) -* support header matching in edge functions ([#361](https://github.com/netlify/primitives/issues/361)) ([05791fb](https://github.com/netlify/primitives/commit/05791fba0498326bc764dbde39943983c13962c8)) - - -### Bug Fixes - -* add missing await and let server process be collected ([#319](https://github.com/netlify/primitives/issues/319)) ([1724d50](https://github.com/netlify/primitives/commit/1724d507b844a3b8e1ccb0b6c84a7e80d70d4d4c)) -* clean up edge functions server ([#310](https://github.com/netlify/primitives/issues/310)) ([243f3b4](https://github.com/netlify/primitives/commit/243f3b472d1350eb6a80d8f736385750de8bc0d4)) -* declare `Netlify` global in edge functions types ([#330](https://github.com/netlify/primitives/issues/330)) ([0546bb6](https://github.com/netlify/primitives/commit/0546bb6eccf0e61aae64973cef788cc75d2965d8)) -* **deps:** update dependency @netlify/edge-bundler to ^14.0.5 ([#243](https://github.com/netlify/primitives/issues/243)) ([44f18de](https://github.com/netlify/primitives/commit/44f18de491828e08d13d59622a7ec0554cffa21b)) -* **deps:** update dependency @netlify/edge-functions-bootstrap to ^2.14.0 ([#314](https://github.com/netlify/primitives/issues/314)) ([f52f332](https://github.com/netlify/primitives/commit/f52f332abcd51093dbd6d7ab05cccff931a22a52)) -* **deps:** update netlify packages ([#290](https://github.com/netlify/primitives/issues/290)) ([ca10da6](https://github.com/netlify/primitives/commit/ca10da69a916ef29bb6251822548f9dbefb58d06)) -* **deps:** update netlify packages ([#333](https://github.com/netlify/primitives/issues/333)) ([0fa1f1e](https://github.com/netlify/primitives/commit/0fa1f1e8d717cbc5c797c19b64b4fa4ffbdaf992)) -* **edge:** note when stopped so we can kill process in early init ([#313](https://github.com/netlify/primitives/issues/313)) ([3062d40](https://github.com/netlify/primitives/commit/3062d400e4b8387c43c6c03713c58d3b29325a5d)) -* fix `@netlify/edge-functions` exports ([#289](https://github.com/netlify/primitives/issues/289)) ([cfb8fac](https://github.com/netlify/primitives/commit/cfb8fac01437452168686f64a2afe76c990fe63e)) -* fix edge functions workers ([#298](https://github.com/netlify/primitives/issues/298)) ([0666593](https://github.com/netlify/primitives/commit/0666593a6d3d8cf85a0718025e5c0b11c120563c)) -* handle 304 responses from edge functions ([#364](https://github.com/netlify/primitives/issues/364)) ([08e2543](https://github.com/netlify/primitives/commit/08e254325163707a397c8dddc0761df6aad63fd7)) -* move deno typescript files to mjs + jsdoc ([#260](https://github.com/netlify/primitives/issues/260)) ([32fd66a](https://github.com/netlify/primitives/commit/32fd66a28f3cac321fd24fbab0b59fd46e126920)) -* pass run options to Deno script as arg ([#263](https://github.com/netlify/primitives/issues/263)) ([ec414cc](https://github.com/netlify/primitives/commit/ec414ccae9e40585b0cf5aa3bfe26992499fe47c)) -* reinstate missing edge functions types ([#280](https://github.com/netlify/primitives/issues/280)) ([f4360c9](https://github.com/netlify/primitives/commit/f4360c955812e7b96dfb1b0f8112d70496488ee2)) -* revamp dev and vite plugin logging ([#269](https://github.com/netlify/primitives/issues/269)) ([de9b46c](https://github.com/netlify/primitives/commit/de9b46c1cb1c7b2bf6437ab516134e44203d83b7)) - -## [2.16.3](https://github.com/netlify/primitives/compare/edge-functions-v2.16.2...edge-functions-v2.16.3) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.0 to 4.1.1 - -## [2.16.2](https://github.com/netlify/primitives/compare/edge-functions-v2.16.1...edge-functions-v2.16.2) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.0.0 to 4.1.0 - -## [2.16.1](https://github.com/netlify/primitives/compare/edge-functions-v2.16.0...edge-functions-v2.16.1) (2025-07-21) - - -### Bug Fixes - -* handle 304 responses from edge functions ([#364](https://github.com/netlify/primitives/issues/364)) ([08e2543](https://github.com/netlify/primitives/commit/08e254325163707a397c8dddc0761df6aad63fd7)) - -## [2.16.0](https://github.com/netlify/primitives/compare/edge-functions-v2.15.8...edge-functions-v2.16.0) (2025-07-18) - - -### Features - -* support header matching in edge functions ([#361](https://github.com/netlify/primitives/issues/361)) ([05791fb](https://github.com/netlify/primitives/commit/05791fba0498326bc764dbde39943983c13962c8)) - -## [2.15.8](https://github.com/netlify/primitives/compare/edge-functions-v2.15.7...edge-functions-v2.15.8) (2025-07-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#333](https://github.com/netlify/primitives/issues/333)) ([0fa1f1e](https://github.com/netlify/primitives/commit/0fa1f1e8d717cbc5c797c19b64b4fa4ffbdaf992)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.3.0 to 4.0.0 - -## [2.15.7](https://github.com/netlify/primitives/compare/edge-functions-v2.15.6...edge-functions-v2.15.7) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.2.2 to 3.3.0 - -## [2.15.6](https://github.com/netlify/primitives/compare/edge-functions-v2.15.5...edge-functions-v2.15.6) (2025-07-07) - - -### Bug Fixes - -* declare `Netlify` global in edge functions types ([#330](https://github.com/netlify/primitives/issues/330)) ([0546bb6](https://github.com/netlify/primitives/commit/0546bb6eccf0e61aae64973cef788cc75d2965d8)) - -## [2.15.5](https://github.com/netlify/primitives/compare/edge-functions-v2.15.4...edge-functions-v2.15.5) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.2.1 to 3.2.2 - -## [2.15.4](https://github.com/netlify/primitives/compare/edge-functions-v2.15.3...edge-functions-v2.15.4) (2025-06-26) - - -### Bug Fixes - -* add missing await and let server process be collected ([#319](https://github.com/netlify/primitives/issues/319)) ([1724d50](https://github.com/netlify/primitives/commit/1724d507b844a3b8e1ccb0b6c84a7e80d70d4d4c)) - -## [2.15.3](https://github.com/netlify/primitives/compare/edge-functions-v2.15.2...edge-functions-v2.15.3) (2025-06-26) - - -### Bug Fixes - -* **deps:** update dependency @netlify/edge-functions-bootstrap to ^2.14.0 ([#314](https://github.com/netlify/primitives/issues/314)) ([f52f332](https://github.com/netlify/primitives/commit/f52f332abcd51093dbd6d7ab05cccff931a22a52)) - -## [2.15.2](https://github.com/netlify/primitives/compare/edge-functions-v2.15.1...edge-functions-v2.15.2) (2025-06-25) - - -### Bug Fixes - -* **edge:** note when stopped so we can kill process in early init ([#313](https://github.com/netlify/primitives/issues/313)) ([3062d40](https://github.com/netlify/primitives/commit/3062d400e4b8387c43c6c03713c58d3b29325a5d)) - -## [2.15.1](https://github.com/netlify/primitives/compare/edge-functions-v2.15.0...edge-functions-v2.15.1) (2025-06-18) - - -### Bug Fixes - -* clean up edge functions server ([#310](https://github.com/netlify/primitives/issues/310)) ([243f3b4](https://github.com/netlify/primitives/commit/243f3b472d1350eb6a80d8f736385750de8bc0d4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.2.0 to 3.2.1 - -## [2.15.0](https://github.com/netlify/primitives/compare/edge-functions-v2.14.5...edge-functions-v2.15.0) (2025-06-17) - - -### Features - -* add `serverAddress` to request handler ([#308](https://github.com/netlify/primitives/issues/308)) ([fa811f2](https://github.com/netlify/primitives/commit/fa811f24d473d471108f560abc484d17ea11bd70)) - -## [2.14.5](https://github.com/netlify/primitives/compare/edge-functions-v2.14.4...edge-functions-v2.14.5) (2025-06-06) - - -### Bug Fixes - -* fix edge functions workers ([#298](https://github.com/netlify/primitives/issues/298)) ([0666593](https://github.com/netlify/primitives/commit/0666593a6d3d8cf85a0718025e5c0b11c120563c)) - -## [2.14.4](https://github.com/netlify/primitives/compare/edge-functions-v2.14.3...edge-functions-v2.14.4) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.1.1 to 3.2.0 - -## [2.14.3](https://github.com/netlify/primitives/compare/edge-functions-v2.14.2...edge-functions-v2.14.3) (2025-06-06) - - -### Bug Fixes - -* **deps:** update netlify packages ([#290](https://github.com/netlify/primitives/issues/290)) ([ca10da6](https://github.com/netlify/primitives/commit/ca10da69a916ef29bb6251822548f9dbefb58d06)) -* fix `@netlify/edge-functions` exports ([#289](https://github.com/netlify/primitives/issues/289)) ([cfb8fac](https://github.com/netlify/primitives/commit/cfb8fac01437452168686f64a2afe76c990fe63e)) - -## [2.14.2](https://github.com/netlify/primitives/compare/edge-functions-v2.14.1...edge-functions-v2.14.2) (2025-06-04) - - -### Bug Fixes - -* reinstate missing edge functions types ([#280](https://github.com/netlify/primitives/issues/280)) ([f4360c9](https://github.com/netlify/primitives/commit/f4360c955812e7b96dfb1b0f8112d70496488ee2)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/types bumped from 2.0.1 to 2.0.2 - -## [2.14.1](https://github.com/netlify/primitives/compare/edge-functions-v2.14.0...edge-functions-v2.14.1) (2025-06-03) - - -### Bug Fixes - -* revamp dev and vite plugin logging ([#269](https://github.com/netlify/primitives/issues/269)) ([de9b46c](https://github.com/netlify/primitives/commit/de9b46c1cb1c7b2bf6437ab516134e44203d83b7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.1.0 to 3.1.1 - -## [2.14.0](https://github.com/netlify/primitives/compare/edge-functions-v2.13.2...edge-functions-v2.14.0) (2025-06-03) - - -### Features - -* accept `IncomingMessage` in handler ([#267](https://github.com/netlify/primitives/issues/267)) ([aa84022](https://github.com/netlify/primitives/commit/aa84022cf9ecb2258dce39b87b0a21ec73524914)) - -## [2.13.2](https://github.com/netlify/primitives/compare/edge-functions-v2.13.1...edge-functions-v2.13.2) (2025-06-03) - - -### Bug Fixes - -* pass run options to Deno script as arg ([#263](https://github.com/netlify/primitives/issues/263)) ([ec414cc](https://github.com/netlify/primitives/commit/ec414ccae9e40585b0cf5aa3bfe26992499fe47c)) - -## [2.13.1](https://github.com/netlify/primitives/compare/edge-functions-v2.13.0...edge-functions-v2.13.1) (2025-06-02) - - -### Bug Fixes - -* move deno typescript files to mjs + jsdoc ([#260](https://github.com/netlify/primitives/issues/260)) ([32fd66a](https://github.com/netlify/primitives/commit/32fd66a28f3cac321fd24fbab0b59fd46e126920)) - -## [2.13.0](https://github.com/netlify/primitives/compare/edge-functions-v2.12.0...edge-functions-v2.13.0) (2025-06-02) - - -### Features - -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) -* improve error handling in edge functions ([#246](https://github.com/netlify/primitives/issues/246)) ([c0be696](https://github.com/netlify/primitives/commit/c0be6963c8bd9a49bb967040c29580e7facaae03)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/edge-bundler to ^14.0.5 ([#243](https://github.com/netlify/primitives/issues/243)) ([44f18de](https://github.com/netlify/primitives/commit/44f18de491828e08d13d59622a7ec0554cffa21b)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 3.0.0 to 3.1.0 - * @netlify/runtime-utils bumped from 2.0.0 to 2.1.0 - * devDependencies - * @netlify/types bumped from 1.2.0 to 2.0.1 - -## Changelog diff --git a/packages/edge-functions/prod/package.json b/packages/edge-functions/prod/package.json deleted file mode 100644 index 7c6568d..0000000 --- a/packages/edge-functions/prod/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@netlify/edge-functions", - "version": "3.0.8", - "description": "TypeScript utilities for interacting with Netlify Edge Functions", - "type": "module", - "engines": { - "node": ">=18.0.0" - }, - "main": "./dist/main.js", - "exports": { - ".": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*", - "deno/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [ - "netlify", - "edge functions" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/edge-functions/prod" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "directories": { - "test": "test" - }, - "devDependencies": { - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "@netlify/types": "2.8.0" - } -} diff --git a/packages/edge-functions/prod/src/lib/config.ts b/packages/edge-functions/prod/src/lib/config.ts deleted file mode 100644 index 536cdf1..0000000 --- a/packages/edge-functions/prod/src/lib/config.ts +++ /dev/null @@ -1,72 +0,0 @@ -type Cache = 'off' | 'manual' - -export type Path = `/${string}` - -type OnError = 'fail' | 'bypass' | Path - -export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' - -export type HeadersConfig = Record - -type RateLimitAggregator = 'domain' | 'ip' - -type RateLimitAction = 'rate_limit' | 'rewrite' - -/** - * Netlify Custom Rate Limits inline configuration options. - */ -interface RateLimitConfig { - action?: RateLimitAction - aggregateBy?: RateLimitAggregator | RateLimitAggregator[] - to?: string - windowSize: number - windowLimit: number -} - -/** - * Netlify Edge Function inline configuration options. - * - * @see {@link https://docs.netlify.com/edge-functions/declarations/#declare-edge-functions-inline} - */ -export interface Config { - cache?: Cache - excludedPath?: Path | Path[] - excludedPattern?: string | string[] - header?: HeadersConfig - onError?: OnError - path?: Path | Path[] - pattern?: string | string[] - method?: HTTPMethod | HTTPMethod[] - rateLimit?: RateLimitConfig -} - -/** - * Framework-generated Netlify Edge Function inline configuration options. - * - * @see {@link https://docs.netlify.com/edge-functions/create-integration/#generate-declarations} - */ -export interface IntegrationsConfig extends Config { - name?: string - generator?: string -} - -/** - * A function configuration in the `manifest.json` file for framework-generated Netlify - * Edge Functions. - * - * @see {@link https://docs.netlify.com/edge-functions/declarations/#declare-edge-functions-inline} - */ -export interface ManifestFunction extends IntegrationsConfig { - function: string -} - -/** - * The `manifest.json` file for framework-generated Netlify Edge Functions. - * - * @see {@link https://docs.netlify.com/edge-functions/create-integration/#generate-declarations} - */ -export interface Manifest { - version: 1 - functions: ManifestFunction[] - import_map?: string -} diff --git a/packages/edge-functions/prod/src/lib/edge-function.ts b/packages/edge-functions/prod/src/lib/edge-function.ts deleted file mode 100644 index c7afa22..0000000 --- a/packages/edge-functions/prod/src/lib/edge-function.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { Context } from '@netlify/types' - -export type EdgeFunction = ( - request: Request, - context: Context, -) => Response | Promise | URL | Promise | undefined | Promise diff --git a/packages/edge-functions/prod/src/main.test.ts b/packages/edge-functions/prod/src/main.test.ts deleted file mode 100644 index ae57dd7..0000000 --- a/packages/edge-functions/prod/src/main.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { expect, test } from 'vitest' - -import * as main from './main.js' - -test('Main file does not export anything', () => { - expect(Object.keys(main)).toStrictEqual([]) -}) diff --git a/packages/edge-functions/prod/src/main.ts b/packages/edge-functions/prod/src/main.ts deleted file mode 100644 index d718f85..0000000 --- a/packages/edge-functions/prod/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { NetlifyGlobal } from '@netlify/types' - -declare global { - // Using `var` instead of `const` to allow TypeScript declaration merging. - // Multiple packages can declare the same global with `var`, but `const` cannot be redeclared. - var Netlify: NetlifyGlobal -} - -export type { Context, Cookie } from '@netlify/types' -export type { Config, IntegrationsConfig, Manifest, ManifestFunction } from './lib/config.js' -export type { EdgeFunction } from './lib/edge-function.js' diff --git a/packages/edge-functions/prod/tsconfig.json b/packages/edge-functions/prod/tsconfig.json deleted file mode 100644 index df1179a..0000000 --- a/packages/edge-functions/prod/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "rootDir": ".", - "moduleResolution": "nodenext", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } -} diff --git a/packages/edge-functions/prod/tsup.config.ts b/packages/edge-functions/prod/tsup.config.ts deleted file mode 100644 index 9a08857..0000000 --- a/packages/edge-functions/prod/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['esm'], - entry: ['src/main.ts'], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/functions/.gitignore b/packages/functions/.gitignore deleted file mode 100644 index 1eae0cf..0000000 --- a/packages/functions/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist/ -node_modules/ diff --git a/packages/functions/dev/CHANGELOG.md b/packages/functions/dev/CHANGELOG.md deleted file mode 100644 index dc298a5..0000000 --- a/packages/functions/dev/CHANGELOG.md +++ /dev/null @@ -1,340 +0,0 @@ -# Changelog - -## [1.3.0](https://github.com/netlify/primitives/compare/functions-dev-v1.2.11...functions-dev-v1.3.0) (2026-05-29) - - -### Features - -* add function config properties ([#696](https://github.com/netlify/primitives/issues/696)) ([e43cd8f](https://github.com/netlify/primitives/commit/e43cd8f132ec7d5c4517c29cb7c6dbe9dbd5b6b7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.8 to 10.7.9 - * @netlify/dev-utils bumped from 4.4.5 to 4.4.6 - * @netlify/functions bumped from 5.2.2 to 5.3.0 - -## [1.2.11](https://github.com/netlify/primitives/compare/functions-dev-v1.2.10...functions-dev-v1.2.11) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.7 to 10.7.8 - * @netlify/dev-utils bumped from 4.4.4 to 4.4.5 - * @netlify/functions bumped from 5.2.1 to 5.2.2 - -## [1.2.10](https://github.com/netlify/primitives/compare/functions-dev-v1.2.9...functions-dev-v1.2.10) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.6 to 10.7.7 - * @netlify/dev-utils bumped from 4.4.3 to 4.4.4 - -## [1.2.9](https://github.com/netlify/primitives/compare/functions-dev-v1.2.8...functions-dev-v1.2.9) (2026-05-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.5 to 10.7.6 - * @netlify/functions bumped from 5.2.0 to 5.2.1 - -## [1.2.8](https://github.com/netlify/primitives/compare/functions-dev-v1.2.7...functions-dev-v1.2.8) (2026-05-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.4 to 10.7.5 - -## [1.2.7](https://github.com/netlify/primitives/compare/functions-dev-v1.2.6...functions-dev-v1.2.7) (2026-05-11) - - -### Bug Fixes - -* **deps:** update netlify packages ([#674](https://github.com/netlify/primitives/issues/674)) ([8179496](https://github.com/netlify/primitives/commit/8179496fad479522f329cc99d03175408bffcb0c)) - -## [1.2.6](https://github.com/netlify/primitives/compare/functions-dev-v1.2.5...functions-dev-v1.2.6) (2026-04-14) - - -### Bug Fixes - -* preserve multi-value response headers in dev ([#646](https://github.com/netlify/primitives/issues/646)) ([f18e24b](https://github.com/netlify/primitives/commit/f18e24b162d7889384131c01b60eff07d425d80e)) - -## [1.2.5](https://github.com/netlify/primitives/compare/functions-dev-v1.2.4...functions-dev-v1.2.5) (2026-04-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 5.1.5 to 5.2.0 - -## [1.2.4](https://github.com/netlify/primitives/compare/functions-dev-v1.2.3...functions-dev-v1.2.4) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.3 to 10.7.4 - * @netlify/dev-utils bumped from 4.4.2 to 4.4.3 - * @netlify/functions bumped from 5.1.4 to 5.1.5 - -## [1.2.3](https://github.com/netlify/primitives/compare/functions-dev-v1.2.2...functions-dev-v1.2.3) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.2 to 10.7.3 - * @netlify/dev-utils bumped from 4.4.1 to 4.4.2 - * @netlify/functions bumped from 5.1.3 to 5.1.4 - -## [1.2.2](https://github.com/netlify/primitives/compare/functions-dev-v1.2.1...functions-dev-v1.2.2) (2026-03-13) - - -### Bug Fixes - -* **deps:** update netlify packages ([#626](https://github.com/netlify/primitives/issues/626)) ([a87ba84](https://github.com/netlify/primitives/commit/a87ba84fa23c3a4ff506cd9c3d5f3b5cd78d9f3c)) - -## [1.2.1](https://github.com/netlify/primitives/compare/functions-dev-v1.2.0...functions-dev-v1.2.1) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.1 to 10.7.2 - * @netlify/dev-utils bumped from 4.4.0 to 4.4.1 - * @netlify/functions bumped from 5.1.2 to 5.1.3 - -## [1.2.0](https://github.com/netlify/primitives/compare/functions-dev-v1.1.12...functions-dev-v1.2.0) (2026-03-10) - - -### Features - -* add `FileWatcher` class ([#607](https://github.com/netlify/primitives/issues/607)) ([1f8bdfc](https://github.com/netlify/primitives/commit/1f8bdfc06e411703cc9338b9cd7dfe3a0c0f4eff)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.7.0 to 10.7.1 - * @netlify/dev-utils bumped from 4.3.3 to 4.4.0 - -## [1.1.12](https://github.com/netlify/primitives/compare/functions-dev-v1.1.11...functions-dev-v1.1.12) (2026-02-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#583](https://github.com/netlify/primitives/issues/583)) ([bcd8241](https://github.com/netlify/primitives/commit/bcd824172757fecac5aa91dc36b06163efb63497)) - -## [1.1.11](https://github.com/netlify/primitives/compare/functions-dev-v1.1.10...functions-dev-v1.1.11) (2026-02-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.6.0 to 10.7.0 - -## [1.1.10](https://github.com/netlify/primitives/compare/functions-dev-v1.1.9...functions-dev-v1.1.10) (2026-02-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.5.0 to 10.6.0 - -## [1.1.9](https://github.com/netlify/primitives/compare/functions-dev-v1.1.8...functions-dev-v1.1.9) (2026-01-28) - - -### Bug Fixes - -* **deps:** update netlify packages ([#576](https://github.com/netlify/primitives/issues/576)) ([1c6ff24](https://github.com/netlify/primitives/commit/1c6ff247318b8cdb1961ce76e96fe423a4ec8cd7)) - -## [1.1.8](https://github.com/netlify/primitives/compare/functions-dev-v1.1.7...functions-dev-v1.1.8) (2026-01-19) - - -### Bug Fixes - -* **deps:** update netlify packages ([#566](https://github.com/netlify/primitives/issues/566)) ([184656a](https://github.com/netlify/primitives/commit/184656af871a81bddc69e9133f22bfa945f28ebf)) - -## [1.1.7](https://github.com/netlify/primitives/compare/functions-dev-v1.1.6...functions-dev-v1.1.7) (2025-12-21) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 5.1.1 to 5.1.2 - -## [1.1.6](https://github.com/netlify/primitives/compare/functions-dev-v1.1.5...functions-dev-v1.1.6) (2025-12-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.4 to 10.5.0 - -## [1.1.5](https://github.com/netlify/primitives/compare/functions-dev-v1.1.4...functions-dev-v1.1.5) (2025-12-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.3 to 10.4.4 - -## [1.1.4](https://github.com/netlify/primitives/compare/functions-dev-v1.1.3...functions-dev-v1.1.4) (2025-12-08) - - -### Bug Fixes - -* **deps:** update netlify packages ([#557](https://github.com/netlify/primitives/issues/557)) ([60644bf](https://github.com/netlify/primitives/commit/60644bf6863a0ba41d9e73b0d8d1cfa90205c963)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.2 to 10.4.3 - * @netlify/dev-utils bumped from 4.3.2 to 4.3.3 - * @netlify/functions bumped from 5.1.0 to 5.1.1 - -## [1.1.3](https://github.com/netlify/primitives/compare/functions-dev-v1.1.2...functions-dev-v1.1.3) (2025-12-03) - - -### Bug Fixes - -* **deps:** update netlify packages ([#549](https://github.com/netlify/primitives/issues/549)) ([ec4fb29](https://github.com/netlify/primitives/commit/ec4fb2978af5cf75c12645ade9f771bc94a796e2)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.1 to 10.4.2 - -## [1.1.2](https://github.com/netlify/primitives/compare/functions-dev-v1.1.1...functions-dev-v1.1.2) (2025-11-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.4.0 to 10.4.1 - -## [1.1.1](https://github.com/netlify/primitives/compare/functions-dev-v1.1.0...functions-dev-v1.1.1) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.3 to 10.4.0 - * @netlify/dev-utils bumped from 4.3.1 to 4.3.2 - -## [1.1.0](https://github.com/netlify/primitives/compare/functions-dev-v1.0.5...functions-dev-v1.1.0) (2025-11-05) - - -### Features - -* implement functions timeout defaults and overrides in dev ([#346](https://github.com/netlify/primitives/issues/346)) ([c17753e](https://github.com/netlify/primitives/commit/c17753ec35bdef076db563fa37c1a4222bd5c149)) - - -### Bug Fixes - -* **deps:** update netlify packages ([#515](https://github.com/netlify/primitives/issues/515)) ([67034cc](https://github.com/netlify/primitives/commit/67034cce9f80e35582f328b1990d0f26e7181cff)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.2 to 10.3.3 - * @netlify/dev-utils bumped from 4.3.0 to 4.3.1 - * @netlify/functions bumped from 5.0.1 to 5.1.0 - -## [1.0.5](https://github.com/netlify/primitives/compare/functions-dev-v1.0.4...functions-dev-v1.0.5) (2025-11-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.1 to 10.3.2 - -## [1.0.4](https://github.com/netlify/primitives/compare/functions-dev-v1.0.3...functions-dev-v1.0.4) (2025-10-29) - - -### Bug Fixes - -* **deps:** update netlify packages ([#504](https://github.com/netlify/primitives/issues/504)) ([3586853](https://github.com/netlify/primitives/commit/35868533dd9f878b4162685131219419ca33bd8a)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.3.0 to 10.3.1 - -## [1.0.3](https://github.com/netlify/primitives/compare/functions-dev-v1.0.2...functions-dev-v1.0.3) (2025-10-27) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.2.1 to 10.3.0 - -## [1.0.2](https://github.com/netlify/primitives/compare/functions-dev-v1.0.1...functions-dev-v1.0.2) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.2.0 to 10.2.1 - -## [1.0.1](https://github.com/netlify/primitives/compare/functions-dev-v1.0.0...functions-dev-v1.0.1) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.1.0 to 10.2.0 - * @netlify/functions bumped from 5.0.0 to 5.0.1 - -## 1.0.0 (2025-10-14) - - -### ⚠ BREAKING CHANGES - -* The `/dev` export, introduced in version 3.1.0, has been removed. - -### Features - -* extract dev logic into new `@netlify/functions-dev` package ([#475](https://github.com/netlify/primitives/issues/475)) ([0730f5f](https://github.com/netlify/primitives/commit/0730f5f40ace6cd37ffc1f54a7ebb4f405bbca65)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/functions bumped from 4.3.0 to 5.0.0 diff --git a/packages/functions/dev/package.json b/packages/functions/dev/package.json deleted file mode 100644 index a7dd109..0000000 --- a/packages/functions/dev/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "@netlify/functions-dev", - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "type": "module", - "exports": { - ".": { - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - } - }, - "version": "1.3.0", - "description": "Local dev emulation of Netlify Functions", - "files": [ - "dist/**/*.js", - "dist/**/*.mjs", - "dist/**/*.d.ts", - "dist/**/*.d.mts" - ], - "scripts": { - "dev": "tsup-node --watch", - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest" - }, - "keywords": [ - "netlify", - "functions", - "serverless" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/functions/dev" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "@netlify/blobs": "10.7.9", - "@netlify/dev-utils": "4.4.6", - "@netlify/functions": "5.3.0", - "@netlify/zip-it-and-ship-it": "^14.5.5", - "cron-parser": "^4.9.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", - "semver": "^7.6.3", - "source-map-support": "^0.5.21" - }, - "devDependencies": { - "@types/semver": "^7.5.8", - "@types/source-map-support": "^0.5.10", - "npm-run-all2": "^5.0.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, - "engines": { - "node": ">=20.6.1" - } -} diff --git a/packages/functions/dev/src/builder.ts b/packages/functions/dev/src/builder.ts deleted file mode 100644 index 4e8a655..0000000 --- a/packages/functions/dev/src/builder.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MemoizeCache } from '@netlify/dev-utils' -import { ExtendedRoute, FunctionResult, ModuleFormat } from '@netlify/zip-it-and-ship-it' - -export interface FunctionBuilder { - build: ({ cache }: { cache: BuildCache }) => Promise - builderName: string -} - -export interface BuildResult { - buildPath: string - excludedRoutes?: ExtendedRoute[] - includedFiles?: string[] - invocationMode?: FunctionResult['invocationMode'] - outputModuleFormat?: ModuleFormat - mainFile: string - routes?: ExtendedRoute[] - runtimeAPIVersion?: number - srcFiles: string[] - schedule?: string - targetDirectory?: string -} - -export type BuildCache = MemoizeCache diff --git a/packages/functions/dev/src/events.ts b/packages/functions/dev/src/events.ts deleted file mode 100644 index e835448..0000000 --- a/packages/functions/dev/src/events.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { DevEvent } from '@netlify/dev-utils' - -import type { NetlifyFunction } from './function.js' - -export interface FunctionBuildErrorEvent extends DevEvent { - error: Error | null - function: NetlifyFunction -} - -export interface FunctionExtractedEvent extends DevEvent { - function: NetlifyFunction -} - -export interface FunctionLoadedEvent extends DevEvent { - firstLoad: boolean - function: NetlifyFunction -} - -export interface FunctionMissingTypesPackageEvent extends DevEvent {} - -export interface FunctionNotInvokableOnPathEvent extends DevEvent { - function: NetlifyFunction - urlPath: string -} - -export interface FunctionRegisteredEvent extends DevEvent { - function: NetlifyFunction -} - -export interface FunctionReloadingEvent extends DevEvent { - function: NetlifyFunction -} - -export interface FunctionRemovedEvent extends DevEvent { - function: NetlifyFunction -} diff --git a/packages/functions/dev/src/function.ts b/packages/functions/dev/src/function.ts deleted file mode 100644 index ad380c9..0000000 --- a/packages/functions/dev/src/function.ts +++ /dev/null @@ -1,446 +0,0 @@ -import { basename, extname } from 'node:path' -import { version as nodeVersion } from 'node:process' - -import { EnvironmentContext } from '@netlify/blobs' -import { headers as netlifyHeaders, MemoizeCache, renderFunctionErrorPage } from '@netlify/dev-utils' -import type { ExtendedRoute, FunctionResult, Route } from '@netlify/zip-it-and-ship-it' -import CronParser from 'cron-parser' -import semver from 'semver' - -import { BuildResult } from './builder.js' -import { Runtime } from './runtimes/index.js' -import { HandlerContext } from '@netlify/functions' - -export type FunctionBuildCache = MemoizeCache - -const BACKGROUND_FUNCTION_SUFFIX = '-background' -const TYPESCRIPT_EXTENSIONS = new Set(['.cts', '.mts', '.ts']) -const V2_MIN_NODE_VERSION = '18.14.0' - -// Returns a new set with all elements of `setA` that don't exist in `setB`. -const difference = (setA: Set, setB: Set) => new Set([...setA].filter((item) => !setB.has(item))) - -const getNextRun = function (schedule: string) { - const cron = CronParser.parseExpression(schedule, { - tz: 'Etc/UTC', - }) - return cron.next().toDate() -} - -export interface InvocationError { - errorMessage: string - errorType: string - stackTrace: string[] -} - -export const getBlobsEventProperty = (context: EnvironmentContext) => ({ - primary_region: context.primaryRegion, - url: context.edgeURL, - url_uncached: context.edgeURL, - token: context.token, -}) - -interface NetlifyFunctionOptions { - blobsContext?: EnvironmentContext - config: any - directory: string - displayName?: string - excludedRoutes?: Route[] - mainFile: string - name: string - projectRoot: string - routes?: ExtendedRoute[] - runtime: Runtime - settings: any - timeoutBackground: number - timeoutSynchronous: number -} - -interface InvokeFunctionOptions { - buildCache?: FunctionBuildCache - buildDirectory?: string - clientContext?: HandlerContext['clientContext'] - request: Request - route?: string -} - -export class NetlifyFunction { - public name: string - public mainFile: string - public displayName: string - public schedule?: string - public runtime: Runtime - - private readonly blobsContext?: EnvironmentContext - private readonly config: any - private readonly directory: string - private readonly projectRoot: string - private readonly settings: any - private readonly timeoutBackground: number - private readonly timeoutSynchronous: number - - // Determines whether this is a background function. Checks (in order): - // 1. ZISI build data — `invocationMode === 'background'` captures the - // filename suffix AND the in-source `config.background: true`. - // 2. The TOML config — `[functions.] background = true`. - // 3. The filename suffix as a last-resort fallback (used pre-build and for - // non-ZISI runtimes). - get isBackground(): boolean { - if (this.buildData?.invocationMode === 'background') { - return true - } - if (this.config.functions?.[this.name]?.background === true) { - return true - } - return this.name.endsWith(BACKGROUND_FUNCTION_SUFFIX) - } - - private buildQueue?: Promise - private buildData?: BuildResult - public buildError: Error | null = null - - // List of the function's source files. This starts out as an empty set - // and will get populated on every build. - private srcFiles = new Set() - - public excludedRoutes: Route[] | undefined - public routes: ExtendedRoute[] | undefined - - constructor({ - blobsContext, - config, - directory, - displayName, - excludedRoutes, - mainFile, - name, - projectRoot, - routes, - runtime, - settings, - timeoutBackground, - timeoutSynchronous, - }: NetlifyFunctionOptions) { - this.blobsContext = blobsContext - this.config = config - this.directory = directory - this.excludedRoutes = excludedRoutes - this.mainFile = mainFile - this.name = name - this.displayName = displayName ?? name - this.projectRoot = projectRoot - this.routes = routes - this.runtime = runtime - this.timeoutBackground = timeoutBackground - this.timeoutSynchronous = timeoutSynchronous - this.settings = settings - - const functionConfig = config.functions?.[name] - this.schedule = functionConfig?.schedule - - this.srcFiles = new Set() - } - - get filename() { - if (!this.buildData?.mainFile) { - return null - } - - return basename(this.buildData.mainFile) - } - - getRecommendedExtension() { - if (this.buildData?.runtimeAPIVersion !== 2) { - return - } - - const extension = this.buildData?.mainFile ? extname(this.buildData.mainFile) : undefined - const moduleFormat = this.buildData?.outputModuleFormat - - if (moduleFormat === 'esm') { - return - } - - if (extension === '.ts') { - return '.mts' - } - - if (extension === '.js') { - return '.mjs' - } - } - - hasValidName() { - // same as https://github.com/netlify/bitballoon/blob/fbd7881e6c8e8c48e7a0145da4ee26090c794108/app/models/deploy.rb#L482 - return /^[A-Za-z0-9_-]+$/.test(this.name) - } - - async isScheduled() { - await this.buildQueue - - return Boolean(this.schedule) - } - - isSupported() { - return !(this.buildData?.runtimeAPIVersion === 2 && semver.lt(nodeVersion, V2_MIN_NODE_VERSION)) - } - - isTypeScript() { - if (this.filename === null) { - return false - } - - return TYPESCRIPT_EXTENSIONS.has(extname(this.filename)) - } - - async getNextRun() { - if (!(await this.isScheduled())) { - return null - } - - return getNextRun(this.schedule!) - } - - // The `build` method transforms source files into invocable functions. Its - // return value is an object with: - // - // - `srcFilesDiff`: Files that were added and removed since the last time - // the function was built. - async build({ buildDirectory, cache }: { buildDirectory: string; cache: MemoizeCache }) { - this.buildQueue = this.runtime - .getBuildFunction({ - config: this.config, - directory: this.directory, - func: this, - projectRoot: this.projectRoot, - targetDirectory: buildDirectory, - }) - .then((buildFunction) => buildFunction({ cache })) - - try { - const buildData = await this.buildQueue - - if (buildData === undefined) { - throw new Error(`Could not build function ${this.name}`) - } - - const { includedFiles = [], routes, schedule, srcFiles } = buildData - const srcFilesSet = new Set(srcFiles) - const srcFilesDiff = this.getSrcFilesDiff(srcFilesSet) - - this.buildData = buildData - this.buildError = null - this.routes = routes - - this.srcFiles = srcFilesSet - this.schedule = schedule || this.schedule - - if (!this.isSupported()) { - throw new Error( - `Function requires Node.js version ${V2_MIN_NODE_VERSION} or above, but ${nodeVersion.slice( - 1, - )} is installed. Refer to https://ntl.fyi/functions-runtime for information on how to update.`, - ) - } - - return { includedFiles, srcFilesDiff } - } catch (error) { - if (error instanceof Error) { - this.buildError = error - } - - return { error } - } - } - - private formatError(rawError: Error | InvocationError, acceptsHTML: boolean): string { - const error = this.normalizeError(rawError) - - if (acceptsHTML) { - return JSON.stringify({ - ...error, - stackTrace: undefined, - trace: error.stackTrace, - }) - } - - return `${error.errorType}: ${error.errorMessage}\n ${error.stackTrace.join('\n')}` - } - - async getBuildData() { - await this.buildQueue - - return this.buildData - } - - // Compares a new set of source files against a previous one, returning an - // object with two Sets, one with added and the other with deleted files. - getSrcFilesDiff(newSrcFiles: Set) { - const added = difference(newSrcFiles, this.srcFiles) - const deleted = difference(this.srcFiles, newSrcFiles) - - return { - added, - deleted, - } - } - - private async handleError(rawError: Error | InvocationError | string, acceptsHTML: boolean): Promise { - const errorString = typeof rawError === 'string' ? rawError : this.formatError(rawError, acceptsHTML) - const status = 500 - - if (acceptsHTML) { - const body = await renderFunctionErrorPage(errorString, 'function') - - return new Response(body, { - headers: { - 'Content-Type': 'text/html', - }, - status, - }) - } - - return new Response(errorString, { status }) - } - - // Invokes the function and returns its response object. - async invoke({ buildCache = {}, buildDirectory, clientContext = {}, request, route }: InvokeFunctionOptions) { - // If a `buildDirectory` has been supplied, it means we need to run a build - // specifically for this invocation. Otherwise, we use the build queue. - if (buildDirectory) { - await this.build({ buildDirectory, cache: buildCache }) - } else { - await this.buildQueue - } - - if (this.buildError) { - throw this.buildError - } - - const timeout = this.isBackground ? this.timeoutBackground : this.timeoutSynchronous - const environment = {} - - if (this.blobsContext) { - const payload = JSON.stringify(getBlobsEventProperty(this.blobsContext)) - - request.headers.set(netlifyHeaders.BlobsInfo, Buffer.from(payload).toString('base64')) - } - - try { - return await this.runtime.invokeFunction({ - context: clientContext, - environment, - func: this, - request, - route, - timeout, - }) - } catch (error) { - const acceptsHTML = request.headers.get('accept')?.includes('text/html') - - return await this.handleError(error as Error | InvocationError | string, Boolean(acceptsHTML)) - } - } - - /** - * Matches all routes agains the incoming request. If a match is found, then the matched route is returned. - * @returns matched route - */ - async matchURLPath(rawPath: string, method: string) { - let path = rawPath !== '/' && rawPath.endsWith('/') ? rawPath.slice(0, -1) : rawPath - path = path.toLowerCase() - const { excludedRoutes = [], routes = [] } = this - - const matchingRoute = routes.find((route: ExtendedRoute) => { - if (route.methods && route.methods.length !== 0 && !route.methods.includes(method)) { - return false - } - - if ('literal' in route && route.literal !== undefined) { - return path === route.literal - } - - if ('expression' in route && route.expression !== undefined) { - const regex = new RegExp(route.expression) - - return regex.test(path) - } - - return false - }) - - if (!matchingRoute) { - return - } - - const isExcluded = excludedRoutes.some((excludedRoute: Route) => { - if ('literal' in excludedRoute && excludedRoute.literal !== undefined) { - return path === excludedRoute.literal - } - - if ('expression' in excludedRoute && excludedRoute.expression !== undefined) { - const regex = new RegExp(excludedRoute.expression) - - return regex.test(path) - } - - return false - }) - - if (isExcluded) { - return - } - - return matchingRoute - } - - private normalizeError(error: Error | InvocationError): InvocationError { - if (error instanceof Error) { - const normalizedError: InvocationError = { - errorMessage: error.message, - errorType: error.name, - stackTrace: error.stack ? error.stack.split('\n') : [], - } - - if ('code' in error && error.code === 'ERR_REQUIRE_ESM') { - return { - ...normalizedError, - errorMessage: - 'a CommonJS file cannot import ES modules. Consider switching your function to ES modules. For more information, refer to https://ntl.fyi/functions-runtime.', - } - } - - return normalizedError - } - - // Formatting stack trace lines in the same way that Node.js formats native errors. - const stackTrace = error.stackTrace.map((line) => ` at ${line}`) - - return { - errorType: error.errorType, - errorMessage: error.errorMessage, - stackTrace, - } - } - - get runtimeAPIVersion() { - return this.buildData?.runtimeAPIVersion ?? 1 - } - - setRoutes(routes: FunctionResult['routes']) { - if (this.buildData) { - this.buildData.routes = routes - } - } - - get url() { - // This line fixes the issue here https://github.com/netlify/cli/issues/4116 - // Not sure why `settings.port` was used here nor does a valid reference exist. - // However, it remains here to serve whatever purpose for which it was added. - const port = this.settings.port || this.settings.functionsPort - const protocol = this.settings.https ? 'https' : 'http' - const url = new URL(`/.netlify/functions/${this.name}`, `${protocol}://localhost:${port}`) - - return url.href - } -} diff --git a/packages/functions/dev/src/main.test.ts b/packages/functions/dev/src/main.test.ts deleted file mode 100644 index bc998e2..0000000 --- a/packages/functions/dev/src/main.test.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { join } from 'node:path' - -import { Reactive, EventInspector, FileWatcher, Fixture } from '@netlify/dev-utils' -import { describe, expect, test } from 'vitest' - -import { FunctionsHandler } from './main.js' -import { FunctionLoadedEvent } from './events.js' - -describe('Functions with the v2 API syntax', () => { - test('Invokes a function and watches for changes', async () => { - const fixture = new Fixture().withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Hello world")`, - ) - - const directory = await fixture.create() - const destPath = join(directory, 'functions-serve') - const events = new EventInspector() - const fileWatcher = new FileWatcher() - const functions = new FunctionsHandler({ - accountId: 'account-123', - config: new Reactive({}), - eventHandler: (event) => { - events.handleEvent(event) - }, - destPath, - fileWatcher, - geolocation: {}, - projectRoot: directory, - settings: {}, - timeouts: {}, - userFunctionsPath: 'netlify/functions', - }) - - const req1 = new Request('https://site.netlify/.netlify/functions/foo') - const match1 = await functions.match(req1, destPath) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify/.netlify/functions/hello') - const match2 = await functions.match(req2, destPath) - const res2 = await match2!.handle(req2) - expect(res2?.status).toBe(200) - expect(await res2?.text()).toBe('Hello world') - - await fixture.writeFile('netlify/functions/hello.mjs', `export default async () => new Response("Goodbye world")`) - await events.waitFor((event) => event.name === 'FunctionLoadedEvent' && !(event as FunctionLoadedEvent).firstLoad) - - const req3 = new Request('https://site.netlify/.netlify/functions/hello') - const match3 = await functions.match(req3, destPath) - const res3 = await match3!.handle(req3) - expect(res3?.status).toBe(200) - expect(await res3?.text()).toBe('Goodbye world') - - await fixture.deleteFile('netlify/functions/hello.mjs') - await events.waitFor((event) => event.name === 'FunctionRemovedEvent') - - const req4 = new Request('https://site.netlify/.netlify/functions/hello') - const match4 = await functions.match(req4, destPath) - expect(match4).toBeUndefined() - - await fixture.destroy() - await fileWatcher.close() - }) - - test('Invokes a function and streams the response', async () => { - const source = ` - export default async () => - new Response( - new ReadableStream({ - start(controller) { - controller.enqueue('first chunk') - setTimeout(() => { - controller.enqueue('second chunk') - controller.close() - }, 200) - }, - }), - { - status: 200, - }, - ) - - export const config = { path: '/streamer' } - ` - const fixture = new Fixture().withFile('netlify/functions/streamer.mjs', source) - - const directory = await fixture.create() - const destPath = join(directory, 'functions-serve') - const functions = new FunctionsHandler({ - accountId: 'account-123', - config: new Reactive({}), - destPath, - geolocation: {}, - projectRoot: directory, - settings: {}, - timeouts: {}, - userFunctionsPath: 'netlify/functions', - }) - - const req = new Request('https://site.netlify/streamer') - const match = await functions.match(req, destPath) - expect(match).not.toBeUndefined() - const res = await match!.handle(req) - expect(res.status).toBe(200) - - const reader = res.body!.getReader() - - const firstChunk = await reader.read() - expect(new TextDecoder().decode(firstChunk.value)).toBe('first chunk') - expect(firstChunk.done).toBeFalsy() - - const secondChunk = await reader.read() - expect(new TextDecoder().decode(secondChunk.value)).toBe('second chunk') - expect(secondChunk.done).toBeFalsy() - - const thirdChunk = await reader.read() - expect(thirdChunk.done).toBeTruthy() - }) - - test('Handles bodyless responses', async () => { - const source = ` - export default async () => - new Response(null, - { - status: 304, - }, - ) - - export const config = { path: '/bodyless-response' } - ` - const fixture = new Fixture().withFile('netlify/functions/bodyless-response.mjs', source) - - const directory = await fixture.create() - const destPath = join(directory, 'functions-serve') - const functions = new FunctionsHandler({ - accountId: 'account-123', - config: new Reactive({}), - destPath, - geolocation: {}, - projectRoot: directory, - settings: {}, - timeouts: {}, - userFunctionsPath: 'netlify/functions', - }) - - const req = new Request('https://site.netlify/bodyless-response') - const match = await functions.match(req, destPath) - expect(match).not.toBeUndefined() - const res = await match!.handle(req) - expect(res.status).toBe(304) - }) - - test('Preserves response headers for v2 functions', async () => { - const source = ` - export default async () => - new Response(JSON.stringify({ ok: true }), { - status: 401, - headers: { - 'content-type': 'application/json', - 'cache-control': 'no-store', - 'www-authenticate': 'Bearer realm="repro"', - 'x-repro-header': 'present', - }, - }) - - export const config = { path: '/headers' } - ` - const fixture = new Fixture().withFile('netlify/functions/headers.mjs', source) - - const directory = await fixture.create() - const destPath = join(directory, 'functions-serve') - const functions = new FunctionsHandler({ - accountId: 'account-123', - config: new Reactive({}), - destPath, - geolocation: {}, - projectRoot: directory, - settings: {}, - timeouts: {}, - userFunctionsPath: 'netlify/functions', - }) - - const req = new Request('https://site.netlify/headers') - const match = await functions.match(req, destPath) - expect(match).not.toBeUndefined() - - const res = await match!.handle(req) - expect(res.status).toBe(401) - expect(res.headers.get('content-type')).toBe('application/json') - expect(res.headers.get('cache-control')).toBe('no-store') - expect(res.headers.get('www-authenticate')).toBe('Bearer realm="repro"') - expect(res.headers.get('x-repro-header')).toBe('present') - expect(await res.text()).toBe(JSON.stringify({ ok: true })) - }) - - test('Preserves headers for streamed v2 responses', async () => { - const source = ` - export default async () => - new Response( - new ReadableStream({ - start(controller) { - controller.enqueue('chunk') - controller.close() - }, - }), - { - status: 200, - headers: { - 'content-type': 'text/event-stream', - 'cache-control': 'no-cache', - 'x-repro-header': 'stream', - }, - }, - ) - - export const config = { path: '/stream-headers' } - ` - const fixture = new Fixture().withFile('netlify/functions/stream-headers.mjs', source) - - const directory = await fixture.create() - const destPath = join(directory, 'functions-serve') - const functions = new FunctionsHandler({ - accountId: 'account-123', - config: new Reactive({}), - destPath, - geolocation: {}, - projectRoot: directory, - settings: {}, - timeouts: {}, - userFunctionsPath: 'netlify/functions', - }) - - const req = new Request('https://site.netlify/stream-headers') - const match = await functions.match(req, destPath) - expect(match).not.toBeUndefined() - - const res = await match!.handle(req) - expect(res.status).toBe(200) - expect(res.headers.get('content-type')).toBe('text/event-stream') - expect(res.headers.get('cache-control')).toBe('no-cache') - expect(res.headers.get('x-repro-header')).toBe('stream') - expect(await res.text()).toBe('chunk') - }) - - test('Returns a `preferStatic` property', async () => { - const fixture = new Fixture().withFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Hello world") - - export const config = { - path: "/hello" - }`, - ) - - const directory = await fixture.create() - const destPath = join(directory, 'functions-serve') - const events = new EventInspector() - const fileWatcher = new FileWatcher() - const functions = new FunctionsHandler({ - accountId: 'account-123', - config: new Reactive({}), - eventHandler: (event) => { - events.handleEvent(event) - }, - destPath, - fileWatcher, - geolocation: {}, - projectRoot: directory, - settings: {}, - timeouts: {}, - userFunctionsPath: 'netlify/functions', - }) - - const req1 = new Request('https://site.netlify/hello') - const match1 = await functions.match(req1, destPath) - expect(match1?.preferStatic).toBe(false) - const res1 = await match1!.handle(req1) - expect(res1?.status).toBe(200) - expect(await res1?.text()).toBe('Hello world') - - await fixture.writeFile( - 'netlify/functions/hello.mjs', - `export default async () => new Response("Goodbye world") - - export const config = { - path: "/hello", - preferStatic: true - }`, - ) - await events.waitFor((event) => event.name === 'FunctionLoadedEvent' && !(event as FunctionLoadedEvent).firstLoad) - - const req2 = new Request('https://site.netlify/hello') - const match2 = await functions.match(req2, destPath) - expect(match2?.preferStatic).toBe(true) - const res2 = await match2!.handle(req2) - expect(res2?.status).toBe(200) - expect(await res2?.text()).toBe('Goodbye world') - - await fixture.destroy() - await fileWatcher.close() - }) -}) diff --git a/packages/functions/dev/src/main.ts b/packages/functions/dev/src/main.ts deleted file mode 100644 index 2e37b4d..0000000 --- a/packages/functions/dev/src/main.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { Buffer } from 'node:buffer' - -import type { Geolocation } from '@netlify/dev-utils' -import type { FunctionBuildCache, NetlifyFunction } from './function.js' -import { FunctionsRegistry, type FunctionRegistryOptions } from './registry.js' -import { headersObjectFromWebHeaders } from './runtimes/nodejs/lambda.js' -import { buildClientContext } from './server/client-context.js' - -const CLOCKWORK_USERAGENT = 'Netlify Clockwork' -const UNLINKED_SITE_MOCK_ID = 'unlinked' - -export interface FunctionMatch { - handle: (req: Request) => Promise - preferStatic: boolean -} - -type FunctionsHandlerOptions = FunctionRegistryOptions & { - accountId?: string - geolocation: Geolocation - siteId?: string - userFunctionsPath?: string -} - -export class FunctionsHandler { - private accountID?: string - private buildCache: FunctionBuildCache - private geolocation: Geolocation - private globalBuildDirectory: string - private registry: FunctionsRegistry - private scan: Promise - private siteID?: string - - constructor({ accountId, geolocation, siteId, userFunctionsPath, ...registryOptions }: FunctionsHandlerOptions) { - const registry = new FunctionsRegistry(registryOptions) - - this.accountID = accountId - this.buildCache = {} - this.geolocation = geolocation - this.globalBuildDirectory = registryOptions.destPath - this.registry = registry - this.scan = registry.scan([userFunctionsPath]) - this.siteID = siteId - } - - private async invoke(request: Request, route: string | undefined, func: NetlifyFunction, buildDirectory?: string) { - // TODO: Revisit this logic that was copied over from the CLI. - let remoteAddress = request.headers.get('x-forwarded-for') || '' - remoteAddress = - remoteAddress - .split(remoteAddress.includes('.') ? ':' : ',') - .pop() - ?.trim() ?? '' - - request.headers.set('x-nf-client-connection-ip', remoteAddress) - - if (this.accountID) { - request.headers.set('x-nf-account-id', this.accountID) - } - - request.headers.set('x-nf-site-id', this.siteID ?? UNLINKED_SITE_MOCK_ID) - request.headers.set('x-nf-geo', Buffer.from(JSON.stringify(this.geolocation)).toString('base64')) - - const { headers: headersObject } = headersObjectFromWebHeaders(request.headers) - const clientContext = buildClientContext(headersObject) || {} - - if (func.isBackground) { - // Background functions do not receive a clientContext - await func.invoke({ - buildCache: this.buildCache, - buildDirectory: buildDirectory ?? this.globalBuildDirectory, - request, - route, - }) - - return new Response(null, { status: 202 }) - } - - if (await func.isScheduled()) { - // In production, scheduled functions always receive POST requests, so we - // have to emulate that here, even if a user has triggered a GET request - // as part of their tests. If we don't do this, we'll hit problems when - // we send the invocation body in a request that can't have a body. - const newRequest = new Request(request, { - ...request, - method: 'POST', - }) - - newRequest.headers.set('user-agent', CLOCKWORK_USERAGENT) - newRequest.headers.set('x-nf-event', 'schedule') - - return await func.invoke({ - buildCache: this.buildCache, - buildDirectory: buildDirectory ?? this.globalBuildDirectory, - clientContext, - request: newRequest, - route, - }) - } - - return await func.invoke({ - buildCache: this.buildCache, - buildDirectory: buildDirectory ?? this.globalBuildDirectory, - clientContext, - request, - route, - }) - } - - async match(request: Request, buildDirectory?: string): Promise { - await this.scan - - const url = new URL(request.url) - const match = await this.registry.getFunctionForURLPath(url.pathname, request.method) - if (!match) { - return - } - - const functionName = match?.func?.name - if (!functionName) { - return - } - - const matchingRoute = match.route?.pattern - - const func = this.registry.get(functionName) - if (func === undefined) { - return { - handle: async () => - new Response('Function not found...', { - status: 404, - }), - preferStatic: false, - } - } - - if (!func.hasValidName()) { - return { - handle: async () => - new Response('Function name should consist only of alphanumeric characters, hyphen & underscores.', { - status: 400, - }), - preferStatic: false, - } - } - - return { - handle: (request: Request) => this.invoke(request, matchingRoute, func, buildDirectory), - preferStatic: match.route?.prefer_static ?? false, - } - } -} diff --git a/packages/functions/dev/src/registry.test.ts b/packages/functions/dev/src/registry.test.ts deleted file mode 100644 index 9ef45d5..0000000 --- a/packages/functions/dev/src/registry.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import { Reactive } from '@netlify/dev-utils' -import { SYNCHRONOUS_FUNCTION_TIMEOUT, BACKGROUND_FUNCTION_TIMEOUT } from '@netlify/functions' -import { FunctionsRegistry } from './registry.js' - -describe('FunctionsRegistry timeout configuration', () => { - test('uses default timeouts when no config or override provided', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({}), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: SYNCHRONOUS_FUNCTION_TIMEOUT, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) - - test('uses functions_timeout from siteInfo for sync functions only', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({ - siteInfo: { - functions_timeout: 60, - }, - }), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: 60, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) - - test('uses functions_config.timeout from siteInfo for sync functions only', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({ - siteInfo: { - functions_config: { - timeout: 45, - }, - }, - }), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: 45, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) - - test('prefers functions_timeout over functions_config.timeout for sync functions', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({ - siteInfo: { - functions_timeout: 60, - functions_config: { - timeout: 45, - }, - }, - }), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: 60, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) - - test('uses override timeouts when provided', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({ - siteInfo: { - functions_timeout: 60, - }, - }), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - timeouts: { - syncFunctions: 120, - backgroundFunctions: 1800, - }, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: 120, - backgroundFunctions: 1800, - }) - }) - - test('allows partial override of timeouts', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({ - siteInfo: { - functions_timeout: 60, - }, - }), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - timeouts: { - syncFunctions: 120, - }, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: 120, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) - - test('falls back to defaults when siteInfo is undefined', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({ - siteInfo: undefined, - }), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: SYNCHRONOUS_FUNCTION_TIMEOUT, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) - - test('falls back to defaults when config is empty object', () => { - const registry = new FunctionsRegistry({ - config: new Reactive({}), - destPath: '/tmp/test', - projectRoot: '/tmp/project', - settings: {}, - }) - - expect(registry.timeouts).toEqual({ - syncFunctions: SYNCHRONOUS_FUNCTION_TIMEOUT, - backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT, - }) - }) -}) diff --git a/packages/functions/dev/src/registry.ts b/packages/functions/dev/src/registry.ts deleted file mode 100644 index 7c14756..0000000 --- a/packages/functions/dev/src/registry.ts +++ /dev/null @@ -1,524 +0,0 @@ -import { stat } from 'node:fs/promises' -import { createRequire } from 'node:module' -import { basename, extname, isAbsolute, join, resolve } from 'node:path' -import { env } from 'node:process' - -import type { EnvironmentContext as BlobsContext } from '@netlify/blobs' -import { DevEventHandler, FileWatcher, type FileWatchSubscriptionHandle, Reactive } from '@netlify/dev-utils' -import { SYNCHRONOUS_FUNCTION_TIMEOUT, BACKGROUND_FUNCTION_TIMEOUT } from '@netlify/functions' -import { ListedFunction, listFunctions, Manifest } from '@netlify/zip-it-and-ship-it' -import extractZip from 'extract-zip' - -import type { - FunctionBuildErrorEvent, - FunctionExtractedEvent, - FunctionLoadedEvent, - FunctionMissingTypesPackageEvent, - FunctionNotInvokableOnPathEvent, - FunctionRegisteredEvent, - FunctionReloadingEvent, - FunctionRemovedEvent, -} from './events.js' - -import { BuildCache } from './builder.js' -import { NetlifyFunction } from './function.js' -import { runtimes } from './runtimes/index.js' - -export const DEFAULT_FUNCTION_URL_EXPRESSION = /^\/.netlify\/(functions|builders)\/([^/]+).*/ -const TYPES_PACKAGE = '@netlify/functions' - -export interface FunctionRegistryOptions { - blobsContext?: BlobsContext - destPath: string - config: Reactive - debug?: boolean - eventHandler?: DevEventHandler - frameworksAPIFunctionsPath?: string - internalFunctionsPath?: string - manifest?: Manifest - projectRoot: string - settings: any - timeouts?: { syncFunctions?: number; backgroundFunctions?: number } - fileWatcher?: FileWatcher -} - -export class FunctionsRegistry { - /** - * Context object for Netlify Blobs - */ - private blobsContext?: BlobsContext - - /** - * The functions held by the registry - */ - private functions = new Map() - - /** - * File watchers for function files. Maps function names to subscription - * handles from the shared `FileWatcher`. - */ - private functionWatchers = new Map() - - /** - * Keeps track of whether we've checked whether `TYPES_PACKAGE` is - * installed. - */ - private hasCheckedTypesPackage = false - - private buildCache: BuildCache - private config: Reactive - private debug: boolean - private destPath: string - private directoryWatchers: Map - private handleEvent: DevEventHandler - private frameworksAPIFunctionsPath?: string - private internalFunctionsPath?: string - private manifest?: Manifest - private projectRoot: string - private timeouts: any - private settings: any - private fileWatcher?: FileWatcher - - constructor({ - blobsContext, - config, - debug = false, - destPath, - eventHandler, - frameworksAPIFunctionsPath, - internalFunctionsPath, - manifest, - projectRoot, - settings, - timeouts, - fileWatcher, - }: FunctionRegistryOptions) { - this.blobsContext = blobsContext - this.config = config - this.debug = debug - this.destPath = destPath - this.frameworksAPIFunctionsPath = frameworksAPIFunctionsPath - this.handleEvent = eventHandler ?? (() => {}) - this.internalFunctionsPath = internalFunctionsPath - this.projectRoot = projectRoot - - // Calculate timeouts from config if not provided as override - const configValue = config.get() - const siteTimeout = configValue?.siteInfo?.functions_timeout ?? configValue?.siteInfo?.functions_config?.timeout - this.timeouts = { - syncFunctions: timeouts?.syncFunctions ?? siteTimeout ?? SYNCHRONOUS_FUNCTION_TIMEOUT, - // NOTE: This isn't documented, but the generically named "functions timeout" config fields only - // apply to synchronous Netlify Functions. - backgroundFunctions: timeouts?.backgroundFunctions ?? BACKGROUND_FUNCTION_TIMEOUT, - } - - this.settings = settings - this.fileWatcher = fileWatcher - - /** - * An object to be shared among all functions in the registry. It can be - * used to cache the results of the build function — e.g. it's used in - * the `memoizedBuild` method in the JavaScript runtime. - */ - this.buildCache = {} - - /** - * File watchers for parent directories where functions live — i.e. the - * ones supplied to `scan()`. This is a Map because in the future we - * might have several function directories. - */ - this.directoryWatchers = new Map() - - /** - * Contents of a `manifest.json` file that can be looked up when dealing - * with built functions. - */ - this.manifest = manifest - } - - async checkTypesPackage() { - if (this.hasCheckedTypesPackage) { - return - } - - this.hasCheckedTypesPackage = true - - const require = createRequire(this.projectRoot) - - try { - require.resolve(TYPES_PACKAGE, { paths: [this.projectRoot] }) - } catch (error) { - if ((error as NodeJS.ErrnoException)?.code === 'MODULE_NOT_FOUND') { - this.handleEvent({ name: 'FunctionMissingTypesPackageEvent' } as FunctionMissingTypesPackageEvent) - } - } - } - - /** - * Builds a function and sets up the appropriate file watchers so that any - * changes will trigger another build. - */ - async buildFunctionAndWatchFiles(func: NetlifyFunction, firstLoad = false) { - if (!firstLoad) { - this.handleEvent({ function: func, name: 'FunctionReloadingEvent' } as FunctionReloadingEvent) - } - - const { - error: buildError, - includedFiles, - srcFilesDiff, - } = await func.build({ buildDirectory: this.destPath, cache: this.buildCache }) - - if (buildError) { - this.handleEvent({ function: func, name: 'FunctionBuildErrorEvent' } as FunctionBuildErrorEvent) - } else { - this.handleEvent({ firstLoad, function: func, name: 'FunctionLoadedEvent' } as FunctionLoadedEvent) - } - - if (func.isTypeScript()) { - this.checkTypesPackage() - } - - // If the build hasn't resulted in any files being added or removed, there - // is nothing else we need to do. - if (!srcFilesDiff) { - return - } - - if (!this.fileWatcher) { - return - } - - const handle = this.functionWatchers.get(func.name) - - // If there is already a watcher for this function, we need to unwatch any - // files that have been removed and watch any files that have been added. - if (handle) { - srcFilesDiff.deleted.forEach((path) => { - handle.unwatch(path) - }) - - srcFilesDiff.added.forEach((path) => { - handle.add(path) - }) - - return - } - - // If there is no watcher for this function but the build produced files, - // we create a new watcher and watch them. - if (srcFilesDiff.added.size !== 0) { - const filesToWatch = [...srcFilesDiff.added, ...includedFiles] - const newHandle = this.fileWatcher.subscribe({ - paths: filesToWatch, - decache: true, - onChange: () => { - this.buildFunctionAndWatchFiles(func, false) - }, - }) - - this.functionWatchers.set(func.name, newHandle) - } - } - - set eventHandler(handler: DevEventHandler) { - this.handleEvent = handler - } - - /** - * Returns a function by name. - */ - get(name: string) { - return this.functions.get(name) - } - - /** - * Looks for the first function that matches a given URL path. If a match is - * found, returns an object with the function and the route. If the URL path - * matches the default functions URL (i.e. can only be for a function) but no - * function with the given name exists, returns an object with the function - * and the route set to `null`. Otherwise, `undefined` is returned, - */ - async getFunctionForURLPath(urlPath: string, method: string) { - // We're constructing a URL object just so that we can extract the path from - // the incoming URL. It doesn't really matter that we don't have the actual - // local URL with the correct port. - const url = new URL(`http://localhost${urlPath}`) - const defaultURLMatch = DEFAULT_FUNCTION_URL_EXPRESSION.exec(url.pathname) - - if (defaultURLMatch) { - const func = this.get(defaultURLMatch[2]) - - if (!func) { - return { func: null, route: null } - } - - const { routes = [] } = func - - if (routes.length !== 0) { - this.handleEvent({ - function: func, - name: 'FunctionNotInvokableOnPathEvent', - urlPath, - } as FunctionNotInvokableOnPathEvent) - - return - } - - return { func, route: null } - } - - for (const func of this.functions.values()) { - const route = await func.matchURLPath(url.pathname, method) - - if (route) { - return { func, route } - } - } - } - - isInternalFunction(func: ListedFunction | NetlifyFunction) { - if (this.internalFunctionsPath && func.mainFile.includes(this.internalFunctionsPath)) { - return true - } - - if (this.frameworksAPIFunctionsPath && func.mainFile.includes(this.frameworksAPIFunctionsPath)) { - return true - } - - return false - } - - /** - * Adds a function to the registry - */ - async registerFunction(name: string, func: NetlifyFunction, isReload = false) { - this.handleEvent({ function: func, name: 'FunctionRegisteredEvent' } as FunctionRegisteredEvent) - - // If the function file is a ZIP, we extract it and rewire its main file to - // the new location. - if (extname(func.mainFile) === '.zip') { - const unzippedDirectory = await this.unzipFunction(func) - - // If there's a manifest file, look up the function in order to extract - // the build data. - const manifestEntry = (this.manifest?.functions || []).find((manifestFunc) => manifestFunc.name === func.name) - - // We found a zipped function that does not have a corresponding entry in - // the manifest. This shouldn't happen, but we ignore the function in - // this case. - if (!manifestEntry) { - return - } - - if (this.debug) { - this.handleEvent({ function: func, name: 'FunctionExtractedEvent' } as FunctionExtractedEvent) - } - - func.setRoutes(manifestEntry?.routes) - - // When we look at an unzipped function, we don't know whether it uses - // the legacy entry file format (i.e. `[function name].mjs`) or the new - // one (i.e. `___netlify-entry-point.mjs`). Let's look for the new one - // and use it if it exists, otherwise use the old one. - try { - const v2EntryPointPath = join(unzippedDirectory, '___netlify-entry-point.mjs') - - await stat(v2EntryPointPath) - - func.mainFile = v2EntryPointPath - } catch { - func.mainFile = join(unzippedDirectory, basename(manifestEntry.mainFile)) - } - } else if (this.fileWatcher) { - this.buildFunctionAndWatchFiles(func, !isReload) - } - - this.functions.set(name, func) - } - - /** - * A proxy to zip-it-and-ship-it's `listFunctions` method. It exists just so - * that we can mock it in tests. - */ - - async listFunctions(...args: Parameters) { - return await listFunctions(...args) - } - - /** - * Takes a list of directories and scans for functions. It keeps tracks of - * any functions in those directories that we've previously seen, and takes - * care of registering and unregistering functions as they come and go. - */ - async scan(relativeDirs: (string | undefined)[]) { - const directories = relativeDirs - .filter((dir): dir is string => Boolean(dir)) - .map((dir) => (isAbsolute(dir) ? dir : join(this.projectRoot, dir))) - - // check after filtering to filter out [undefined] for example - if (directories.length === 0) { - return - } - - const functions = await this.listFunctions(directories, { - featureFlags: { - buildRustSource: env.NETLIFY_EXPERIMENTAL_BUILD_RUST_SOURCE === 'true', - }, - configFileDirectories: [this.internalFunctionsPath].filter(Boolean) as string[], - config: this.config.get().functions, - parseISC: true, - }) - - // user-defined functions take precedence over internal functions, - // so we want to ignore any internal functions where there's a user-defined one with the same name - const ignoredFunctions = new Set( - functions - .filter( - (func) => - this.isInternalFunction(func) && - this.functions.has(func.name) && - !this.isInternalFunction(this.functions.get(func.name)!), - ) - .map((func) => func.name), - ) - - // Before registering any functions, we look for any functions that were on - // the previous list but are missing from the new one. We unregister them. - const deletedFunctions = [...this.functions.values()].filter((oldFunc) => { - const isFound = functions.some( - (newFunc) => - ignoredFunctions.has(newFunc.name) || - (newFunc.name === oldFunc.name && newFunc.mainFile === oldFunc.mainFile), - ) - - return !isFound - }) - - await Promise.all(deletedFunctions.map((func) => this.unregisterFunction(func))) - - const deletedFunctionNames = new Set(deletedFunctions.map((func) => func.name)) - const addedFunctions = await Promise.all( - // zip-it-and-ship-it returns an array sorted based on which extension should have precedence, - // where the last ones precede the previous ones. This is why - // we reverse the array so we get the right functions precedence in the CLI. - functions.reverse().map(async ({ displayName, excludedRoutes, mainFile, name, routes, runtime: runtimeName }) => { - if (ignoredFunctions.has(name)) { - return - } - - const runtime = runtimes[runtimeName] - - // If there is no matching runtime, it means this function is not yet - // supported in Netlify Dev. - // TODO: Add callback for other runtimes. - if (runtime === undefined) { - return - } - - // If this function has already been registered, we skip it. - if (this.functions.has(name)) { - return - } - - const directory = directories.find((directory) => mainFile.startsWith(directory)) - - if (directory === undefined) { - return - } - - const func = new NetlifyFunction({ - blobsContext: this.blobsContext, - config: this.config.get(), - directory, - displayName, - excludedRoutes, - mainFile, - name, - projectRoot: this.projectRoot, - routes, - runtime, - settings: this.settings, - timeoutBackground: this.timeouts.backgroundFunctions, - timeoutSynchronous: this.timeouts.syncFunctions, - }) - - // If a function we're registering was also unregistered in this run, - // then it was a rename. Let's flag it as such so that the messaging - // is adjusted accordingly. - const isReload = deletedFunctionNames.has(name) - - await this.registerFunction(name, func, isReload) - - return func - }), - ) - const addedFunctionNames = new Set(addedFunctions.filter(Boolean).map((func) => func?.name)) - - deletedFunctions.forEach(async (func) => { - // If a function we've unregistered was also registered in this run, then - // it was a rename that we've already logged. Nothing to do in this case. - if (addedFunctionNames.has(func.name)) { - return - } - - this.handleEvent({ function: func, name: 'FunctionRemovedEvent' } as FunctionRemovedEvent) - }) - - if (this.fileWatcher) { - await Promise.all(directories.map((path) => this.setupDirectoryWatcher(path))) - } - } - - /** - * Creates a watcher that looks at files being added or removed from a - * functions directory. It doesn't care about files being changed, because - * those will be handled by each functions' watcher. - */ - async setupDirectoryWatcher(directory: string) { - if (this.directoryWatchers.has(directory)) { - return - } - - const handle = this.fileWatcher!.subscribe({ - paths: directory, - depth: 1, - onAdd: () => { - this.scan([directory]) - }, - onUnlink: () => { - this.scan([directory]) - }, - }) - - this.directoryWatchers.set(directory, handle) - } - - /** - * Removes a function from the registry and closes its file watchers. - */ - async unregisterFunction(func: NetlifyFunction) { - const { name } = func - - this.functions.delete(name) - - const handle = this.functionWatchers.get(name) - - if (handle) { - handle.unsubscribe() - } - - this.functionWatchers.delete(name) - } - - /** - * Takes a zipped function and extracts its contents to an internal directory. - */ - async unzipFunction(func: NetlifyFunction) { - const targetDirectory = resolve(this.projectRoot, this.destPath, '.unzipped', func.name) - - await extractZip(func.mainFile, { dir: targetDirectory }) - - return targetDirectory - } -} diff --git a/packages/functions/dev/src/runtimes/index.ts b/packages/functions/dev/src/runtimes/index.ts deleted file mode 100644 index a986f9b..0000000 --- a/packages/functions/dev/src/runtimes/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { HandlerResponse } from '@netlify/functions' -import { FunctionBuilder } from '../builder.js' -import { NetlifyFunction } from '../function.js' -import { nodeJSRuntime } from './nodejs/index.js' - -export interface GetBuildFunctionOptions { - config: any - directory: string - func: NetlifyFunction - projectRoot: string - targetDirectory: string -} - -export interface InvokeFunctionOptions { - context: any - environment: any - func: NetlifyFunction - request: Request - route?: string - timeout: number -} - -export interface Runtime { - getBuildFunction: (options: GetBuildFunctionOptions) => Promise - invokeFunction: (options: InvokeFunctionOptions) => Promise -} - -export const runtimes: Record = { - js: nodeJSRuntime, -} diff --git a/packages/functions/dev/src/runtimes/nodejs/builder.ts b/packages/functions/dev/src/runtimes/nodejs/builder.ts deleted file mode 100644 index 836fe61..0000000 --- a/packages/functions/dev/src/runtimes/nodejs/builder.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { writeFile } from 'node:fs/promises' -import { createRequire } from 'node:module' -import path from 'node:path' - -import { memoize } from '@netlify/dev-utils' -import { zipFunction, listFunction, ArchiveFormat, Config as FunctionsConfig } from '@netlify/zip-it-and-ship-it' -import { FeatureFlags } from '@netlify/zip-it-and-ship-it/dist/feature_flags.js' -import decache from 'decache' -import { readPackageUp } from 'read-package-up' -import sourceMapSupport from 'source-map-support' - -import { normalizeFunctionsConfig, TOMLFunctionConfig } from './config.js' -import { NetlifyFunction } from '../../function.js' - -import { BuildCache, BuildResult, FunctionBuilder } from '../../builder.js' - -const require = createRequire(import.meta.url) - -const addFunctionsConfigDefaults = (config: FunctionsConfig): FunctionsConfig => ({ - ...config, - '*': { - nodeSourcemap: true, - ...config['*'], - }, -}) - -interface BuildFunctionOptions { - cache: BuildCache - config: FunctionsConfig - directory: string - featureFlags: Record - func: NetlifyFunction - hasTypeModule: boolean - projectRoot: string - targetDirectory: string -} - -const buildFunction = async ({ - cache, - config, - directory, - featureFlags, - func, - hasTypeModule, - projectRoot, - targetDirectory, -}: BuildFunctionOptions) => { - const zipOptions = { - archiveFormat: 'none' as ArchiveFormat, - basePath: projectRoot, - config, - featureFlags: { ...featureFlags, zisi_functions_api_v2: true } as FeatureFlags, - } - const functionDirectory = path.dirname(func.mainFile) - - // If we have a function at `functions/my-func/index.js` and we pass - // that path to `zipFunction`, it will lack the context of the whole - // functions directory and will infer the name of the function to be - // `index`, not `my-func`. Instead, we need to pass the directory of - // the function. The exception is when the function is a file at the - // root of the functions directory (e.g. `functions/my-func.js`). In - // this case, we use `mainFile` as the function path of `zipFunction`. - const entryPath = functionDirectory === directory ? func.mainFile : functionDirectory - const buildResult = await memoize({ - cache, - cacheKey: `zisi-${entryPath}`, - command: () => zipFunction(entryPath, targetDirectory, zipOptions), - }) - - if (!buildResult) { - return - } - - const { - entryFilename, - excludedRoutes, - includedFiles, - inputs, - invocationMode, - mainFile, - outputModuleFormat, - path: functionPath, - routes, - runtimeAPIVersion, - schedule, - } = buildResult - const srcFiles = (inputs ?? []).filter((inputPath) => !inputPath.includes(`${path.sep}node_modules${path.sep}`)) - const buildPath = path.join(functionPath, entryFilename) - - // some projects include a package.json with "type=module", forcing Node to interpret every descending file - // as ESM. ZISI outputs CJS, so we emit an overriding directive into the output directory. - if (hasTypeModule) { - await writeFile( - path.join(functionPath, `package.json`), - JSON.stringify({ - type: 'commonjs', - }), - ) - } - - clearFunctionsCache(targetDirectory) - - return { - buildPath, - excludedRoutes, - includedFiles, - invocationMode, - outputModuleFormat, - mainFile, - routes, - runtimeAPIVersion, - srcFiles, - schedule, - targetDirectory, - } -} - -interface ParseFunctionForMetadataOptions { - config: any - mainFile: string - projectRoot: string -} - -export const parseFunctionForMetadata = async ({ config, mainFile, projectRoot }: ParseFunctionForMetadataOptions) => - await listFunction(mainFile, { - config: netlifyConfigToZisiConfig(config.functions, projectRoot), - featureFlags: { zisi_functions_api_v2: true } as FeatureFlags, - parseISC: true, - }) - -// Clears the cache for any files inside the directory from which functions are -// served. -const clearFunctionsCache = (functionsPath: string) => { - Object.keys(require.cache) - .filter((key) => key.startsWith(functionsPath)) - .forEach(decache) -} - -const netlifyConfigToZisiConfig = (functionsConfig: Record, projectRoot: string) => - addFunctionsConfigDefaults(normalizeFunctionsConfig({ functionsConfig, projectRoot })) - -interface HandlerOptions { - config: any - directory: string - func: NetlifyFunction - metadata: any - projectRoot: string - targetDirectory: string -} - -export const getNoopBuilder = async ({ directory, func, metadata }: HandlerOptions): Promise => { - const functionDirectory = path.dirname(func.mainFile) - const srcFiles = functionDirectory === directory ? [func.mainFile] : [functionDirectory] - const build = async () => - ({ - buildPath: '', - excludedRoutes: [], - includedFiles: [], - mainFile: func.mainFile, - outputModuleFormat: 'cjs', - routes: [], - runtimeAPIVersion: func.runtimeAPIVersion, - schedule: metadata.schedule, - srcFiles, - }) as BuildResult - - return { - build, - builderName: '', - } -} - -export const getZISIBuilder = async ({ - config, - directory, - func, - metadata, - projectRoot, - targetDirectory, -}: HandlerOptions): Promise => { - const functionsConfig = netlifyConfigToZisiConfig(config.functions, projectRoot) - const packageJson = await readPackageUp({ cwd: path.dirname(func.mainFile) }) - const hasTypeModule = Boolean(packageJson && packageJson.packageJson.type === 'module') - const featureFlags: FeatureFlags = {} - - if (metadata.runtimeAPIVersion === 2) { - featureFlags.zisi_pure_esm = true - featureFlags.zisi_pure_esm_mjs = true - } else { - // We must use esbuild for certain file extensions. - const mustTranspile = ['.mjs', '.ts', '.mts', '.cts'].includes(path.extname(func.mainFile)) - const mustUseEsbuild = hasTypeModule || mustTranspile - - if (mustUseEsbuild && !functionsConfig['*'].nodeBundler) { - functionsConfig['*'].nodeBundler = 'esbuild' - } - - // TODO: Resolve functions config globs so that we can check for the bundler - // on a per-function basis. - const { nodeBundler } = functionsConfig['*'] - const isUsingEsbuild = nodeBundler === 'esbuild_zisi' || nodeBundler === 'esbuild' - - if (!isUsingEsbuild) { - return null - } - } - - // Enable source map support. - sourceMapSupport.install() - - return { - build: ({ cache = {} }: { cache?: BuildCache }) => - buildFunction({ - cache, - config: functionsConfig, - directory, - func, - projectRoot, - targetDirectory, - hasTypeModule, - featureFlags, - }), - builderName: 'zip-it-and-ship-it', - } -} diff --git a/packages/functions/dev/src/runtimes/nodejs/config.ts b/packages/functions/dev/src/runtimes/nodejs/config.ts deleted file mode 100644 index 6818e10..0000000 --- a/packages/functions/dev/src/runtimes/nodejs/config.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { Config as FunctionsConfig, NodeBundlerName } from '@netlify/zip-it-and-ship-it' - -// TODO: Import from `@netlify/config`. -export interface TOMLFunctionConfig { - external_node_modules: string[] - ignored_node_modules: string[] - included_files: string[] - node_bundler: string - schedule: string -} - -interface NormalizeFunctionsConfigOptions { - functionsConfig: Record - projectRoot: string - siteEnv?: Record -} - -// The function configuration keys returned by @netlify/config are not an exact -// match to the properties that @netlify/zip-it-and-ship-it expects. We do that -// translation here. -export const normalizeFunctionsConfig = ({ - functionsConfig = {}, - projectRoot, - siteEnv = {}, -}: NormalizeFunctionsConfigOptions) => - Object.entries(functionsConfig).reduce( - (result, [pattern, config]) => ({ - ...result, - [pattern]: { - externalNodeModules: config.external_node_modules, - includedFiles: config.included_files, - includedFilesBasePath: projectRoot, - ignoredNodeModules: config.ignored_node_modules, - nodeBundler: (config.node_bundler === 'esbuild' ? 'esbuild_zisi' : config.node_bundler) as NodeBundlerName, - nodeVersion: siteEnv.AWS_LAMBDA_JS_RUNTIME, - processDynamicNodeImports: true, - schedule: config.schedule, - zipGo: true, - }, - }), - {} as FunctionsConfig, - ) diff --git a/packages/functions/dev/src/runtimes/nodejs/index.ts b/packages/functions/dev/src/runtimes/nodejs/index.ts deleted file mode 100644 index 6f8cb97..0000000 --- a/packages/functions/dev/src/runtimes/nodejs/index.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { createConnection } from 'node:net' -import { pathToFileURL } from 'node:url' -import { Worker } from 'node:worker_threads' - -import lambdaLocal from 'lambda-local' - -import type { NetlifyFunction } from '../../function.js' -import type { Runtime } from '../index.js' - -import { getNoopBuilder, getZISIBuilder, parseFunctionForMetadata } from './builder.js' - -// TODO: Find better place for this. -const BLOBS_CONTEXT_VARIABLE = 'NETLIFY_BLOBS_CONTEXT' - -lambdaLocal.getLogger().level = 'alert' - -import { HandlerEvent, HandlerResponse } from '@netlify/functions' -import { lambdaEventFromWebRequest, webResponseFromLambdaResponse } from './lambda.js' - -export const nodeJSRuntime: Runtime = { - getBuildFunction: async ({ config, directory, func, projectRoot, targetDirectory }) => { - const metadata = await parseFunctionForMetadata({ mainFile: func.mainFile, config, projectRoot }) - const zisiBuilder = await getZISIBuilder({ config, directory, func, metadata, projectRoot, targetDirectory }) - - if (zisiBuilder) { - return zisiBuilder.build - } - - const noopBuilder = await getNoopBuilder({ config, directory, func, metadata, projectRoot, targetDirectory }) - - return noopBuilder.build - }, - - invokeFunction: async ({ context, environment, func, request, route, timeout }) => { - const event = await lambdaEventFromWebRequest(request, route) - const buildData = await func.getBuildData() - - if (buildData?.runtimeAPIVersion !== 2) { - const lambdaResponse = await invokeFunctionDirectly({ context, event, func, timeout }) - - return webResponseFromLambdaResponse(lambdaResponse) - } - - const workerData = { - clientContext: JSON.stringify(context), - environment, - event, - // If a function builder has defined a `buildPath` property, we use it. - // Otherwise, we'll invoke the function's main file. - // Because we use import() we have to use file:// URLs for Windows. - entryFilePath: pathToFileURL(buildData?.buildPath ?? func.mainFile).href, - timeoutMs: timeout * 1_000, - } - - const worker = new Worker(workerURL, { workerData }) - const lambdaResponse = await new Promise((resolve, reject) => { - worker.on('message', (result) => { - if (result?.streamPort) { - const client = createConnection( - { - port: result.streamPort, - host: 'localhost', - }, - () => { - result.body = client - resolve(result) - }, - ) - client.on('error', reject) - } else { - resolve(result) - } - }) - - worker.on('error', reject) - }) - - return webResponseFromLambdaResponse(lambdaResponse) - }, -} - -const workerURL = new URL('worker.js', import.meta.url) - -export const invokeFunctionDirectly = async ({ - context, - event, - func, - timeout, -}: { - context: any - event: HandlerEvent - func: NetlifyFunction - timeout: number -}) => { - // If a function builder has defined a `buildPath` property, we use it. - // Otherwise, we'll invoke the function's main file. - const buildData = await func.getBuildData() - const lambdaPath = buildData?.buildPath ?? func.mainFile - const result = (await lambdaLocal.execute({ - clientContext: JSON.stringify(context), - environment: { - // We've set the Blobs context on the parent process, which means it will - // be available to the Lambda. This would be inconsistent with production - // where only V2 functions get the context injected. To fix it, unset the - // context variable before invoking the function. - // This has the side-effect of also removing the variable from `process.env`. - [BLOBS_CONTEXT_VARIABLE]: undefined, - }, - event, - lambdaPath, - timeoutMs: timeout * 1_000, - verboseLevel: 3, - esm: lambdaPath.endsWith('.mjs'), - })) as HandlerResponse - - return result -} diff --git a/packages/functions/dev/src/runtimes/nodejs/lambda.ts b/packages/functions/dev/src/runtimes/nodejs/lambda.ts deleted file mode 100644 index abeed99..0000000 --- a/packages/functions/dev/src/runtimes/nodejs/lambda.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { shouldBase64Encode } from '@netlify/dev-utils' -import { HandlerEvent, HandlerResponse } from '@netlify/functions' - -export const headersObjectFromWebHeaders = (webHeaders: Headers) => { - const headers: Record = {} - const multiValueHeaders: Record = {} - - webHeaders.forEach((value, key) => { - headers[key] = value - multiValueHeaders[key] = value.split(',').map((value) => value.trim()) - }) - - return { - headers, - multiValueHeaders, - } -} - -export const webHeadersFromLambdaResponse = (lambdaResponse: HandlerResponse) => { - const headers = new Headers() - - Object.entries(lambdaResponse.headers ?? {}).forEach(([name, value]) => { - if (value !== undefined) { - headers.set(name.toLowerCase(), value.toString()) - } - }) - - Object.entries(lambdaResponse.multiValueHeaders ?? {}).forEach(([name, values]) => { - for (const value of values) { - headers.append(name.toLowerCase(), value.toString()) - } - }) - - return headers -} - -export const lambdaEventFromWebRequest = async (request: Request, route?: string): Promise => { - const url = new URL(request.url) - const queryStringParameters: Record = {} - const multiValueQueryStringParameters: Record = {} - - url.searchParams.forEach((value, key) => { - queryStringParameters[key] = queryStringParameters[key] ? `${queryStringParameters[key]},${value}` : value - multiValueQueryStringParameters[key] = [...(multiValueQueryStringParameters[key] ?? []), value] - }) - - const { headers, multiValueHeaders } = headersObjectFromWebHeaders(request.headers) - const body = (await request.text()) || null - - return { - rawUrl: url.toString(), - rawQuery: url.search, - path: url.pathname, - httpMethod: request.method, - headers, - multiValueHeaders, - queryStringParameters, - multiValueQueryStringParameters, - body, - isBase64Encoded: shouldBase64Encode(request.headers.get('content-type') ?? ''), - route, - } -} - -export const webResponseFromLambdaResponse = async (lambdaResponse: HandlerResponse): Promise => { - return new Response(lambdaResponse.body, { - headers: webHeadersFromLambdaResponse(lambdaResponse), - status: lambdaResponse.statusCode, - }) -} diff --git a/packages/functions/dev/src/runtimes/nodejs/worker.js b/packages/functions/dev/src/runtimes/nodejs/worker.js deleted file mode 100644 index b8e0b0f..0000000 --- a/packages/functions/dev/src/runtimes/nodejs/worker.js +++ /dev/null @@ -1,106 +0,0 @@ -// @ts-check -// This is a JavaScript file because we need to locate it at runtime using the -// `Worker` API and using a `.ts` complicates things. To make it type-safe, -// we use JSDoc annotations. -import { createServer } from 'node:net' -import process from 'node:process' -import { isMainThread, workerData, parentPort } from 'node:worker_threads' - -import { isStream } from 'is-stream' -import lambdaLocal from 'lambda-local' -import sourceMapSupport from 'source-map-support' - -// https://github.com/nodejs/undici/blob/a36e299d544863c5ade17d4090181be894366024/lib/web/fetch/constants.js#L6 -const nullBodyStatus = new Set([101, 204, 205, 304]) - -/** - * @typedef HandlerResponse - * @type {import('../../../src/function/handler_response.js').HandlerResponse} - */ - -/** - * @typedef WorkerResult - * @type {HandlerResponse & { streamPort?: number }} - */ - -if (isMainThread) { - throw new Error(`Do not import "${import.meta.url}" in the main thread.`) -} - -sourceMapSupport.install() - -lambdaLocal.getLogger().level = 'alert' - -const { clientContext, entryFilePath, environment = {}, event, timeoutMs } = workerData - -// Injecting into the environment any properties passed in by the parent. -for (const key in environment) { - process.env[key] = environment[key] -} -const lambdaFunc = await import(entryFilePath) -const invocationResult = /** @type {HandlerResponse} */ ( - await lambdaLocal.execute({ - clientContext, - event, - lambdaFunc, - region: 'dev', - timeoutMs, - verboseLevel: 3, - }) -) - -/** - * When the result body is a stream and result status code allow to have a body, - * open up a http server that proxies back to the main thread and resolve with server port. - * Otherwise, resolve with undefined. - * - * @param {HandlerResponse} invocationResult - * @returns {Promise} - */ -async function getStreamPortForStreamingResponse(invocationResult) { - // if we don't have result or result's body is not a stream, we do not need a stream port - if (!invocationResult || !isStream(invocationResult.body)) { - return undefined - } - - const { body } = invocationResult - - delete invocationResult.body - - // For streaming responses, lambda-local always returns a result with body stream. - // We need to discard it if result's status code does not allow response to have a body. - const shouldNotHaveABody = nullBodyStatus.has(invocationResult.statusCode) - if (shouldNotHaveABody) { - return undefined - } - - // create a server that will proxy the body stream back to the main thread - return await new Promise((resolve, reject) => { - const server = createServer((socket) => { - body.pipe(socket).on('end', () => server.close()) - }) - server.on('error', (error) => { - reject(error) - }) - server.listen({ port: 0, host: 'localhost' }, () => { - const address = server.address() - - /** @type {number | undefined} */ - let streamPort - if (address && typeof address !== 'string') { - streamPort = address.port - } - - resolve(streamPort) - }) - }) -} - -const streamPort = await getStreamPortForStreamingResponse(invocationResult) - -if (parentPort) { - /** @type {WorkerResult} */ - const message = { ...invocationResult, streamPort } - - parentPort.postMessage(message) -} diff --git a/packages/functions/dev/src/server/client-context.ts b/packages/functions/dev/src/server/client-context.ts deleted file mode 100644 index f081491..0000000 --- a/packages/functions/dev/src/server/client-context.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { jwtDecode } from 'jwt-decode' - -/** - * Inject a client context based on auth header. - * Ported over from netlify-lambda (https://github.com/netlify/netlify-lambda/pull/57). - */ -export const buildClientContext = (headers: Record) => { - if (!headers.authorization) return - - const parts = headers.authorization.split(' ') - if (parts.length !== 2 || parts[0] !== 'Bearer') return - - const identity = { - url: 'https://netlify-dev-locally-emulated-identity.netlify.app/.netlify/identity', - - // { - // "source": "netlify dev", - // "testData": "NETLIFY_DEV_LOCALLY_EMULATED_IDENTITY" - // } - token: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb3VyY2UiOiJuZXRsaWZ5IGRldiIsInRlc3REYXRhIjoiTkVUTElGWV9ERVZfTE9DQUxMWV9FTVVMQVRFRF9JREVOVElUWSJ9.2eSDqUOZAOBsx39FHFePjYj12k0LrxldvGnlvDu3GMI', - } - - try { - // This data is available on both the context root and under custom.netlify for retro-compatibility. - // In the future it will only be available in custom.netlify. - const user = jwtDecode(parts[1]) - - const netlifyContext = JSON.stringify({ - identity, - user, - }) - - return { - identity, - user, - custom: { - netlify: Buffer.from(netlifyContext).toString('base64'), - }, - } - } catch { - // Ignore errors - bearer token is not a JWT, probably not intended for us - } -} diff --git a/packages/functions/dev/tsconfig.json b/packages/functions/dev/tsconfig.json deleted file mode 100644 index c8b61a2..0000000 --- a/packages/functions/dev/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "node", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/functions/dev/tsup.config.ts b/packages/functions/dev/tsup.config.ts deleted file mode 100644 index a5355fb..0000000 --- a/packages/functions/dev/tsup.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - outDir: 'dist', - entry: ['src/main.ts'], - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - publicDir: 'src/runtimes/nodejs', -}) diff --git a/packages/functions/dev/vitest.config.ts b/packages/functions/dev/vitest.config.ts deleted file mode 100644 index 9082123..0000000 --- a/packages/functions/dev/vitest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - resolve: { - alias: { - // This fixes a really strange issue where vitest treats the `stream` - // specifier as a relative import and fails. It's possible that new - // versions of vitest will fix the problem, so you can try to remove - // this and check if the tests still pass. - stream: 'node:stream', - }, - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - typecheck: { - enabled: true, - }, - }, -}) diff --git a/packages/functions/prod/CHANGELOG.md b/packages/functions/prod/CHANGELOG.md deleted file mode 100644 index 9a7486a..0000000 --- a/packages/functions/prod/CHANGELOG.md +++ /dev/null @@ -1,902 +0,0 @@ -# Changelog - -## [5.3.0](https://github.com/netlify/primitives/compare/functions-v5.2.2...functions-v5.3.0) (2026-05-29) - - -### Features - -* add function config properties ([#696](https://github.com/netlify/primitives/issues/696)) ([e43cd8f](https://github.com/netlify/primitives/commit/e43cd8f132ec7d5c4517c29cb7c6dbe9dbd5b6b7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.7.0 to 2.8.0 - -## [5.2.2](https://github.com/netlify/primitives/compare/functions-v5.2.1...functions-v5.2.2) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.6.0 to 2.7.0 - -## [5.2.1](https://github.com/netlify/primitives/compare/functions-v5.2.0...functions-v5.2.1) (2026-05-12) - - -### Bug Fixes - -* update readme badges to point to current repo ([#594](https://github.com/netlify/primitives/issues/594)) ([0e05d46](https://github.com/netlify/primitives/commit/0e05d46b645b66d20d01e824fe5b82a121b491a2)) - -## [5.2.0](https://github.com/netlify/primitives/compare/functions-v5.1.5...functions-v5.2.0) (2026-04-07) - - -### Features - -* export event handler types ([#638](https://github.com/netlify/primitives/issues/638)) ([f651309](https://github.com/netlify/primitives/commit/f6513092153a50f55b71d073c2a32b9e5eb704cb)) - -## [5.1.5](https://github.com/netlify/primitives/compare/functions-v5.1.4...functions-v5.1.5) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.5.0 to 2.6.0 - -## [5.1.4](https://github.com/netlify/primitives/compare/functions-v5.1.3...functions-v5.1.4) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.4.0 to 2.5.0 - -## [5.1.3](https://github.com/netlify/primitives/compare/functions-v5.1.2...functions-v5.1.3) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.3.0 to 2.4.0 - -## [5.1.2](https://github.com/netlify/primitives/compare/functions-v5.1.1...functions-v5.1.2) (2025-12-21) - - -### Bug Fixes - -* avoid emitting global awslambda namespace ([#569](https://github.com/netlify/primitives/issues/569)) ([a90dc42](https://github.com/netlify/primitives/commit/a90dc428e4c2236f78170ac3bbca457784c48607)) - -## [5.1.1](https://github.com/netlify/primitives/compare/functions-v5.1.0...functions-v5.1.1) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.2.0 to 2.3.0 - -## [5.1.0](https://github.com/netlify/primitives/compare/functions-v5.0.1...functions-v5.1.0) (2025-11-05) - - -### Features - -* implement functions timeout defaults and overrides in dev ([#346](https://github.com/netlify/primitives/issues/346)) ([c17753e](https://github.com/netlify/primitives/commit/c17753ec35bdef076db563fa37c1a4222bd5c149)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/types bumped from 2.1.0 to 2.2.0 - -## [5.0.1](https://github.com/netlify/primitives/compare/functions-v5.0.0...functions-v5.0.1) (2025-10-22) - - -### Bug Fixes - -* **types:** allow `global.Netlify` declaration merging ([#494](https://github.com/netlify/primitives/issues/494)) ([bd39b15](https://github.com/netlify/primitives/commit/bd39b15ee03ba88362ccd3a83f61530c03b2ceaa)) - -## [5.0.0](https://github.com/netlify/primitives/compare/functions-v4.3.0...functions-v5.0.0) (2025-10-14) - - -### ⚠ BREAKING CHANGES - -* The `/dev` export, introduced in version 3.1.0, has been removed. - -### Features - -* extract dev logic into new `@netlify/functions-dev` package ([#475](https://github.com/netlify/primitives/issues/475)) ([0730f5f](https://github.com/netlify/primitives/commit/0730f5f40ace6cd37ffc1f54a7ebb4f405bbca65)) - -## [4.3.0](https://github.com/netlify/primitives/compare/functions-v4.2.7...functions-v4.3.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.11 to 10.1.0 - * @netlify/dev-utils bumped from 4.2.0 to 4.3.0 - * @netlify/types bumped from 2.0.3 to 2.1.0 - -## [4.2.7](https://github.com/netlify/primitives/compare/functions-v4.2.6...functions-v4.2.7) (2025-10-01) - - -### Bug Fixes - -* add extra types for ratelimiting ([#464](https://github.com/netlify/primitives/issues/464)) ([6d9fe05](https://github.com/netlify/primitives/commit/6d9fe053bf3f99f33fd9a44f3a2457e8da9fbc4e)) - -## [4.2.6](https://github.com/netlify/primitives/compare/functions-v4.2.5...functions-v4.2.6) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.10 to 10.0.11 - * @netlify/dev-utils bumped from 4.1.3 to 4.2.0 - -## [4.2.5](https://github.com/netlify/primitives/compare/functions-v4.2.4...functions-v4.2.5) (2025-08-28) - - -### Bug Fixes - -* restore missing `Netlify` global type in `@netlify/functions` ([#434](https://github.com/netlify/primitives/issues/434)) ([2e028b9](https://github.com/netlify/primitives/commit/2e028b9cbdc88a61da1641ec9bf30704e2b36220)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.9 to 10.0.10 - * @netlify/dev-utils bumped from 4.1.2 to 4.1.3 - * @netlify/types bumped from 2.0.2 to 2.0.3 - -## [4.2.4](https://github.com/netlify/primitives/compare/functions-v4.2.3...functions-v4.2.4) (2025-08-26) - - -### Bug Fixes - -* **deps:** update dependency @netlify/zip-it-and-ship-it to ^14.1.3 ([#418](https://github.com/netlify/primitives/issues/418)) ([c08dfc9](https://github.com/netlify/primitives/commit/c08dfc9bed1ea71b9654049a48cfe703b90c59c0)) - -## [4.2.3](https://github.com/netlify/primitives/compare/functions-v4.2.2...functions-v4.2.3) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.8 to 10.0.9 - * @netlify/dev-utils bumped from 4.1.1 to 4.1.2 - -## [4.2.2](https://github.com/netlify/primitives/compare/functions-v4.2.1...functions-v4.2.2) (2025-08-14) - - -### Bug Fixes - -* **deps:** update netlify packages ([#411](https://github.com/netlify/primitives/issues/411)) ([bad2dce](https://github.com/netlify/primitives/commit/bad2dceae8b5e5f56d947ce2332372d148819ccc)) - -## [4.2.1](https://github.com/netlify/primitives/compare/functions-v4.2.0...functions-v4.2.1) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.7 to 10.0.8 - * @netlify/dev-utils bumped from 4.1.0 to 4.1.1 - -## [4.2.0](https://github.com/netlify/primitives/compare/functions-v4.1.15...functions-v4.2.0) (2025-07-28) - - -### Features - -* add `generator` field to `Config` type ([#397](https://github.com/netlify/primitives/issues/397)) ([ee49e8a](https://github.com/netlify/primitives/commit/ee49e8a64b360a0b54711e0f1de7bf512d366eb9)) - -## [4.1.15](https://github.com/netlify/primitives/compare/functions-v4.1.14...functions-v4.1.15) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.6 to 10.0.7 - * @netlify/dev-utils bumped from 4.0.0 to 4.1.0 - -## [4.1.14](https://github.com/netlify/primitives/compare/functions-v4.1.13...functions-v4.1.14) (2025-07-22) - - -### Bug Fixes - -* export `Context` type from `@netlify/types` ([#374](https://github.com/netlify/primitives/issues/374)) ([77e828c](https://github.com/netlify/primitives/commit/77e828c597c411a0490fa68333d9846e24e3fcd8)) -* handle 304 responses from functions ([#373](https://github.com/netlify/primitives/issues/373)) ([1094683](https://github.com/netlify/primitives/commit/1094683542fd38bd501b8452a24912e5ee2896ef)) - -## [4.1.13](https://github.com/netlify/primitives/compare/functions-v4.1.12...functions-v4.1.13) (2025-07-21) - - -### Bug Fixes - -* **deps:** update dependency @netlify/zip-it-and-ship-it to v14 ([#334](https://github.com/netlify/primitives/issues/334)) ([fe935fe](https://github.com/netlify/primitives/commit/fe935fe999b18440b3c051b68b3cf4867979d2c0)) - -## [4.1.12](https://github.com/netlify/primitives/compare/functions-v4.1.11...functions-v4.1.12) (2025-07-17) - - -### Bug Fixes - -* **deps:** update netlify packages ([#333](https://github.com/netlify/primitives/issues/333)) ([0fa1f1e](https://github.com/netlify/primitives/commit/0fa1f1e8d717cbc5c797c19b64b4fa4ffbdaf992)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.5 to 10.0.6 - * @netlify/dev-utils bumped from 3.3.0 to 4.0.0 - -## [4.1.11](https://github.com/netlify/primitives/compare/functions-v4.1.10...functions-v4.1.11) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.4 to 10.0.5 - * @netlify/dev-utils bumped from 3.2.2 to 3.3.0 - -## [4.1.10](https://github.com/netlify/primitives/compare/functions-v4.1.9...functions-v4.1.10) (2025-07-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.3 to 10.0.4 - -## [4.1.9](https://github.com/netlify/primitives/compare/functions-v4.1.8...functions-v4.1.9) (2025-07-04) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v2.1.3 ([#328](https://github.com/netlify/primitives/issues/328)) ([3a82e4f](https://github.com/netlify/primitives/commit/3a82e4fc5dd9070871cc9cc8a4368af6585d9035)) -* **deps:** update dependency @netlify/zip-it-and-ship-it to ^12.2.0 ([#322](https://github.com/netlify/primitives/issues/322)) ([fb6721f](https://github.com/netlify/primitives/commit/fb6721fe63d92cf7538d40902821705841c1f0ce)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.2 to 10.0.3 - * @netlify/dev-utils bumped from 3.2.1 to 3.2.2 - -## [4.1.8](https://github.com/netlify/primitives/compare/functions-v4.1.7...functions-v4.1.8) (2025-06-26) - - -### Bug Fixes - -* **deps:** update netlify packages ([#318](https://github.com/netlify/primitives/issues/318)) ([6710630](https://github.com/netlify/primitives/commit/671063084526b210711971fbae53135e2aeb6e0a)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.1 to 10.0.2 - -## [4.1.7](https://github.com/netlify/primitives/compare/functions-v4.1.6...functions-v4.1.7) (2025-06-25) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v2.1.2 ([#307](https://github.com/netlify/primitives/issues/307)) ([7327ebe](https://github.com/netlify/primitives/commit/7327ebe88160b572e8c5086f223caf491886ac2f)) - -## [4.1.6](https://github.com/netlify/primitives/compare/functions-v4.1.5...functions-v4.1.6) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 10.0.0 to 10.0.1 - * @netlify/dev-utils bumped from 3.2.0 to 3.2.1 - -## [4.1.5](https://github.com/netlify/primitives/compare/functions-v4.1.4...functions-v4.1.5) (2025-06-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.6 to 10.0.0 - -## [4.1.4](https://github.com/netlify/primitives/compare/functions-v4.1.3...functions-v4.1.4) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.5 to 9.1.6 - * @netlify/dev-utils bumped from 3.1.1 to 3.2.0 - -## [4.1.3](https://github.com/netlify/primitives/compare/functions-v4.1.2...functions-v4.1.3) (2025-06-06) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v2.1.1 ([#284](https://github.com/netlify/primitives/issues/284)) ([21555ae](https://github.com/netlify/primitives/commit/21555aee654b8f47155a02fa4391a5100b9e3afc)) -* **deps:** update dependency @netlify/zip-it-and-ship-it to ^12.1.2 ([#285](https://github.com/netlify/primitives/issues/285)) ([bf00043](https://github.com/netlify/primitives/commit/bf00043a71018e18ddf9dfa23cdf9923da80b5f3)) -* **deps:** update netlify packages ([#288](https://github.com/netlify/primitives/issues/288)) ([cdf9261](https://github.com/netlify/primitives/commit/cdf92610050cafb0c0967eee8bebe76f352ffdb5)) -* **deps:** update netlify packages ([#290](https://github.com/netlify/primitives/issues/290)) ([ca10da6](https://github.com/netlify/primitives/commit/ca10da69a916ef29bb6251822548f9dbefb58d06)) - -## [4.1.2](https://github.com/netlify/primitives/compare/functions-v4.1.1...functions-v4.1.2) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.4 to 9.1.5 - * @netlify/dev-utils bumped from 3.1.0 to 3.1.1 - -## [4.1.1](https://github.com/netlify/primitives/compare/functions-v4.1.0...functions-v4.1.1) (2025-06-03) - - -### Bug Fixes - -* add guard against query param handling ([#272](https://github.com/netlify/primitives/issues/272)) ([14dc44c](https://github.com/netlify/primitives/commit/14dc44c2d7ff97a6ed90c1afcc92d28ae7d6979d)) - -## [4.1.0](https://github.com/netlify/primitives/compare/functions-v4.0.0...functions-v4.1.0) (2025-06-02) - - -### Features - -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v2.1.0 ([#237](https://github.com/netlify/primitives/issues/237)) ([5e7a805](https://github.com/netlify/primitives/commit/5e7a805077fad030494bc84a6a7495f20c48b8a5)) -* **deps:** update netlify packages ([#236](https://github.com/netlify/primitives/issues/236)) ([630e675](https://github.com/netlify/primitives/commit/630e675822ece3d4bca58673b0a899f5a6c06bd9)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.3 to 9.1.4 - * @netlify/dev-utils bumped from 3.0.0 to 3.1.0 - -## [4.0.0](https://github.com/netlify/primitives/compare/functions-v3.1.10...functions-v4.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v2 ([#190](https://github.com/netlify/primitives/issues/190)) ([5f20b5f](https://github.com/netlify/primitives/commit/5f20b5f75e0bb96e9224bedd7e158230ee688ac5)) -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from 9.1.2 to 9.1.3 - * @netlify/dev-utils bumped from 2.2.0 to 3.0.0 - -## [3.1.10](https://github.com/netlify/primitives/compare/functions-v3.1.9...functions-v3.1.10) (2025-05-27) - - -### Bug Fixes - -* pin monorepo packages ([#205](https://github.com/netlify/primitives/issues/205)) ([353a812](https://github.com/netlify/primitives/commit/353a81275dae3076465daf505c770a9218427376)) - -## [3.1.9](https://github.com/netlify/primitives/compare/functions-v3.1.8...functions-v3.1.9) (2025-05-23) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.41.2 ([#201](https://github.com/netlify/primitives/issues/201)) ([fa01004](https://github.com/netlify/primitives/commit/fa010041754e97b97bd1d80ca6d5f1fd4d1fcfb8)) -* pass route to function invocation ([#202](https://github.com/netlify/primitives/issues/202)) ([7bb9396](https://github.com/netlify/primitives/commit/7bb939649dede2fae6642f724e3491dc598621b6)) -* use ephemeral directories to serve functions ([#199](https://github.com/netlify/primitives/issues/199)) ([a749e26](https://github.com/netlify/primitives/commit/a749e2600c1245dbe7f1401ebd020a862cb8f734)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.1 to ^9.1.2 - * @netlify/dev-utils bumped from 2.1.1 to 2.2.0 - -## [3.1.8](https://github.com/netlify/primitives/compare/functions-v3.1.7...functions-v3.1.8) (2025-05-09) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.41.1 ([#182](https://github.com/netlify/primitives/issues/182)) ([5e2b72a](https://github.com/netlify/primitives/commit/5e2b72af6f0f7cea44c9176affed1f70badefa0a)) -* **deps:** update netlify packages ([#153](https://github.com/netlify/primitives/issues/153)) ([1fd1824](https://github.com/netlify/primitives/commit/1fd1824cd9f398921f006b0ccd538f371935d1fa)) -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.0 to ^9.1.1 - * @netlify/dev-utils bumped from 2.1.0 to 2.1.1 - -## [3.1.7](https://github.com/netlify/primitives/compare/functions-v3.1.6...functions-v3.1.7) (2025-05-09) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.41.0 ([#177](https://github.com/netlify/primitives/issues/177)) ([5b00d0a](https://github.com/netlify/primitives/commit/5b00d0ab22e4e1cf478e906c389768a071bd6aa4)) - -## [3.1.6](https://github.com/netlify/primitives/compare/functions-v3.1.5...functions-v3.1.6) (2025-05-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.0.1 to ^9.1.0 - -## [3.1.5](https://github.com/netlify/primitives/compare/functions-v3.1.4...functions-v3.1.5) (2025-05-06) - - -### Bug Fixes - -* publish `functions` files ([#167](https://github.com/netlify/primitives/issues/167)) ([24117d7](https://github.com/netlify/primitives/commit/24117d79eab9f1ed1bcc15fca6c90fb90edef6ff)) - -## [3.1.4](https://github.com/netlify/primitives/compare/functions-v3.1.3...functions-v3.1.4) (2025-05-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.0.0 to ^9.0.1 - * @netlify/dev-utils bumped from 2.0.0 to 2.1.0 - -## [3.1.3](https://github.com/netlify/primitives/compare/functions-v3.1.2...functions-v3.1.3) (2025-05-02) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.37.0 ([#146](https://github.com/netlify/primitives/issues/146)) ([ca75a23](https://github.com/netlify/primitives/commit/ca75a23361baea7c020afe1ec38b966d26403a42)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.38.0 ([#152](https://github.com/netlify/primitives/issues/152)) ([89d6ea1](https://github.com/netlify/primitives/commit/89d6ea1c9380f0b91959c241135ac6f1fb70cf3e)) -* **deps:** update dependency @netlify/zip-it-and-ship-it to ^10.0.7 ([#148](https://github.com/netlify/primitives/issues/148)) ([4208214](https://github.com/netlify/primitives/commit/420821490bc6b2986c60fe78a205b68259cd429b)) -* **deps:** update dependency @netlify/zip-it-and-ship-it to v10 ([#149](https://github.com/netlify/primitives/issues/149)) ([152529d](https://github.com/netlify/primitives/commit/152529d17ca0a8ee850ea90ee1054e1033ab867e)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^8.2.0 to ^9.0.0 - * @netlify/dev-utils bumped from 1.1.0 to 2.0.0 - -## [3.1.2](https://github.com/netlify/primitives/compare/functions-v3.1.1...functions-v3.1.2) (2025-04-16) - - -### Bug Fixes - -* **functions:** included published .cjs files ([#142](https://github.com/netlify/primitives/issues/142)) ([74fe165](https://github.com/netlify/primitives/commit/74fe16560e1474e1ba39a55765b41ebb704f8303)) - -## [3.1.1](https://github.com/netlify/primitives/compare/functions-v3.1.0...functions-v3.1.1) (2025-04-16) - - -### Bug Fixes - -* use right exports in `functions` package ([#140](https://github.com/netlify/primitives/issues/140)) ([10c61ac](https://github.com/netlify/primitives/commit/10c61ac0ad388ae6320a99d2ff191a7306830e36)) - -## [3.1.0](https://github.com/netlify/primitives/compare/functions-v3.0.4...functions-v3.1.0) (2025-04-16) - - -### Features - -* move primitives into monorepo ([#101](https://github.com/netlify/primitives/issues/101)) ([93b72b1](https://github.com/netlify/primitives/commit/93b72b1364022e45cbd87814dc6aa235f1e1c83e)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^8.1.0 to ^8.2.0 - * @netlify/dev-utils bumped from 1.0.0 to 1.1.0 - -## [2.8.2](https://github.com/netlify/functions/compare/v2.8.1...v2.8.2) (2024-09-26) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.21.0 ([#515](https://github.com/netlify/functions/issues/515)) ([b8cf1e8](https://github.com/netlify/functions/commit/b8cf1e8f5c1cff41847b78f96d549bd32d8ae3ca)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.22.0 ([#519](https://github.com/netlify/functions/issues/519)) ([8b7d564](https://github.com/netlify/functions/commit/8b7d564b2c9a88437a0956f60da8b4f3633a67dc)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.23.0 ([#523](https://github.com/netlify/functions/issues/523)) ([e81d740](https://github.com/netlify/functions/commit/e81d740530e005a56c7e85ed2f4eba6a5eab264d)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.23.1 ([#526](https://github.com/netlify/functions/issues/526)) ([08fee85](https://github.com/netlify/functions/commit/08fee851914eaa5f6be2cded1c57703855de4415)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.24.0 ([#527](https://github.com/netlify/functions/issues/527)) ([50b3d97](https://github.com/netlify/functions/commit/50b3d975e989be741fedb045b5b90e2c2fb30b99)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.24.1 ([#531](https://github.com/netlify/functions/issues/531)) ([4bd6f44](https://github.com/netlify/functions/commit/4bd6f44ceb83c707612f44f91207c098377c2d14)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.25.0 ([#532](https://github.com/netlify/functions/issues/532)) ([111a69c](https://github.com/netlify/functions/commit/111a69cace9042428d96428a1236f8a3bcf7b307)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.26.0 ([#533](https://github.com/netlify/functions/issues/533)) ([e7a0bb1](https://github.com/netlify/functions/commit/e7a0bb153bc80f82929352fdb3cdf8f2f2da75ef)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.26.1 ([#534](https://github.com/netlify/functions/issues/534)) ([97f340b](https://github.com/netlify/functions/commit/97f340b08c305625038681a484bb64bf10a84de1)) - -## [2.8.1](https://github.com/netlify/functions/compare/v2.8.0...v2.8.1) (2024-07-04) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.18.5 ([#511](https://github.com/netlify/functions/issues/511)) ([ca1bf8b](https://github.com/netlify/functions/commit/ca1bf8b865e91ccc06d3d618303d5ec7fb3ce731)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.19.0 ([#513](https://github.com/netlify/functions/issues/513)) ([e16fc5e](https://github.com/netlify/functions/commit/e16fc5eb096232740a1a6d0590cf677a7bb9f4a1)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.19.1 ([#514](https://github.com/netlify/functions/issues/514)) ([7fd4e3e](https://github.com/netlify/functions/commit/7fd4e3e63b08aca79fc7958f8a7847c75c274eb6)) - -## [2.8.0](https://github.com/netlify/functions/compare/v2.7.0...v2.8.0) (2024-06-20) - - -### Features - -* add `excludedPath` property ([#509](https://github.com/netlify/functions/issues/509)) ([5c390ab](https://github.com/netlify/functions/commit/5c390ab98df35e0c2e22aeb7af88e7287d3d1730)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.18.2 ([#502](https://github.com/netlify/functions/issues/502)) ([3af85f1](https://github.com/netlify/functions/commit/3af85f1f9bc5cfdfcd3b732430f00b4cc9224cd6)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.18.3 ([#504](https://github.com/netlify/functions/issues/504)) ([f5d365d](https://github.com/netlify/functions/commit/f5d365d351ef3894e00bec309902e9fa0b7b981a)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.18.4 ([#507](https://github.com/netlify/functions/issues/507)) ([3529a39](https://github.com/netlify/functions/commit/3529a3976a6f9e471a2ce93ca3813c99f6b30859)) - -## [2.7.0](https://github.com/netlify/functions/compare/v2.6.3...v2.7.0) (2024-05-16) - - -### Features - -* add custom rate limit types ([#500](https://github.com/netlify/functions/issues/500)) ([00e262a](https://github.com/netlify/functions/commit/00e262a65de94ebc27282f196eee750ff96cb0de)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.18.1 ([#497](https://github.com/netlify/functions/issues/497)) ([cd92ae9](https://github.com/netlify/functions/commit/cd92ae9056b6dbfd13b633a5ecf91f67ce96f88f)) - -## [2.6.3](https://github.com/netlify/functions/compare/v2.6.2...v2.6.3) (2024-05-03) - - -### Bug Fixes - -* main path imports for typescript ([#495](https://github.com/netlify/functions/issues/495)) ([a72e407](https://github.com/netlify/functions/commit/a72e4075a64d5c8cda068d6f32222f8ffe45e895)) - -## [2.6.2](https://github.com/netlify/functions/compare/v2.6.1...v2.6.2) (2024-05-03) - - -### Bug Fixes - -* path imports for typescript ([#493](https://github.com/netlify/functions/issues/493)) ([aa417b7](https://github.com/netlify/functions/commit/aa417b78b3e92d16ccd2064e7aa89c8964c5b276)) - -## [2.6.1](https://github.com/netlify/functions/compare/v2.6.0...v2.6.1) (2024-05-03) - - -### Bug Fixes - -* add internal to export paths ([#492](https://github.com/netlify/functions/issues/492)) ([c82eedd](https://github.com/netlify/functions/commit/c82eedda9e472c9d1b9c07aaec47a90e2229e93b)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.15.0 ([#482](https://github.com/netlify/functions/issues/482)) ([e342b0d](https://github.com/netlify/functions/commit/e342b0ddabca7ebbb11438814f97d8899dddcfff)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.16.0 ([#485](https://github.com/netlify/functions/issues/485)) ([9806ad6](https://github.com/netlify/functions/commit/9806ad6d771fe18adc81e91d43ffd90fb602c9ce)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.16.1 ([#486](https://github.com/netlify/functions/issues/486)) ([a5552da](https://github.com/netlify/functions/commit/a5552da8d2e4d4861f8a7eaa292bbde1364ae563)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.16.2 ([#488](https://github.com/netlify/functions/issues/488)) ([53309ef](https://github.com/netlify/functions/commit/53309ef388c6781ab94d5f68ca5ea7fab3cf4ba4)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.17.0 ([#489](https://github.com/netlify/functions/issues/489)) ([ccd67cc](https://github.com/netlify/functions/commit/ccd67cc8e1a1a11fcf4b9b0fee5aaa3c271c202c)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.18.0 ([#490](https://github.com/netlify/functions/issues/490)) ([6807ea6](https://github.com/netlify/functions/commit/6807ea671aac7d7ecf3471afd7b16d247360703c)) - -## [2.6.0](https://github.com/netlify/functions/compare/v2.5.1...v2.6.0) (2024-02-13) - - -### Features - -* publish ESM version ([#473](https://github.com/netlify/functions/issues/473)) ([b1b7553](https://github.com/netlify/functions/commit/b1b7553d7d3c7bce3504dbb6369d9901c69ac9f6)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.13.1 ([#462](https://github.com/netlify/functions/issues/462)) ([29b33ae](https://github.com/netlify/functions/commit/29b33ae3083a2bef04ed70efea02c9ed7d62a65b)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.14.0 ([#470](https://github.com/netlify/functions/issues/470)) ([c77eb33](https://github.com/netlify/functions/commit/c77eb338a2571e2b8cb820a09acdc9489406d247)) -* skip purgeCache in local dev ([#472](https://github.com/netlify/functions/issues/472)) ([9236053](https://github.com/netlify/functions/commit/92360530e9edd9685c0416f379caa6913e413cfa)) - -## [2.5.1](https://github.com/netlify/functions/compare/v2.5.0...v2.5.1) (2024-01-19) - - -### Bug Fixes - -* mute system logger in local dev ([#458](https://github.com/netlify/functions/issues/458)) ([f4429db](https://github.com/netlify/functions/commit/f4429dba6ce45663a9d3898d1afe83cc9fa184fa)) - -## [2.5.0](https://github.com/netlify/functions/compare/v2.4.1...v2.5.0) (2024-01-18) - - -### Features - -* add system logger ([#457](https://github.com/netlify/functions/issues/457)) ([f09ddc4](https://github.com/netlify/functions/commit/f09ddc44933156ca7f6b67b4c93e41c15c31c3bb)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.13.0 ([#451](https://github.com/netlify/functions/issues/451)) ([d15b673](https://github.com/netlify/functions/commit/d15b6737131e3b1c67e54e8129937aea924e7c64)) - -## [2.4.1](https://github.com/netlify/functions/compare/v2.4.0...v2.4.1) (2023-12-12) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.12.0 ([#444](https://github.com/netlify/functions/issues/444)) ([4baff43](https://github.com/netlify/functions/commit/4baff43486e0f7566959a347137d81f2e8478af2)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.12.1 ([#446](https://github.com/netlify/functions/issues/446)) ([7552375](https://github.com/netlify/functions/commit/755237528a51e88204b22f07cd47e93a7ea42759)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.12.3 ([#450](https://github.com/netlify/functions/issues/450)) ([0bfb610](https://github.com/netlify/functions/commit/0bfb61099ff73bc411ecc12915a7fb4d8b4eb6be)) - -## [2.4.0](https://github.com/netlify/functions/compare/v2.3.0...v2.4.0) (2023-11-09) - - -### Features - -* add `preferStatic` type to config ([#443](https://github.com/netlify/functions/issues/443)) ([9abc987](https://github.com/netlify/functions/commit/9abc9877d91257cfb7c5c51cdffd68864dcafd21)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.10.0 ([#437](https://github.com/netlify/functions/issues/437)) ([9f0de91](https://github.com/netlify/functions/commit/9f0de918c110625cb9f8c2286ae5d12bc934c962)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.10.1 ([#438](https://github.com/netlify/functions/issues/438)) ([c8551b9](https://github.com/netlify/functions/commit/c8551b97b14457c787581c18dcaad4bab47da0ef)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.11.0 ([#442](https://github.com/netlify/functions/issues/442)) ([d558f36](https://github.com/netlify/functions/commit/d558f3684cab4b7a2fcb84ab08bd93a4b1e91404)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.9.1 ([#434](https://github.com/netlify/functions/issues/434)) ([3f0b712](https://github.com/netlify/functions/commit/3f0b712e0576156043be1f22f4288cd99da5317e)) - -## [2.3.0](https://github.com/netlify/functions/compare/v2.2.1...v2.3.0) (2023-10-12) - - -### Features - -* add `purgeCache` helper ([#433](https://github.com/netlify/functions/issues/433)) ([f6098c0](https://github.com/netlify/functions/commit/f6098c066de33db09139a9dfe849b8e4876648c8)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.9.0 ([#431](https://github.com/netlify/functions/issues/431)) ([82f6c12](https://github.com/netlify/functions/commit/82f6c12fe19d143d86603c9558983ba87d010104)) - -## [2.2.1](https://github.com/netlify/functions/compare/v2.2.0...v2.2.1) (2023-10-06) - - -### Bug Fixes - -* fixes the ambient declarations on import ([#429](https://github.com/netlify/functions/issues/429)) ([271a255](https://github.com/netlify/functions/commit/271a255cc69bbdf75036c9932544b2820aa865e8)) - -## [2.2.0](https://github.com/netlify/functions/compare/v2.1.0...v2.2.0) (2023-10-05) - - -### Features - -* add ambient type declarations for Netlify.env ([#428](https://github.com/netlify/functions/issues/428)) ([88e3e7b](https://github.com/netlify/functions/commit/88e3e7b5c4c6fca42f5dcfd1bfa70449bc6803a9)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.8.0 ([#426](https://github.com/netlify/functions/issues/426)) ([3270f5f](https://github.com/netlify/functions/commit/3270f5f7823aef8f27e62ab39322514481b7b171)) - -## [2.1.0](https://github.com/netlify/functions/compare/v2.0.2...v2.1.0) (2023-09-22) - - -### Features - -* publish `Config` type ([#423](https://github.com/netlify/functions/issues/423)) ([392f177](https://github.com/netlify/functions/commit/392f177d3602883aec2d34c1906dc6896a32abfb)) - -## [2.0.2](https://github.com/netlify/functions/compare/v2.0.1...v2.0.2) (2023-08-23) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.7.2 ([#418](https://github.com/netlify/functions/issues/418)) ([81ed0fb](https://github.com/netlify/functions/commit/81ed0fbecd87501fdc6c2ff82a40e7ddd52f9b4a)) -* **deps:** update dependency @netlify/serverless-functions-api to v1.7.3 ([#420](https://github.com/netlify/functions/issues/420)) ([a32d2fe](https://github.com/netlify/functions/commit/a32d2fe3cea04be0037a5b0975dd8b073823d045)) - -## [2.0.1](https://github.com/netlify/functions/compare/v2.0.0...v2.0.1) (2023-08-22) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.7.1 ([#416](https://github.com/netlify/functions/issues/416)) ([86b82d2](https://github.com/netlify/functions/commit/86b82d29e9e344b0b0cb7dfea2683e3da17df350)) - -## [2.0.0](https://github.com/netlify/functions/compare/v1.6.0...v2.0.0) (2023-08-22) - - -### ⚠ BREAKING CHANGES - -* export v2 api ([#408](https://github.com/netlify/functions/issues/408)) - -### Features - -* export v2 api ([#408](https://github.com/netlify/functions/issues/408)) ([894fb91](https://github.com/netlify/functions/commit/894fb914107f76305bdb9930a2bce6ccaf01f21a)) - - -### Bug Fixes - -* **deps:** update dependency @netlify/serverless-functions-api to v1.7.0 ([#414](https://github.com/netlify/functions/issues/414)) ([6fba3af](https://github.com/netlify/functions/commit/6fba3afce7350dac0fa6c1ea4db223d5a59bd8af)) - -## [1.6.0](https://github.com/netlify/functions/compare/v1.5.0...v1.6.0) (2023-05-12) - - -### Features - -* add `stream` helper ([#395](https://github.com/netlify/functions/issues/395)) ([7b305cf](https://github.com/netlify/functions/commit/7b305cfb529d4fe3cdfa25b3eb176c5038f28b6e)) - -## [1.5.0](https://github.com/netlify/functions/compare/v1.4.0...v1.5.0) (2023-05-09) - - -### Features - -* add npm provenance ([#398](https://github.com/netlify/functions/issues/398)) ([ba70428](https://github.com/netlify/functions/commit/ba7042822dce1f94d1419bb6e1a39c91e2b9cb8a)) -* remove netlify graph code ([#400](https://github.com/netlify/functions/issues/400)) ([49f893e](https://github.com/netlify/functions/commit/49f893e7e5050013c1d87ac8744edb48016f1719)) - -## [1.4.0](https://github.com/netlify/functions/compare/v1.3.0...v1.4.0) (2023-01-05) - - -### Features - -* export builder types correctly ([#371](https://github.com/netlify/functions/issues/371)) ([24fc838](https://github.com/netlify/functions/commit/24fc838df0633feef42142e9150569d85b9c798a)) - -## [1.3.0](https://github.com/netlify/functions/compare/v1.2.0...v1.3.0) (2022-10-05) - - -### Features - -* add new BackgroundHandler type ([#364](https://github.com/netlify/functions/issues/364)) ([b2d112b](https://github.com/netlify/functions/commit/b2d112be4ab356fcb25fa2e2a05d2feb84c93016)) - -## [1.2.0](https://github.com/netlify/functions/compare/v1.1.0...v1.2.0) (2022-08-16) - - -### Features - -* Allow any status code in builder functions ([#357](https://github.com/netlify/functions/issues/357)) ([0264c17](https://github.com/netlify/functions/commit/0264c171346ddb5247d2e2900589e4ea207db429)) - -## [1.1.0](https://github.com/netlify/functions/compare/v1.0.0...v1.1.0) (2022-08-12) - - -### Features - -* **graph:** update graph helpers to work better with next.js ([#354](https://github.com/netlify/functions/issues/354)) ([b854652](https://github.com/netlify/functions/commit/b854652a8549c23bda3b060ab5bc756144caa7c2)) - -## [1.0.0](https://github.com/netlify/functions/compare/v0.11.1...v1.0.0) (2022-02-15) - - -### Features - -* update jsdocs for schedule helper ([#318](https://github.com/netlify/functions/issues/318)) ([4f4e34f](https://github.com/netlify/functions/commit/4f4e34fd4f9052d8b97a0745ef7ba79ddfe6fc12)) - - -### Miscellaneous Chores - -* release 1.0.0 ([#324](https://github.com/netlify/functions/issues/324)) ([2c81e04](https://github.com/netlify/functions/commit/2c81e04c4134c6c3e680daf5b9db5d7d442ea806)) - -### [0.11.1](https://www.github.com/netlify/functions/compare/v0.11.0...v0.11.1) (2022-02-15) - - -### Bug Fixes - -* **handler type:** make callback parameter optional ([#222](https://www.github.com/netlify/functions/issues/222)) ([2c9edc6](https://www.github.com/netlify/functions/commit/2c9edc63e4bb0e339a39b5fe77ec4f5320363974)) -* narrow type of BaseHandler ([#308](https://www.github.com/netlify/functions/issues/308)) ([d5bb602](https://www.github.com/netlify/functions/commit/d5bb602c79062ed34ed6f7fdaa628317e0ff4340)) - -## [0.11.0](https://www.github.com/netlify/functions/compare/v0.10.0...v0.11.0) (2022-01-21) - - -### Features - -* add schedule helper ([#226](https://www.github.com/netlify/functions/issues/226)) ([ae10749](https://www.github.com/netlify/functions/commit/ae107493cc46874e2c5ecac79afd46696183fe58)) - - -### Bug Fixes - -* husky binary not found ([#306](https://www.github.com/netlify/functions/issues/306)) ([0ac50d3](https://www.github.com/netlify/functions/commit/0ac50d3bc43964d116f388ffa682e96d9b085570)) - -## [0.10.0](https://www.github.com/netlify/functions/compare/v0.9.0...v0.10.0) (2021-11-22) - - -### Features - -* use builder plugin metadata to set ODB TTL ([#213](https://www.github.com/netlify/functions/issues/213)) ([c93c0a6](https://www.github.com/netlify/functions/commit/c93c0a6acf6e0ad3b6380f1a14efbbe22a14ef87)) - -## [0.9.0](https://www.github.com/netlify/functions/compare/v0.8.0...v0.9.0) (2021-11-17) - - -### Features - -* add API authentication support ([#217](https://www.github.com/netlify/functions/issues/217)) ([57ff1da](https://www.github.com/netlify/functions/commit/57ff1daaa7ece4a32489851c648447004f31bc56)) - -## [0.8.0](https://www.github.com/netlify/functions/compare/v0.7.2...v0.8.0) (2021-10-26) - - -### Features - -* migrate to TypeScript ([#150](https://www.github.com/netlify/functions/issues/150)) ([d79ed42](https://www.github.com/netlify/functions/commit/d79ed4273aa1d347bb147d0e9e4173f694b680c4)) - -### [0.7.2](https://www.github.com/netlify/functions/compare/v0.7.1...v0.7.2) (2021-05-05) - - -### Bug Fixes - -* make `Response.body` optional ([#63](https://www.github.com/netlify/functions/issues/63)) ([9932e07](https://www.github.com/netlify/functions/commit/9932e07b613e562af5aea2f93db8a5fa1526c57a)) - -### [0.7.1](https://www.github.com/netlify/functions/compare/v0.7.0...v0.7.1) (2021-05-05) - - -### Bug Fixes - -* Convert typings to .d.ts files ([#61](https://www.github.com/netlify/functions/issues/61)) ([f47e83a](https://www.github.com/netlify/functions/commit/f47e83a282ef4a8217941e14d23646c5ed938a76)) - -## [0.7.0](https://www.github.com/netlify/functions/compare/v0.6.0...v0.7.0) (2021-04-14) - -### Features - -- add type to builder wrapper ([#48](https://www.github.com/netlify/functions/issues/48)) - ([0af5b04](https://www.github.com/netlify/functions/commit/0af5b04c2b1241f64a56394317371a08781e881d)) - -## [0.6.0](https://www.github.com/netlify/functions/compare/v0.5.0...v0.6.0) (2021-04-12) - -### Features - -- rename builder function wrapper ([#44](https://www.github.com/netlify/functions/issues/44)) - ([3738d98](https://www.github.com/netlify/functions/commit/3738d98a17a538728b07758e6b8c795ac6ceb528)) - -## [0.5.0](https://www.github.com/netlify/functions/compare/v0.4.1...v0.5.0) (2021-04-08) - -### Features - -- omit query string parameters from builder functions ([#40](https://www.github.com/netlify/functions/issues/40)) - ([1219049](https://www.github.com/netlify/functions/commit/1219049a003acb693c5e93591a5d78ad678974a1)) - -### [0.4.1](https://www.github.com/netlify/functions/compare/v0.4.0...v0.4.1) (2021-03-26) - -### Bug Fixes - -- add TS files to npm package ([#28](https://www.github.com/netlify/functions/issues/28)) - ([88a73c6](https://www.github.com/netlify/functions/commit/88a73c670fac3ef2449f9bed5604d394e1ecec07)) - -## [0.4.0](https://www.github.com/netlify/functions/compare/v0.3.1...v0.4.0) (2021-03-26) - -### Features - -- add TypeScript declarations ([#26](https://www.github.com/netlify/functions/issues/26)) - ([6180687](https://www.github.com/netlify/functions/commit/618068784662782257d9d814c18cd3332e1b5fe7)) - -### [0.3.1](https://www.github.com/netlify/functions/compare/v0.3.0...v0.3.1) (2021-03-01) - -### Bug Fixes - -- **deps:** update dependency is-promise to v4 ([#18](https://www.github.com/netlify/functions/issues/18)) - ([6a92e72](https://www.github.com/netlify/functions/commit/6a92e72a68b69d99131abd1d19fa6c9e8ab14bf3)) - -## [0.3.0](https://www.github.com/netlify/functions/compare/v0.2.0...v0.3.0) (2021-02-24) - -### Features - -- update metadata ([#12](https://www.github.com/netlify/functions/issues/12)) - ([f92c4f9](https://github.com/netlify/functions/commit/f92c4f9cc89ba496c8b19dafe4ee0ebcc133dad7)) - -## [0.2.0](https://www.github.com/netlify/functions/compare/v0.1.0...v0.2.0) (2021-02-23) - -### Features - -- conform to handler function signature ([#10](https://www.github.com/netlify/functions/issues/10)) - ([261d4d2](https://www.github.com/netlify/functions/commit/261d4d25b410f29c060f666d38153a822832dccd)) - -## 0.1.0 (2021-02-22) - -### Features - -- initial commit ([b3a1933](https://www.github.com/netlify/functions/commit/b3a193372ee0dfdaa769ab4ec48f83fa980aa559)) - -### Bug Fixes - -- use correct parameters in callback syntax ([#4](https://www.github.com/netlify/functions/issues/4)) - ([b4154d7](https://www.github.com/netlify/functions/commit/b4154d76ac84c3a41756b88ee72bf1bfb985664a)) diff --git a/packages/functions/prod/CODE_OF_CONDUCT.md b/packages/functions/prod/CODE_OF_CONDUCT.md deleted file mode 100644 index fad7632..0000000 --- a/packages/functions/prod/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,60 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making -participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, -disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take -appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, -issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any -contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the -project or its community. Examples of representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed representative at an online or offline -event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at -david@netlify.com. All complaints will be reviewed and investigated and will result in a response that is deemed -necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to -the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent -repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at -[http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/packages/functions/prod/CONTRIBUTING.md b/packages/functions/prod/CONTRIBUTING.md deleted file mode 100644 index ef2bc9f..0000000 --- a/packages/functions/prod/CONTRIBUTING.md +++ /dev/null @@ -1,48 +0,0 @@ -# Contributions - -🎉 Thanks for considering contributing to this project! 🎉 - -These guidelines will help you send a pull request. - -Please note that this project is not intended to be used outside my own projects so new features are unlikely to be -accepted. - -If you're submitting an issue instead, please skip this document. - -If your pull request is related to a typo or the documentation being unclear, please click on the relevant page's `Edit` -button (pencil icon) and directly suggest a correction instead. - -This project was made with ❤️. The simplest way to give back is by starring and sharing it online. - -Everyone is welcome regardless of personal background. We enforce a [Code of conduct](CODE_OF_CONDUCT.md) in order to -promote a positive and inclusive environment. - -# Development process - -First fork and clone the repository. If you're not sure how to do this, please watch -[these videos](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). - -Run: - -```bash -npm install -``` - -Make sure everything is correctly setup with: - -```bash -npm test -``` - -After submitting the pull request, please make sure the Continuous Integration checks are passing. - -### Creating a prerelease - -1. Create a branch named `releases//` with the version you'd like to release. -2. Push the branch to the repo. - -For example, a branch named `releases/rc/4.0.0` will create the version `v4.0.0-rc` and publish it under the `rc` tag. - -## Releasing - -Merge the release PR diff --git a/packages/functions/prod/LICENSE b/packages/functions/prod/LICENSE deleted file mode 100644 index 7d56877..0000000 --- a/packages/functions/prod/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2020 Netlify - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/functions/prod/README.md b/packages/functions/prod/README.md deleted file mode 100644 index 76d6644..0000000 --- a/packages/functions/prod/README.md +++ /dev/null @@ -1,104 +0,0 @@ -# ![functions](functions.png) - -[![Build](https://github.com/netlify/primitives/workflows/Build/badge.svg)](https://github.com/netlify/primitives/actions) -[![Node](https://img.shields.io/node/v/@netlify/functions.svg?logo=node.js)](https://www.npmjs.com/package/@netlify/functions) - -JavaScript and TypeScript utilities for [Netlify Functions](https://docs.netlify.com/functions/overview/). - -## Installation - -``` -npm install @netlify/functions -``` - -## Usage - -### On-demand Builders - -To use On-demand Builders, wrap your function handler with the `builder` function. - -- With JavaScript: - - ```js - const { builder } = require('@netlify/functions') - - const handler = async (event, context) => { - return { - statusCode: 200, - body: JSON.stringify({ message: 'Hello World' }), - } - } - - exports.handler = builder(handler) - ``` - -- With TypeScript: - - ```ts - import { builder, Handler } from '@netlify/functions' - - const myHandler: Handler = async (event, context) => { - return { - statusCode: 200, - body: JSON.stringify({ message: 'Hello World' }), - } - } - - const handler = builder(myHandler) - - export { handler } - ``` - -### Scheduled Functions (currently in beta) - -To use Scheduled Functions, wrap your function handler with the `schedule` function. - -- With JavaScript: - - ```js - const { schedule } = require('@netlify/functions') - - exports.handler = schedule('5 4 * * *', async () => { - console.log("It's 04:05 AM!") - }) - ``` - -- With TypeScript: - - ```ts - import { schedule } from '@netlify/functions' - - export const handler = schedule('5 4 * * *', async () => { - console.log("It's 04:05 AM!") - }) - ``` - -### TypeScript typings - -This module exports typings for authoring Netlify Functions in TypeScript. - -```ts -import { Handler } from '@netlify/functions' - -const handler: Handler = async (event, context) => { - return { - statusCode: 200, - body: JSON.stringify({ message: 'Hello World' }), - } -} - -export { handler } -``` - -The following types are exported: - -- `Handler` -- `HandlerCallback` -- `HandlerContext` -- `HandlerEvent` -- `HandlerResponse` - -## Contributors - -Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for instructions on how to set up and work on this repository. Thanks -for contributing! diff --git a/packages/functions/prod/functions.png b/packages/functions/prod/functions.png deleted file mode 100644 index 6099417d991c5e4ba27f8524ff58a066edf68d65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32204 zcmdqIgMsbG?9s29@ zzSsLdeAk!eYVRZ`ca9||=Oq28sji5JO^FQv0PvKR-f9B?m_Pskl^TeKteNA(E<_eC zHC1)w72Q>zpPx|xfUvMI!1Hrbbu|(|S63HVlt$L*=tSh?NJ~rG+S(e1g(2(tEiGMK zTwK%A%*@P`kjcdb3F+bCVTNq=@bFAZ`rp1tcrPz6Ra;vVFE87$Fh@s66B83BB#fh@ zrH_wCV4#4k0*};NPH|aIahd=5mgSNF^GL~Yh{@1#3sJCg6Em{ozk1CoBtgT$Z)|Ie zY!z2hN4A>U*%?_{8oRjI`uTmXsVS-Y@?Wm}s*8k?ltYe-EPk&1YUbuNWwF8SwpxCEs$*NAN%1()*##cHYVpGzm=jO}4)bK}V zNmO@ARCTg;wTdgLiGS&2>uMwB7U54V7XRAGren`*9Zbe4!q(YVT3sWQTP6CngVV%Q zEw@KCr<*Q3k}Do6R?{h3)4{B2_NJqaqrFW&{)=)()0_4-w%kI|+Rj&|wlC#WXe8gM z=k>m+t5?x87OCxct!hT8Z^Bwp!P(wU$|XV}C`&J|8~$w+<#X zGhv@(!EYVh&FzBU+65Xq1irQNHnsCNw9A!r(K@*CH@3em>E`|3&iB28?|VB(Nd;fk zH*jeeyKj_i&Ug8Qud-2}mD0aAwsr`YHprBB$s%)E7q1&crJ(1HsV9S-J8xknleN1{ zMHi|qglbj|V2jdizwRUl__wq8ax3_Y2HFI*ZbaJwFcenHK zaPjrE^YJmTvMOyTKq@@o!CPDXJpcs-6$K3y4ILfr1^NpNj2D=gKxD=OVqsxnW8)w{ zxH!1DczCLDjT_JXP&cIL|4S659OqPc_ylAzbqNIJ1P#$3LP8>ZBI0;Lk_wXl1$llZ z{lAC*5B+XZlaak7r=*~wrhK`=Zpr}w1SBZGmDTY_Iqr)a* z>phtlo?CIB_d6;+JwNYkq@AbYVf0>~qKZWx9M*o0xw-ifBGlN>Jhm$;JTdxRs8HQc z+}Q8K=@6nYV1BJ7z!js>Eodx#Z6eS&#J^cEPvWTR>X_FmjPG~yQu*5Nhx7-xC*kM1 zo4~GyrBQ3`C`JrDD*g-dWVF$911(4sIT}o!1_$EyV(M>jVuQs2wRyeU2QQqskU9$T zh#`FYb!2z5^sr-#x`m?(;y!X)s_&=_n7L`Ojprw-E(}X_wlP;E7)EKfdB0XI-FZrK zK0_GD-!|gE1xAxq&hhDB{`Z34%+Gw+fnA}ma7#(%2!Aq)Br~3=X1K>E6e+sX1KO!x(YUFT2Ll#(=WF@1ULken0dmhZ^6vbeY!SCe{nqIvL2b z&s7QdXx3EUcXw1fe5}SVaLp)Sn!vHCS^3ypsx@-(ZJy-Q)M@p~@SwWioOP4YO%<8p zJHZ>nBP*wB;pe>Py}h2+<^;-Ib=Q0SPSZLJ7k-oRkfvG_u?iKBm-*^_T5`r+tta<>V^xai%x?%lo;1 z+~WGs#d>VC74y{kZ+Z7c*UFU4cqc0z!49m;gj1O7j@0iyISJao2^ZKuSIMzNd!`=n z7?tTAsrMm!$x3uNWmu!=33feAoj&A~OETNSORY@eRh8w&v3w+`vwk#u=ANe&t|0cv zYDEYdt`diCweh4Wb*{H|;!+i=AodCEF}U=3?bBr5$d+Xr=L#;2l&Vpmw<4D&Mum zu9J!ABX<<{_@C&e6Q4I1ZGWiuOIH#ei?iINwE6Lu8&3M zXzi)}{mYJa_71_EZXUlEUMsH@Ky#-&TeWGJ)yITb1#8oH1|q>RO0BU~6DZ=$e%*Ow zjBC6r-FZ$g;SU=OznH}hz|B!5A%|xKl8CQ8Dm7P+Z$u4i*1klb%`UwB= zFWQ9Mh)BL2<%fu3qM^nT5N6wp7Q7M?l-P@7BI14Adcb@E3x`DU;fx{aGyB>@wLNJR z!dCs=HXldeI&nkCU^nLBEyEw_J_1RLEf0EsETc#5)-S`I-LEQyF_&cJ3#Rb`qhG#? zCh^YxX_d`3I5l<*Ih_1u<&2WgduNo08I~qos!J=$keC7QU)qf8K!u5c;j%(U6L(>C zp?H^Ea}I9cOw4ANgby0G&c+OBx6=M0A#Arq=gt2}na?mH)`NCla6lWAGYkl%(9lEh zD9)!E%^`jm?!N@hx5G6TW>0Un6Jirv^&Y*5Mz4q3H;uIaSEcJ3Lw|S~b)!<{@zq~> z^oL>xcXOsGJrHb+Xbd*HY(f9oez19JL9>%77`Ys~Tg$DPA35+56;&SZI6_FG`3d(D zSNk!N2d3PP%-KVyJ_e++kYoPdgYfRDiU|@hCQae{y^s{eRY-aJQ$q$dTY_wv;@Up0 zSnxl>zC8&SataoHp{%|hPojTqKH`^WW;}*>Z6?D&n>grWlVcz47bS-O7}fR0*!e?r z#Lcmj9MCtS-TLJ3bC|zfDVym1x)krAk`mZ}AUP^&r-k;IlKdE*z=BlYjDD~cyR_)n zeCj|euLUl1I^Oo6%PeE9n!Ne|yHDgOgbSIdSDxd;U$@KhnAni638%YjDL5^d}@qUM1S)f17xZi;Mdpb-6QX$K7U% zL1q5VI(TV0+N$fcM**e6MS$s~$o!CU(fMnE-UZ9DYf*krBD~Bu;<3Uy1Ok%&vCB8E zP*!0Rw>TSse<<-j6P#_^TEuEaW8j>JCaxkB5VlBJFwred#Vi&2!1zQMHhDD{(FQw* zPDW1a*9CRwT)dPEBS1q#ljQv&y2NAlAyo0)H1Sjh1z}10`8jknEn7QRJKs=)SCa0t z>K~%`fS5rZKeb$zCRwjDtGus6k=)at-Zk?86i&u}k&2$xyPBymaa8{BtdIc-FSS|& z`N$}-x3h#!NxE)I{S}ZHC?-l{QypJ(>&z{a&ARJVl89kU$la;35rtv?hsBqDevK_i zd>Fr(1(*Fy-`uhrYqYL6)3d&KmH{M3*S3HNJ9|la__dZ3<#A&cg&y-3)LP*kiNQPZ zj&bsm-QH2>*rq$QU7ErVF22V(RrKC;*CSTD)dDea9+&yszlEIC$7{iQnGOTen_;83 zRvfR%I=~e`d(XHd^GTX%eYf8tnaP(uSw?q{vE=0B7kw`aeSfc024BUW@h%OMON#L_ zNw2(DE8ES)N#&>bt*vYy!Dimujyve+Z?PgTrTJG zopa&q6p!3+sc;gV;n7?}y#SxK(Fld2Q-MdAXqtn-_QnEpM|rznm%2j!1Zobm!alac zY!B^NT-d<#?Vkm`qx5Puni=YM0_UZ{{sy<>8TAf7M#H#G|C*hg1?M}Mn*(m-z7_CS zv+bN2t6|D5I$Op~xzWv;IL))+I+g1RZTg_vaIe!w&d8`tZ{jy%bJsa-gX5J$Kw6& ztZX@1<_N4)*_A4B&4lt@wgwxI~_mCYKd{JE;hCk-7K^ya_rW2^DD zO3txkM7!zjb(5jZmobVj)H)$er{u4S?&%}3;wam-6b{6Xje3S2Cs!~IJA|!TVXhS= z7iSWZG=e>NR|ZdN@*GOvN29K;QoAiem0APNzrqsRcu`fF{NdKS>S}XhT(9aRd>C#H zBk0uu&O=vQR&p_uQp*3$;b-43U$#%(?c0`028}G^^FaD9>3PCdR$9&`z9<&)vJDz= z^Yff{5CHEh>dbmVM@E&FjanoTp7t6ya##1(6DUkig_Qmggcen0QkXoEO z$XbgeBAGy}Woprv)pxSgwW_y>35j4_*u8YnO~h6!eiVuU)cK9Nu!Ny85Pk8&2zzEk zz3sVcJ+-Rx&u8r3XU=ONiXwAZ!_$42t=ih{phrTQaf~Pxeo;^I@(P*jlN$dV2EbiB z;+d+ir;H=*nr=b1FomtatMQ+uGCd%C$5ApP_2-IBypD>6hJvkj6(p<>2Iz%OiD(n$ zDRGR5rNj2bSo!%}8yNt=Ay3AOl@_qbhTQ#x8~C-cqAnGnxG62^YT>C^d7Fze?B&>- zTbbwBMboNWE|5!excL5H;3OzKDholGA~ZqrL!I1nAh zQ4!8ug(Mjb`NRd+ipXJ}-hTJ3%|7q$M`YV6)?8vGrSa%|)#-Ri5BNo!^bLw>G5k-~ zkV_0|p|x%<_<{H&834-VpV}1GhgYOgs1uh57cRUt!v7+FND4?rX%rDUUZ&k9@9M;4 zkw4h|E=k>w28bmNxou!Ad}DD<@;TMNJ`e@KP$O`rm*6UUm)tdxpjUfI#W35)gF@Xb zaATt@sSD1_*1@p-Os>cZFiP*#vaa=+9QLZ`wqs`B8=l}6qwPlrV18bj6%8Qyo1Syj zW}1`TC&(NQZH+be4rYTCY`5Fyc@Y!usXRwKnfC&GzdPn`-Z4`TXYe#u?Lfm4n^piP zzaUNOqZ85;nFoJzT@0&tSHJ%oh@C1%adz14DrIH%EU%yV0Jg%LAvA>mYJOp02N3$+ z|9!O$fN{LM8lxnD7o+4K^at%#ZyEtH4d?d+=$|V|3n74$eOjVEHBnKIN3LNznXWHc z7SceJ@a}G^-#RvZEZA;QB{2>#QLgXj8-Ty4 zz}+u(Z?UdEx-9OJ@wW0>;fNL>%7*GuyKAdPcF#^fp)^+GsUVn;&BZhm445>*Dg%`Z zHKKL@9nuQaht~c(3VG!p2LfDQ{&~_k3Gn{DVIWz7MQnAlgZ^UP7416(xo(VyFWlFa zxWx5NI%uzHr*cZ(A_7X83jBO<`dLo-1^67bn?yA=%IJ=B&$;K>=|QZbcS+Fji&M?x z67f-?B+GGQv<@~H7>)-vsJha&Z85C9u~7%_f4D5X)AvzC0gxE%?mMk?@~hB84s@Zv z*HzkN30i1;o~`2U;Gh zx{0`@A1`MnaO?aZdtcCx0hLoquO4trf#RA{z2cODqi&*$yv%?AUNTZa~uGGwUKXn+@G zfGG7~AZ>?BKiFRbddH-^+r6L`wQU1$8 ze4|}6@3Z230|Em$K=8+Ir^9yBHvxHN2Umh8NrA-4Or??M4^Abwfq7G*CDDM`IH&#pBL>82aCY0N<=#F!vEE)(yE6sOoLhV-ZYsCgTTgs zN+7K=aHPpdIc)}UlA{q*$*T`ZPIwCj;OpR-S#?SSV5Plk^P6pbMufDXjEs%{n>&(Wc> ztF<501=3cFTYbIFwR8~}YI2&WEw2R5)^gJMw4;E7(6>)QHUH5tT9^bm`eYRUU{th* z@1r1j6O!6-x$T)H#eb>$C(v}iK5^vwqq#!Y)SEP{HV)B1IR1aj*X@=5&wkgRuVLxh z+lGTnov;2KRPhHw%d}<|aO-*_jY|R*$OjKTwGw-3K?PTU1ZFTn>~I=z>mF0NV;iXL z*P=86vwJUzW$T-T0#f-eYqT_46t->^S`>5*-P%u1-6cLVp!Y`3v*I9{YYu)n^;5LZ%QKWlBIQKF>r;Hi7* zA4>ky!FNp`;?lBql9Ek`Y90*=ooi7TDa$mhH7?QG_~6e%L}A2)iN7%>)6yD=3aH?!@!N!{3@g4WT|RIU%S> z-WwZHensUS6G64uWb#ygvEEQ@!IrGr#!ddSZ{DOo9a{=;RkK}?oSVp}HwaC7;) zUhuFHwAHa8LW;Dh^7ciz44<&-_WEgTAul8LkY=z#_?VGnr2VLQ zo^u2MxPQx5_UmnKI_S>1h+N#7DfsZWZz*4hEpl~^jfMj?QgLHKDUxHWY7=6aW#E zlx2y5^nZiT3DZGh!M`)x|Fmj4aZ0%u+wDDQ07FLU?A4fxR{qU4qpikPvX!QU2LHYxnx@ z0t=Qq&0UHeB;w^2DWWUWxo8owk2Iz_kbEgwtSblA4nA*#LHRofAz<~lamo84&j9Ym ze2uT4l4^ldlubYY{j3z2k7&?C33}Hjg&;>N#P(nOm^-?}y-vZvcQsRLYd-h=qBAVr zkEi#v-S>YO0qaO{GC`K`qBTbE$eE*pPyrkH=IKbbJnyI-(yeMq{AHK>h zK7eCH=MW~{PBYyw>h4ViFux{D=I%V0B`669RwG5AQ5+s!=Np%lMrp$RP&W2`7n;?o zo*D!X3+U)eSEs@-0lgm!tQIaD6v*YfQZ%cP#)_YLHUl4w^_w!>xWtS`x`F~xeryLZ zTy9agY8d?`!t|dQFz*NGAT1J%&h4&YwZu-+&)5CEZqg6eRGH^B0Fm~!c^yKj?EqhS zvHklf*t!I=&*?`~;3I2dy2wbh(5&#DV^TVPp@=eFUr#hq_X_~8>IeM=m7(WGKeBNb zMlEvbFBZGo#j9fdin+Md{1+d33l=T@F=WkUqN!wRi+mfw4YT{*(t)kWW>9DpDjn;$ zFY`3ky>`}Ba8}%in`FVB84)a##LP9i9>ke^qE$ntWoz;2Rl{+NUMcuDc>Is>< z(xF=O30ElrSzv4ur_EOuzuyO$l}u$N&++5_rYsw-q#Ru__)X`Q)NTi%y!-kOzb7cD z?(bz%mf4s|C|r_JhoSUxV7%adO{VKi9Io^xuC}};?`eH}58`BhaBy-&%Y$1Yy?*mt zJkFDssUY1Cb?=GS$kaDiG*D%jJukjkEpsmD82Hj%G8L;}3?60V$SRwz56TI@#H68O#)WkTPGdJZ!s3ZtJv&{BKX-5yo)LeQH;Vr1n zXfs6xRf$#LU0XNq*OBTYQ6-Gxr2%R(|RG?mA7;P%%37q~Ojz)}O z0-?qAKdO0camxZ9dN&+)iNd9!N9{;V>{@;3mN zxZj^qf_(UQTFU?E(-HpemADjPj;Hg_Z!X5IlWUa2a8?U(sHETvVhkh5%pi82j^ek| zJRpl*=JUQ_P>$&(Ars;F*aSDnDEH`&lEdX*(UjqCu>_-zC|D4-&ZzW@ClLcosZzqH zX%=Bza&}7CqVVYQty$#7FJCgAKUl<@>z1Pp2Ro^l7I2w_dK;>qD{`rLcPt_%I@tzu zPobRLf?2fwtAKhQ>9E&|fl1Z8s`tu}rjZ#IZ0qDy4Istf8+j$#IE^^d65UUK6E)*N zEjAAc8XW7b^l$BPIHH##;FUH@x8j_?TRn)GachB?Ep52DJVI6m8kj%1aZs2uvfjI! z$4hAs0oG=_1nXKuMC@FX(y@Ld*K0u)M%MVjCpDaENFu1E=$U63rL+tUS@sC4X%J^U za*%F+5Rg>NS~58G=_`2`fgeKnC+t%d)j&ZEQ)xi$udRlB$)_5|$9${;$azBvTph z4UOOAy3#^`A)|!8oKmJjh}q1fesK7@;~GA%JneLpu&eLBVXt{`^q-e65v_jgo14o? z8^n@H)Eeo4qVm%+ZH=tRm!+{ltOK~6Xg%Y@-c6Ava$VRjTuVA@Et}HjP0`FC5bNj3 zBVLY}u9RTpc=M)?j!;NQtGJuODm(Q0qG8nQdi_Ckn9uC_IbJXv+a7~jgbzC!?P-|c z!#}LARhv3VB|g`gzqf`AttqfGZHE-ehGaCEoL@l!AF(lrKK|m$MgLWsmikEs)!rLK zZD{vzwCB97_CEA9_OzqOuSHp!N%riEIOl=5MvL*)n}wh;sq-`jgt+x9L*U7VvtTiy zu#$!QLZ#D+4Q z5Hkyiy-I>uU0PElQbrqK(J^Bctm-khd{XAzeaz{}7M4?k1~_hZQGaXRT8rXuRE1i2zE=l!SQrs*_{c7QR94uI_czi8Heqfn{c(Pod+7flr zIb-a^Og^7IVBa_?K`Z2Z3(36OC?W7Y7k^q>luZTQ0W|b`iXN@d=>_MGNb<$a+J`&s zTdQm7UO2HkIx^mH1CI_5)n)qV66dqrxD{{ShFr3sfJNXGfp|0MB4F1_yX12O3U1PH zk?ra1$u7BxaZZd(;Qlp_2%Ip*Hj(#)7=XCAVGszcMqD0LSF?j$f35)!@b#SPEp@a! z2ztm#e&C%FDxT@5L8KKxMA1bw1tH#HwoCyRZ<(w^OuZib)vTW#e|tLi-ha^{3S%*MiZKUISQHS~HyJC#+s%Ac(FN$RAwsD;9FEGH zd!QLmQXu!k+N2DAVJ*Xs?W^;`q_gV9{_SEE3(_RZxdV*!^PgB?L$4q4)0et41~aoj z!JXBgbYH)I`SKMF2Mb=5zD2eh{&`oazW7LHXDl^&mIb$4-*8E0FIZ z@{Z_fK!%kdL)k28EJ=-XY>cxe?Ot2}`@KO04a~Uza@9NBok8XneV!-jZ@i68vOAr~ zzEs!FOdm^2FgVHJeTL1Y6r5!+Sr?`y0{`9J8*|4ax`+V+4-p zj10=bFUu?-xxP5TImKVpFxMh~`dLD!ZF4FmAPM*_OeltS;Bu+w=%5&3-tPc89Y-*j zP;z0>0Q>r`$H(s}AbaBDGlYkemB#%7a{5V9W%E1~iXu8T(yLN%CQna3r)*7*3m^ym z%Zp?*V1+v^;sVjEks8HBujRj-kfKd1e|p%fims|VOHz!^_9yDAJ31x|2bMM&ac)DG zde~kkyC^#+s#pmwc|OlyP!#ENE}9I1$Q=N8gupB;Ea<8_bNiaA22}X?aKghMoipVc z1WhTa)W@feGnT^|71$oqw-J)TN#5I24({j2_x|d{mtbQ*dnRu>XOtHm9Ubjwb|5b4 z-?E}0BFHm*l68Rx=IEWD#YoM&>RbepD^XWhKW5NbVKES_)`nQ|7-CT83sAtO_RN4a z1~Jsfho`6A?tR%{g6PDQ(?+Qh0uv@o3JDi`5#uB~5)AH*zqOZ2+5d)*MSHB+cF%Ul z3I(q)KYW|*usp2}Xw0&Gijx6i_!2{0Zuo)Xnd9Q1Ln*M{i0a2BMG^2GFt&8FI3vSY zYa%9aPBE@w>gS@Sn|lZoM=i8+i!hlHcFX#D%ERN{A#v-9UH61z$0VNgqNo?QwCX(&UPU%rDXRPd5$riL zA8Ck20Cv*5IaUha1-kO>h0m`GT~G~0bPOkxzmTwL^VRs{8d?;v9J|q-#pU~9|FE2E zOd|DJt~KX=hs+sgck@Besaa=_*(9U!*Z!A_tO&6E$D4td36={Q!3Z`Aug|oF$4jo4 zS2+a2iq@ndKm?*b?9bqx+k;b>(q8D$Ab-c03T~(I)NU#beY{O8>?vzYQ($ znyq(p#AnWh0(OP!tc)KW+={3^;dZn5LBX%gDq($A%WdymNNVha=M0@pHKw}@^y}HP zaiV^Io|g%jKhFE{J2dF(aL#F=_Cw6LnbgFFJtievC2?BE-RX>m^dsX{7cR3Wn*#N( zYx%e7|I*afe_X9>%`uuf)>GW;wfjkA3k*KV^s;7BdCo3a)Kfu3%FR~nVm84b`cO56^J*aLYlsL zWvayo%B5e=6P#1Q5-9q7_WGMYl~s=Mq1nuPl4(k2vXNp(@97y0OWr!e{>xNf$dEP! zIr9l*ei7lz$w|h#+9gsx-WsSwb4IBx4DNxAUmE|oSJALKYayn%=HE2uupXF(Mi%Pw z(dOIPy^13kaJaTH>zP_zon=ke1R&Twl^86{y#+EhGOzAYFz5w@H(VfDW%SoR$>f(f zP*%0RsN?-a4+!M>l6#v66~TLh4c$wW3x;j0>iel`Tc2mnKqh@$YLUC+{2Ix@fN4dw|B zQ#b_X2T7f7KpR;1Wx~`GBv32^TrhKzKB%zZ;g%hVCoE#46(Mq z2QFz&2&#tKXO7ss+Sr|vy;(ZF=6YN%FseW+rB6%@JRv5i5>zdB^j;R&1wKcJ!oQ0e zXua=GSxqg24Z9(21rcOq>(+v#N=&7)qI$m)B8+7gtT*zxOhsg8{&XU~>=k z!vqXU$bE)hbZwI4SRy9E@HcLC&WqGn$Bt3wF0Zj5N9(2)LHcuuz2}>?wS4W0`OMNG^m_TNY&kE$65H=fkU#1F~C@9mh zO)VBv!lvx4UR(7Mjceu4+|u|tYcN6{LxGU_^^KO zpp~_+O?iFhXm(Hh^l$g|%6^ByDbrD=o)4+K!Aa|v{J5!hAGhur1D1&MCSkK6JTtea zSUm9Inq;e%?pf$}EADo-ab2@Syi^Qy#YVT;SphwNrcUh+;WyIKVf0jN&FmoUqcLf? zOUb7gh+TKbV}Tyn{xU_DZdFxUiH=aUL&KFr)O%lZXfQ+ao6;LB0L(8sVD&?fgO%3Q zpxV{LJnIIyGmnrpaQmEIfYvp!WB+IpT#~`^h)s29DCj6OOE4GX9=FmVu!x){gYo(8 zGbqG(Fzh6$hg1xUm?1*X0i*WhRBH6^$tcl+hPcT>!Wq#g;q+QcUAWxtQ&C0Sp&5(f zMP@iNnqK)R0!r5qRN&spgg}D(OJKJe?azX7$y|q;bm3dou!ck+m@&u4^D-lsU09#I zYc#EvJ(0ryfm!L6@^!@doW5Dmr#&*@Z`<`$28=DCgky2i_uyQ6EGH_b)CXOS7 zfGZcpfe_je)#duTjUcBiN~A|L*IyH=D=bw~wm*8+8Q5lHCtYhKYd#5hRj5Z9%C&}X z%IYOa@dapS=+UlRPyzlWwCLON&H&u?Z)OZVb_a_OZLg@G!} zzgZQ1u+I^Z|t}|C@@%u)8v^nlBjm5a>}J_w(3SsBER5 z>5EtW$FkuCxL{5k2)l>9rU?JjW>*XZ#Sm`tkTRvzANFwDaNL^l;MfCmmsdvxDuXE? zMeIm=-DlPgv-!1fjABwzxHzS{6vGEKPey&sVma=Y-kVpyt?_rl(r{<-EpdoEr=6o@ z7BpnG9iVjF$Y$DRl_x|RKYWODktPfo@2kYS+Mruz3EdHg3&PGfWQmOw z5Z;_$o}R7N@{dYoyamcvzm zZx0kF;Wc6z1p}e=PXKyx{~8n+Ad3Qtk4!~}zcdTs1wwwY-?6F|uSLYnm%|#ncwce$B)h$PV~ySV>%ifnnA@Yl220w)?vc z1=Mg97~-o98m9gp&$XapZIt>IxU&z4;^7y1%3(|V^lhEf<6=wv4ELJ^e#F$x&Bevh6&=e3U)$`i;0lLW#=nVx4m|{$=`Iz5{vq{U zR1p6>S8@AJsu_im8=>}+#!Q?W|I%cm)ME&w@>9;!==Kn?1C|AlmJt|xPjyIxRglj# zg}>>v=)MiKz@pX7uo=|IE{$=mAfpzDAzp?nNDAi$?j`}PTPYkoV$By2Pox9)&n)sA)w&VwCt229 z;l7oj1HnG!Q(6EhUXp0q=~QDEcoQDgM;EMh&|~)Ch6Q=P`fVfxG(*Gw{WkovWMk^6 zJcU8ZIWW8jOHdF6@-K~!Q$UjB4Y5q+h)txd|K{6b#^4EeO-Cd1FCnR~JB_*9dEG7Z zlEapj;bTu<HnJaC91`^y8XDb4&u0LmlXN0<&F0+M1#f0HrLHdQCWR=d#o zs7z!8<W8=(@x_CyC~e|Fuqh9#MMa?EEf4e8$3z^gwNV!q z7Q^CVVIO1eU7KXhw8<}&C;Y&dTV6+;arC1fqGjku6uoX?3PkDAP3(3`>nJfv;*AW< z%<&uy#(NZRZ7h`o`m9<>`PU3uof1B#+Mbv++8WZziU=;Mt9@D|2GmO9G6Aas`p(+) zJmZCcACXIqK-6s55S>ng>@B-2@FWhMJt4zZ34XK1P%b8!2nhdP?l6Q=4uq|~RRn&3 z$|x<-Nf@4%?F2HU9|~ff(Eeem#!{aqNhS-nh)7jSn7%LII8WSe_GTH8AV7K_#4PGE z)&imXzSUAl@93wjpc4rtOm_c-F(0~ao%0}=dJPeXj?OMIG0_WVjL&#ONAJqcV}u4% z*qr7gCa!VS(Y*|&l#D9k{{qA%`(kWCq12jik=--OOE}GmBZmeXYn;$_E;HZ((PgfC z`MUq|4)X-X!?aE?WyO#>`5cCb@uGsz(Hq+HLBQ$t2+P&)dFner<2*kF^qroaBqL)o zAQ*W;s|pXSpnwwxUIL|m*rw67jL@V7W)%p`!8}w~M&E4Xf9!u53n?|L#b4#H6D)HwdU-WO|G_46DW_pbfa~4PrH+zJ8-e&2VAEEBVkYO+AhH%{9 zcR7=-hmUbyA$jtIxZi-Xuv2evXeiAcNQ028cD&r9s1A$#!8bGgg>ua7@6MedNUB!| z6kW*4QGT(aTsuefF~7UntB97k27sz8(<8DgrixBskSNZ=+mHLVNk{Mz%8iF6hmNS0 z`3_X~Jn4 z0(>NZyutUBOwAfPeDBB!;4a&AOFFb^O=IY?M`-aj)*y@<^y}<6hl$-FT<}|k3N_he zcL~|b1e;m1a?B4mkpGE~mT^D>+~e4w7IIzHlm*9}yJ}AJ_TGr}L(T`a^@J2xnOb+8 z3OBQ*h8-2DsM4Rcx4csYKb7ULdc`60a@%-~`?NSsG_%y`hFzRKW?Z;<5WYZb5EqR- z=#+pxq`(Gdgi23#G@N|?gLWGjL_-;3$jQ1b$tABugp365;`M8r z!)5PO?SI6R*0~vyPy$^>IkR7u>iRw-!Xr|1sm{^7zP2D^Q5g}bG4*bA*7gEeKtmyw zA9|DKwW&tSosBniohn4bbfp}MtsTKZqE7nhnCyO3Fa3UD(0>|GG=gb4HnKIOWu3<~ zrJRe3fNLwmEc4l*Q_xh3)F({XgTt=+nrm`j)2EMA;$0yS+@$1T@_r_I8rYm-cA;kj z^rZ7MT4{&p!+zD?Uc;G*R)^mrE$q4Y6*-=bW+L9d?F~Ir5v+v^LIys^ zScQ_EvSmUtrZtq?CbmRTA|6XMbPI=b=VmqA@3^|p7PlM%_rRjLWOul~PEzs^`M*VA zq^2Oz@FVg6Mc6%L6HpLx{fbGWS4$|I!`tU z#BMINY4HbfzTk)yysHa?-V37BeGHUN;)b%Z*^RN1Dwk)-)?6_2u}5lVuae2b9FHmQ z>x5}OD!?--zLhWVR9%0>b*)_Z!6%Id?34ZPU|?orarn}S-t$oX-iEghxl2Hvo@hS% zX;3I;k4wRiuUbsQLTuJIzdneZ{s_tHy14+yNQo-u2}@NX|GR^lfTcD{BFL*H*C#9^ z>khi}5?G~1e7#45fSqSU`*hPtU|I%nNo_gFOl-(A&8+4#^Xbt*wbl+MCrGd5eYRjO zRRbdv#>ok>A^`3=`E}OKEvqD7Xr><8@}16Rj+GnRAgnSu5zwEZC=^Qor7#;VX7z_}oeyMY52Y5hd*cdZo6%YhWJqc8YMCh&e}4 zg@_p$&Y^dbr8D{2$EPgg4~>6;7$sX%Sj?Pz2}+OZB5!}Br?HS7reB~+iWaBn$$rUk zY%^EcWy25?cSR)}3k2^12`OFxizwahfP|E~Y;bEjZ%@zZH{u6CEcj0VIMIOWd6wzD zV6Hk+H#_A?kipuob*AYu{jcK!P9sOr{8T`R#(yMw34Sd^lVOg-$MbQxX6z_0;P%8?U*%~R=CUmldThHN_Wfj*b4W55<9wNj}ew0~or zL6jn7mxBs-cDtG<`-0Wn*fj>bwBGia$?hC7BDS+izh;M9kw&BX1Cck9QnTC4rK1i{gr{U8^8& zPQj*FGzH>+biSX)OQIxld|w%Cu@0^()w$AhUi=}#%4*;KB1ZAIcUicfdzOs7@9au)J*hZ5)%`XwBfLJHvp6D-Q8A zM3oTS--bNsbSdhMYjUV|6iBk9kb@fwxS=l${~&5pRX#9|4^NEV#ILcN+NX@yOC>4I zq{$Q|rv&ajaedk)Kn2+j_MGYb+c~z(VLz^vj;n!0{A7LDP7kDj)L}$TI#*=LDB)_q z+>}{dULJkC?81ayM-c(rl0Y}oq1-B$v&`Z!h6mg9%stbt1_Ho5~W$k!H{^_pkB`R`b$+#p62P7!J^@VIZko?f|NMmuBv zZN{;_mnrwkEhl(G{VHP++mQ`p9sXh09LWVm#wtPN4$CY+=vipsjk6*Uq^J84IdML} z%nTo<3sxIKMTi$#D=wDL(%^t~5`{d*1I?)Ek>?#BMd2qqJAbuJI{>p>P&PFb@L$e< z3?KK?GR%Tlw5&uEybNdi@Ozv;!bfJN^vV%+@0bsv-AD!KKp9_fPH(PIdgN8 zoFpgtBsaf;^oH2nM$saVXSO{=TR7p%MM9*2D0mRpxbw)rBiWsL*2!kGrT4dJvEaN7Kq+alC8kp4Yc~kV2DQBH5>pP7yIYcy)tI@lCB7_+oZtk!3@C;P(wG*- z$2ZDAjTxBuF#2ixQ1NCwY}$+TQ9>GUsic5x;Owu29gYoVoocmL3ssAZok%ri2f)+3 zcFe&E1}!Rxo5ETVg(faWh`>8QC=XDf@8>@ZBO_Pp9jC|NS>i#UchFGXdX!%)-+ zOtQy1lJ@Zm^)b@#DA-xyk7@))ok^gMk4&wfhm)3b(2{#JN?^7R=XJ3E)hT~xE%6wx&U>a20B~5J7l@Lj1>gU2&Fd&~PEI}y0bFq)h9woY5WD#~FJlX9 zbz;a%3ul#5JcU}T@qJECP6!{p^*pnD*&S|NUfCB2O^D0pX=;U~wNSc>ZIyp{3!z39 z#Cb!hnd~^{xP4;i9XjL-WEU?K4RR^M8R^|TsS%n0&$Ju+vZFyvsp*62 zDvol_YwAK*ji}AofM2rPB1pc;+52KaM-?gd2d0=6Y$eNXVxtr;N!0^xYl?MG@sV%E zp<2uOjNIoi6ELT2@R0)H)8FvUttM<7-AbTLcR6uVD1h<+#AVbpOuHx72`?#=B(278Ou zZrFs$qGUnCO+hSOjW+QB=$kX7kaL1|{7Pmth|%imcP-zOz}4TR&7PH2cMcgTG@|P? zd%$5S42VfKWjH5o12*c!0>{StcW{^HCTAO;bJ20F^vAIOniFP9dc-6ygss^k7fWg; z8$0p@T(x-$`e*dmEb>+bH9rt>85n3ydKBmc&z5u*tkq<+dBoCNnz~Q3&!{3ST5$$` zcUAq4tR*16;p$pgZs_(jxlz7pIz-)6X;s!7N(GtC^Kv@I!BuCJ_fE4HWDQM7k{mMj z8$qNY9`dRLg28pjcX}XeU*C-QRGFs@pa_R2J;ElHBj`vQRPyeTiQnn&x)~YzCk5+9 z!&Xa8p?p}>NpTq$4<1N9V%^ZmivH3s+Au9koAMX`;mYD%P$4f!oMDY1GewO37)Ky zLWaIbQ9rZs0aGVXLeE24H2&pdLPO6k;g>~@^^fS_3BuT42VaPx7KWm}4b829{}g6P-^BzPA2 zf9nV>8kOZ|UZ;cG#fvIZe_0Xm8>pJ-rgmD$nrs4r=Nww!S$d-H>ngq)nr%|@XrgXY zY08==h%(khkohyhv%dz2hTyScm>6i6E0y0%*RkOZhPbB{W)0 zC{m9(N05A2HdWFzoceT{{|mi_Ro#v)^dWDX^Md;1K#jU8SrUj2Mu8Z-x)8NlY+Aa+ zBXb_{0b9r@6p>f2CGX?cBKZWNQ5J*ZulK~l&_rWtv8}=v1n}JXZoj1wvnd9%CH#9%72&s@pg1tRTLN+Ota)30~9v!&-Jkd_*cx_v(Ei zhFZ|3LT|Qb|0Na({rdt0)9|Y%g{jfbwcMpL{@P1O)xUDb&YcE5|h_= zWN_fy0=1kkkv58l!q7l3<9%SBZ1j{T1P4dkA99fF=H`YcR94EFIdx#s?!TolBaWL( z$J_4z@sQ<=*M~*00<+LZ&3)DcJ;|Gz`W?_n_Ut;Z=nfkK&Y#8(>29E2{L+Q@ZF1}t zxxlW7Xia)-{wpgX3T01mv|>S~0^!NlylHUV$MWM4B(R#A=cJtZ*TGMcZAuLgILPum zFwPGHvOn36Kd+4v3J-p^q=;9?#cwV9tyIuC;)afz=|nAR@YYW2-mM)fG}@;KK@TTY zvI|L%2H^n;T@&5TXMZ_(w7O$e)N5u)RZvcfwScRE!5M0MuTjX^IYK_0NAgl!vssH7 zwzjqBD%+=nmr1}$hkC{hEPo)>v>w>vK(Vdlq3a%Na`?jA94ICDDK18F#M$obv-6>) zgKq*hb$65qfnG0<=3KT$F!jm5G|9!7y$9=C%-<3pu`A|2jUq|Qqtgl|5Jk-lj$qGg z&!-|?DhJnflE-lc>6VzQD@C0>tDp!FrHxSY);bX7|1ot+yE7yJrP#&m`8xe>oXJA~ zHq(u5R85RGjZh$nhKN@|4& zIYjNt6bcP{fx5b>L*6FEbgD-j*GQ$}?mK%i6i7Byzn|Cck7f>As5o>`OS&tQ?}!ba zV{TYvj;J~mhvL%7#gY_R$A+7*S$L?s8{S%)7xM-vHA%&wWrH!ysIic-P@j+?nj|mE z)ySE+EVhiX)19vXnr6wk81xZmdneg$Y+g+9yuYghe-|Z<3K{&$#}A-kUZ8moPmj&{ zzurcOX2_pV)amTS0%aW6Luz)AToPQryt*~5UhZ3$L+iH_7O#w^IuW5g&}m9NHl*f`4N|F7|u2&i^>Nl zL=oLYS>8$!e-M>5h~<|lQOclI7LdEgnH=xEjT&Z7d)Qr^-XG~D99Jd2V6}gr3Pr^Z3HuK=x?BJNrD-A~M^TG5eY#K- z^P@QaRhT1U!5GfiD)U91ljzFnkNeK5fvkx}tr)#F!AQ8zjCfzgbYexk3-dBC`QwU* zo0~bFQSdp9Hrti0Y&c~-Kf?>3a*|Urr1hPvc>{W!@z0WI**?kFvQ5*#V70h7^ne6m z;UMarW2G}{n({qCBvRQBZ6%9AGSRizrLL#^m9FM=1L0+nPcHpk-{lB_pA53HvP}6I zKxyi1ppSxWh)7wh$==43wy%YqpIR_c9>|hQY#Es4u>;(;w$I{HQvB*KI{GiDSBzCc z8E5-50-&)Br13I0$a`(QilpM}5yL#wcLc~c&0 z(Jj8&ew_BHvgBmu?=k|X_;lBnne`Tb#S>p6`4rZJ9mUax!6m8$Qc2K6I$aSSa8z&|pDm@rjw2CrTHV^b!K$-E7w6?% zFS)olTb9NWMa{-0UHNO?sDt*W+mIw*kP+vKL7SftwYQ+ZTSZ^jTN5w98?y(4ioZnb(GvR9 zRRxmp`&!2$KaQik=%`USv3&Uj`g&4mba1-&_D~m6YA=>fK%o>+pBh5JrbeC8PFN-g z9&VGSg82UxcO@>+3k6^4kv`?FPcek!k={^jW?+WPM&QCT_8h`TKY7}!l^cenc=3M! zqtl9oB%^^F!{7Pg&D$-JOuw+l$k4G_po#BI(f=kBTAZY&UwGB+-I!LU#Gogq28}pN zDoBl(uf)mFvpZBtVdH)eWUK5mIgccpUDV5tM>UWjgM7v zIvwq-oc2jrmsXS@wnUQ0 zgU5*{vN`8Na2x!qP;D3&G4y~Cf~a~W3T*fkVtvk1o&U##womw)JG4+7Wm~EY$nOwR?&lj3;+^)brOk#=JLufX7`__w6*$SVrfe@5O6 z<0P3sov|EH(d=aa@bm@uosP~tEBCXhQUe3lRyrj7iFzIGo_K)}Lo z1jwfrLKb3K%hN8cg6HqvS|5W3o$DGCR4+ym%`$cBcYxFM2qLYFK*((2?g)m@m$%GD zf(#<1{Zz?8=%InT^qGQkdTMHFS(d8*B7`+xr=Q`6z;)#>y!;}OEk#e5 z2oTuiryx+A%ht>iuJ{O_a({R~{JQd|PQ4{{*zrI7v>sbOCl++G)PE}-KZ6dl(jQE1 z#-L^MFV!1U=kSbqBVMNHnNCQscZ9yWRONI$zIIpjF8=dq+lV+`!iQ5t?BrL1VUHM- zw}aEIJi5?7QPXk2@mY|l!y#f(Hvli4ry>EEdf~n zQ`y54^Y0#$JdFEspJ=OpB-D8TelQ~1PCGFodS#eYtJ}WR^;RlOBzP<|uFlN&$P*%X zlk1oZlv7~HhW8BkIBPcKtyXIpG{h+dE{V($a-sM??y5 zYq(wbB;niEqHEm($@F=bt%?rEd0KXAGQ}a&E}LPK*Tt5M9Ok?Rv%%%S-MaI0h{PHZ zg}4Ti&)c^YakBrq3K`ZqQh|Xjc5r;J#O(y}Z^s?<{vA*yjh&*wnjT{?A3M0AQ@*EF zkpQ#oyoS)BSAKmbs2_Rg=3~NdZEX2X;p#-%wl@>EP!6m&uIr5HD&;tb9p_yFTaJm- zEEsGw=CDc6Va5}~llZ&67np>%;U7s`jc!r~8cT+2(>#D_x;T_s*^AHKi#F$5{Q102 zQ5EFOK@am7R%mo!0;Ac|gFWOrZx@7$T#5`@U#kF$`iC0+!0~HFS3I1QI zOdAu^o&O=7)QK%l@y%A6RJ{N}u-IDrlQ~=XD5@gaRt7Q`w}Ot15(MfeU#pjg%1(qzY>Q@#8v_)~l`@ z)yHUqx4tuP#;^Zz(+YUSLEDTI1{w=LhkK#|;Vb6AUSs%X;!DIwZT`^ZLU=QCi61Q5 zf9o3p(UmwJP3LY@Lh3oiaQ^e4h(X-z%c;npfk`G2M8Rp4Z1pNxT|YkIOqYhSQ1@Q2 zeC70;3B51OG=Lzg>CiV0dDJk7-3h)n23THkkyINU zm<^&(JRsq^YEJ-Ah6JPU=*eQ<$n`*+^1jU5Dk-)a&$wMLQw>wSybL=9aR$Pg>Dd3( z0N_CBfxm}IHL^-%?c>f6H$GCYZntoFbNy$mxj@`;HLY0v_JH6(vSB*akD$3pjU*9;JyCc@W9oo5(02!iuxiGDOEwD092f5bjY5dOUZYk<9e)FXkg*iAL2n9 zW5qY3TV!!a_qj&)lQy^$XH5;*^MDt~B$!qp0NrAqJhA7UEhrs3B}4(k$@V)1NHT)4 zSK}UEApQ`Ie)`I39r*h?bZa?|C8+X4;gcawWH#xZOEOx~8lC>0x&)wWsp;ZrK| z8|`mr?zZ$8!EK~n8ZdoUuC-pZIHDM0o)?6T=yF;g zgYK?+TxXJ;rJiQhMEYHqpnbe@+8?R&bLX{5pbQUCt-q;Q94hC|M)xlYzQHm{?|=Ut zD)f}~Ce`!$G3LpJB;BHK)_m=GLFu&;{*TwBdr}Bs=E~_oKR$bV26C5Q2Jy1s^|$pX zfb+LfU}oJS=_gq|%E^^*A3*OK+UB?Rco+3?o0$gY;)2{${Ga)2U8Kl>`;XktW4I3G zn~l?UU8JcNnI>PsK!jd08ir9V^7e7?Vv9dy7P=!81_I~OlgTp)s?w}wF+WC}u*PIn4FM%u@-6vqjdtAgIi%feS_G%C|o__2IUBNyQ zpjWquWvV`{Qayl`WXkGD5Pv_bxBgjpE0Bc;}W>F*Mg{-zd!HrU;mVuyIHyIfWgdgil6w8$*@1gMh=@8lzOO1tc=e2x}#wj9X#l>ex$e`{8;ry(b{$eKEJq8J6hxxqAOB{Xq~ zD}l$TK;R0^s$C)nuJ(+df0aP!Mz`c6J>(+iJ;k5-o9x}P1{dB3J@tdzxp1Ej(i=S> z0$`c!XxBc)4?>3r_GSArUtmcB*r2Nlt799D5PAYugWR?}UTXId0ho|nbU#8UeX;o( zuYh@(#P1J4$samJqYMwg!ELtWDs@%}IsXw7Apf~EJcs;-)T zi1CByJN+BA*K#1M-y4HZSYQ@Un}#@+QCa<+_WDy|K?2~y6%UlEoc8A1zKv4Py8K%f z=YB>F^t+>@0rcXC#tRhjCGyQ?(~-4z35xaf+7kphL7ZxJ`1MQ2c<7wrlLHKpUw?wZ zfS?MrXURKv0)9SadWa})t{ES?q|F*o^)S{2j9;)xS{i^Svrr?80O&S>^}oHT$1Vwf zw=DoB1e1>frf6skBjGr`p&@(T70Xx_UHGI1$?~9Y-o6EKg>`}Q&JbQ)aYh=^Q?&+6 z0NijyxtKozt@ucP!}aGO7d~3Oi`<2q(>!7);whs4a z@t{ie{|xdl)|oQmTv4UE1~k~QEN{%4wlfIi@diL+80Bw1VpFvDngBUBCOCdmPWS8V z_T|{f=cuiB;Wl;Z5%`t1VEJcwR2XQG=Q}_W82IAXY{2F~ljHg;YnJPfxiqRSY>qj= zSERepWE;g~dGL;mCMM~1ldB7_URJj#1K5EO1iGxpB)TGO;|?b~>i?})>-Qf?XkAL5 zFmIke5I4d-tpV_3S}c>QpgxLjkrBd%9=zw}YCFjf;=N=U8x8V7|3Bun9&TRe)%jk7 zAx?LP_Olr)mJB*Y0Qax7z*fuH2l`kb8yb*B&(KeP^$mROST&&H3UVbCyw z0m5_Q>f=oDqgz9~w`fNA_k5Iq-r$Oh4?rtg@=`X)?q?0{Z`%JUZ4hXJal2tC`xb3{ zkY`!92+%8AmNJW*R1nZxIbCEf`d#4{>3{#%Kq~g>yUrZGeV!?e@`DcJJUM^G$}1Wm z=nOU1pVsmT=_3T*pB4u4K!P8eeSY)U8rk<22eB@a_-64~HzWP>t;hhHCU`-jpVyLx zE&3xCKIsv{!K{5sk`>RgTHc}si82IWXp?u(>FZgz&0G_PAZS_=gw5~Th9}vkLe4U! zjn~ELiD5gOf;4<`^?IiEg0gL4oo83k%=8DgOY=(pB`r#I8{gfZb}uSLzqE-Y1k@pm zz`+b$E}$)ThG>jDP<7+dq9Vw8i9eOl=Ct*9Mvcv~ltjC%Z`l!SG#5(5T4(ak`RJao>f+{dPy-RpW6#}5Jz@z<{;FY*K)wj8JIB`O zy#WMn&CnN6O<9vDg3Gnq|74r%ia9U+6#LF4?urYLTJ$`ub&!#|e~RYYqd}7c z+~2q-?R^ zmAiP0#FeRNzUl>jAmJl3Sj9eM+eLs$p zkrc(2I`htzwPB*R_O-*h3p+`q$ zMf4t1cUutke`~Hjs*=s4H?HoL6KF(|?B-*DS;WWBu z8d}!_`R_Fv*!(Js;BJOC5-f&h5apAvWzh5668W1BPf$K^XO(k{#( z>d#r$CYY77R?9RD4>=^7UIs15U`_dfmDaH# zyQSN>w_vu4^xkq_1UWe}9Q4BNe3Zo11SwWht~AVUa9fr&nR8xy(<}6(*K-np1@$XQ z5rO`ae)JtRTqrxEL6g7;^5C3qVz(fGaOZss>r@Xc1D=5(0GodwUykH8Ax{mnm8nTO zNx!anM#!^6idK05UZmf>#1DelBOy z0ErZ!Mj)O?*@Jo}xHR(Zt{0LLSfJiX^aKzx3l9+=veSPT{62dC&LWeW!Jm#5Nw*_A zifD=S{Q^*vIIdWaQNRXzvJE$D-Adx)F`2Mp*?7&8t_jtnDxV@a=>6?Pcg!Ebmu{9Z z>ul?9C7|J)h-o(Tcc|59j7M?^-MHB5f?t`?`UNvFXd2npGYXk)N0%;GQ{e1aeg9Z^ z*8YZ_lrOwyhE+&aFfVM{B{yKpn-0FYjRkUYY&9hAJSJYnjFKgSQd?}t<(Ioa8&O4I z5GUj&u%pKDR$E3B@;Af@cVge{evrDDlNyEzct-mg`xs+{tlQTZDUPR@DBnKrpsato zT=R6O{qp#kN)F+i%O|ifB*9p=*|;QA`M{1Bd)uZ@JLrdc5N9p$4W67U?aEA<64cE$ zU1)WocD-9d2{6=0^<=gQzwv%AZ8Jcp*~@Xd#FmQO#s`>iiE+Cs$kQIB;cC2VUb40L z3=$`A?+(<@+dO6l`1u+2+|PRcL)3Kb82*~Oin(yO9i;s7Zg*pdmE&nb}V{T!;^JYmh!6B>RxjCsQxc|Z|Zh%X0<35D&Rc1{fP$9>HDT%@%vx#3)${H@y2Z$!G-0QegO53Y zUf4g0zr-iPStXq4jdR{`U>-AY`yg{%YAc-SH#!(V?3DWAS}cwml_K4NiEMT?^>y%d z*;&=|j&p(z6Jg_GV6?-z=jB$=k9vh{sU}TBN`4(x2uGR>qRWB$*Q*v2Fs0+;3@xK4 zSK)SD5?~=Zvbn7(X>p_jwj`RkTfDu!Osgqi0VK%gj4Fmmk^?2M*7Vppl> zY#T())-+GkK0dg6BI*&5)$h}(#PJt4c2^ZkdESZ1vl%awRYLQN_*+AT4%Da7*f}aM zIZtAttXHL1u~bmXj9n@rF$IA0gwKq9G?jtLAha5ddIhOCWE1l~I+W!x_?%~|<+~Ki z5M1)FO4{HW-1u7p`$eyV18rR67;iq)3c78FST+6QpXXzBRjhu%+^%vU4BqDqqKMK0>euSvLZ|jc@b(*w-b>!MnZB z;$w?jGlYGS@Y$h^_Rg}_2YSaayr+rB!rR2Q8g!4ur+XU)VYB2)M%!`puTx%3QPig% zMo$!#Bv~mAr*AfwlJEgAVIWIh>Wt`E7?S}?oQH0#Vl@g(Sd105XDd--+~;_ksZ1Gp zq9bY!X14F{<4IvojmwVn+4YyE+RQk6G#GXx9|Rj!XV$Tkq#?kY*Ie+z%J15{o zaSz8qY~4fj7Clk~cK)K~=>O!iFkcRY1e3x5bFvV zJiDOcd|eGEt_`YyPO(OVuGlR3sdDB&0lDeO{SGb8e&r2?`cx{*Ij`u@iUP4CB!rgK zSx!7Ua`1R?Z!bEPlQ0v}zGl0Ko3N$X$x9=R6tYDhkz}g%wpz=Q$IGZMynP#z(ahIi zv8q>vr9GRRs2>!k=)u5O*(`8!HSVlV)q1fFsEZREJr>lMHI5#~+FP9`qlkVyccduu`1{OZYoiatk-*G#`-$B>2Y z7{f$YQChJPPR`m+t9pRAz5h5F{WTvDS2fK|AZk{`dZXb>;ejPQSW71-Yud6D_SIZD zMZb*3$|}d`7zn445>~NA{04oMB!)O32h&Y>NHmgn=qc38{MzY!cbjQPN(DIC%%ym5 z{n)?ZLXCs?UDFcUIQs8F#y=bMt;ht$bNJK+B1F?`BR50P#?#Nxr5G9?0%{k z8kvcE>Fi78;Zh<-NQ*d$IP)@ec5W>lMBGuOpw-uk_jUVNLY?C^{h|;pICs0iDWWdM z#4dy~QOV4Sq@(Dl)K*~?Wy~|^=)O_3SV5#V$YkuunDY^)sE;+~>Xj@;)FJ1>6&ow0 z4T*+oTwo=(n0l4zwDj2z1Cp^1e7XF?l1L>q2E@GT1%SEY$L9aIDltf?V#xe~`d0$- z1oF(o7V6;E-Ql+MOU{_l<=qAyo|%d7A!mEK0Wm|s)rSKYa)`i(!FgHE4(CL)U}IIB zv2*dw^W55u%#VS9FSH*sF{FV)DjW+Rrh8>HrEQtNIwI*8^OoA)nZ?V_PWQIgpBye# z_?NFjk+yI9)Lv)wG8h8QB%Gcpdj_c@4U3$*XB!K1uqV!Oj$RfvPpggJ&79eRy{6ZM zr-dF?uk!m{flURkJH-czOjDIY#-d~=U&MF~f*Wi-f&CBMH zesEy=C7Yf7YkfG2l&kHb;A0KK)4*WNI$XNLC5Jqtk{NF_RZxDc+r;}RT0_okm=t&< zX|*V;T0ps%BFoNo9MNX}Q!!JUE(bT)O!tai;*-8UOS?aPx^1f$j&TH;I=i}mU)p|0 z|FNPK+0Ywl$)Sw!Cjr;HG)v1Iz?!SvKaUmV;V}QC4Ro{nf!nw}w7XwYTQXN_8+}MB z-o(kOZ{VHs?KU3k;}0TT&4I`NITsQO#=z+T^P0Ae&-~h?oeK>IA4B3f59jR9E^ZjQ zoU)ZfZXoAKzD1(A!sMv`a(hc3vHMo#49I0@Eg5$%4=8&6huhkb_6Z&Hvw*I~i`{Cap&0O{Fp zED@$Sy=C9iDNsskv%kaJL4PHJeS`hu=xCNe_D7$%;;EP0E8CXQw8z%gb`~-i@4MTW zS;*vRxw})oTX~isARt)zqw6FVBzHb(pBe#O5ICi%4mj0xm|y1V#L1%BU1@%>*gN5i z$BYUTALv{V*3S{%ANF4qx!&SWhazgy2dUQYCW9o2NF;~^W7(&Pb51H~8a`C-AS6ac z1DYXy@6H7@c^1&7zVR$>ClPRbV8B4?NvPQkyy&^_DQk`&c!GC?b7M<8`)~QyE!C?s zPJTOznHJQPjTlKWQ6(TSM4!mbA9O*L5w~;P-N>FI+GtsJ97xMdG5CTRr;r!cxP1pc z!=wiFMnp_W5xg-=lJT*FeZb3kD=`!JR!|@(qeqIDV^@glyF-x<&YwIB?AM;PvU`)~ zo^IIZ*o)WS#AWZMH&@$dOMk07yWb?Olj6(8Jl^Gd1b?w6NESmzMkd`bejy4 z9>>>TA~V{2Tzz7?bv65x7;o{bkl`b2Wy7wa^KVi zC43tq_{UK_ma^EzRTz5^AwOJNYnGjBlGHB+0oP~<`@~qYOl>bFh@j*KPZWto_Zwc+ zMLb_~8EO6Jx4+Sjsd4?w6t<#<=+{&i?t0*|^K3>t@_TX@JgF%C6LxL09;ynP@;(Ff z=R?O!n3KF$ zJNfzjBcH0-Bv<#$TRGiK^_A1EF_3{MUdi0CS9cDtak%N?IM?ne`ov)6lgTsZE7S3c z>x)65m7N+@=(5ifdO&CAJz_x`YL7#hTE1?27f*Uoes2c`-R9}bYPHh=^7>b!m&b?Q zhqs@N4?VTD=c*uuo!~%NNj4BmUG=zu@vE{h3C*G#>N;JbePSe`vKs04 zWswSCEOQpWdyRcEl4d{PUF+fZC3kBsw5=vESC8 zkd<|ub~NtsMA%r!IeC1u)KQTac5y!RNIi{{dO{y&Qmsoqi zrP%v!tszGO(?;*@h%n4>?XG1$Ci>jjDE_UF7>6op{tHb}?)g~XtTdm)U3UYJ1BGlYFLPr64uHIf7*~(Bt&CR0#bDpYptWRgV zVey(SU%H#=Vmoe%4(0cZ{$`(;734$G)l+J;x-F1F_B5U4n8Hn$=-L=>d%uOMNDGi7 z(Ayp&e53Ws%FkLY-e#tT5F-)myrr?n)UuEy>6^H>dG29)O^?5|IX)pdDe+Mb-8;6w z_{;E`J$B=`;kNO7a+EF6%L}KA+hxESsz=c^F?o%Saa^?Ap4D+2BO&LDpd0~y!&y>( zsrdS586$lcIbz;Kf2>btp^rMb{cB9I*O*@khpH2Sm9x6o@D#iSBH0&0sxC>ubQ=`$$+!WM9^GX7Xp(5DG zS%Fk8+yCUoh-(R5seK4I-(t%JW}>8a6XN6JchVr)?5`*&hY9$7qxB%z)3QBIdO|Sk7y@3^XWi+`RqKfj z?BnUkko9dKJF$#NV}}=<3&JNo@BW7fFV{Mh&!0XcctUUb*@t#>-dp#zeK9xR67iff zxs+$-!bNYP?v_nlXXgEcx-wpIrZSwf*qL){Jla#2ZdNAetufz4DCAR{WajCWp{fl{ zRf}3v`oV+L#skU0bT@3oQ}M;I^9XRO{m$(n8niI;?=L}@rY>K^rn>7Uu{<7{8bfuV z$8VACybDrNK8j&@{8HE@?ka?TyOyh_d@7ta-41w zW*iCP;`Uf5i~N*W!R79O^AA*7Jg;qk-%;c|H|c8M@oIC5h%(blc6YR$YK1ch)!c0` ztavVV&HuZ^p2e%l7-aCKwbU<8SGTSdDLNK*5z6{|Ol(Bqc*9{QL|XCpht!?$e?&p= zr8=>BcUOFuf3mYhU!oqZo@O9(4)S^xxPMKYg51YuWMs6$PvryI`=Bt-`7_hPfB*Wd{nzk6GrSnZKe~!dS{BIyfqc+ujIE9x5jJ@bkN)#Q!vC z{ya(EY5;bh7z+Wwkkzft~8O zOcI*KsOz8i35vvdif)VLcdUgj|GDq5RV9z6P`79L*cC ze3Gl*1p|dqp`S*SPHPp;Y|oL&O?s7@)D^{9y6K+xH5=`%544~E zYRd#>vixlTx=LIf=KM*|OAI&jQF@c_v1Tg1h;J@EIS_PDKRqc?b_jtF+<$X@Hygj_ zpo8c0yN812=KZAuPDFm5Port~J4o*S$E*ZZWwN{l>P+swXTz7uS8bS)BkItOgUh5m zF6|h9#Lw4)G4l(e*1DfMef%i^y_#aDa0{$s_HC~KQD(h+1sX9eHeOnU(46M9C>c($nCc%d{S*Kk1Lz zZ8_u@hrd0YqWaF{2RZL^C=o1Hyr=uT;bwX-T4Mici7ZzWRjf({lTB1|%TPQihKy(h z=iQR9s+8X_>>OdzHzVhEgT}`23H)rSiOgy-*K-7ue9@=uhD~g*+;wVPuWb*E{jBzW z$GK!ur^j|sZ0)qx>1d76P4`}-H`N9j@Lj*!H@-y%ZP;uVZ7|GeWuILYIqpMZnx2*E z^x-zpoGxPbe8}JBtv<3tXQZ@ju%->qdL#A#0loSUR+CJDH7!y~2)}t8Ga)uFceysK z0`}&H)lb_rK4#6=I*oht(-c2d)9+^t!f#zED*l=^{WyaPTcy1YoFegC7pNyo0NM8!fyj7Wj|Aw zM4^Zf-&@EK$F@lNEO&LA&c76iFY;VJ-Zb`PPdrB{m4}S2xsLBPWppK1w)z?2pw^p% z(!l{glHZBz!72jhs03;4dw-2BTmRdXIlLufBgClPTw76eMmFN_I}uAL@C0*>q|WHl zAsWr+N}ZH!MPvGm0mW%^0A*!14L`88<>e;4Y+w62PpGSm^rnBb{fH@N{_xa(Tga5L z^jz?$3s+j^+n~5}(r~lv>AXEBj-}dqJ+>9EgPPcK6Sk@Xp~IM#Ozyeb){L&Zvc&$s znj#GrX)c$p?H*W>8#aXv=?v-eZ4OHN=1B2QIte0evfderUJ^h;d*fCnGb!qIHNx7z zUrDAX=l?s7zJ8&`P3$ZD@4p^Vcc%3Wn%BGRNsjn!M@#~W_QCQPeAgUG%1;qk;*LL` z55Jb;Jcya0yiL8>w|X7aPnx-S|9&QLY$f79ore`Yjzfbyish=ud;SR6JRHLrvxMHmcg>$NQ^#9H>bvmO1VdsuN}CKsJ-hFDRmU>Ua5 zQAEM#Mvb1YZ4HBEr`Ieq$gj~_WvIJPOrVTvb(Eu;kkevm3WU9HQ8{zGvN_d4Nfsj+ z_ZuHbO&9O;8INCTzOIGg+``r~V?DddPR1%(h&=qcsmVltOuQU#mSKAIob_lHZzT#$ zH!ipDcVOf5eLbpa-yzDj-aiZRb~?gi=95_cK21UVglFx+F#&yO?$3Uktz7P_n6biH z{WH;jjNP-MW9{*b>QB$>OuMgrQb7$e#VW*v3tj-{*W6F z2;3>JuF`y9duN5#?vTP->IJ1oeduZp?69(2g$!f!?Em1FOCg4D)#$-KK=jr a;kg7#W>B#c!L{yxL@LOre5e7NhWszv+ItxQ diff --git a/packages/functions/prod/internal.d.ts b/packages/functions/prod/internal.d.ts deleted file mode 100644 index 9c50a9c..0000000 --- a/packages/functions/prod/internal.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/internal.js' diff --git a/packages/functions/prod/package.json b/packages/functions/prod/package.json deleted file mode 100644 index 15878b4..0000000 --- a/packages/functions/prod/package.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "@netlify/functions", - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "type": "module", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./internal": { - "require": { - "types": "./dist/internal.d.cts", - "default": "./dist/internal.cjs" - }, - "import": { - "types": "./dist/internal.d.ts", - "default": "./dist/internal.js" - } - } - }, - "version": "5.3.0", - "description": "TypeScript utilities for interacting with Netlify Functions", - "files": [ - "dist/**/*.js", - "dist/**/*.cjs", - "dist/**/*.mjs", - "dist/**/*.d.ts", - "dist/**/*.d.cts", - "dist/**/*.d.mts", - "internal.d.ts" - ], - "scripts": { - "dev": "tsup-node --watch", - "build": "tsup-node", - "prepack": "npm run build", - "test": "run-s test:ci", - "test:dev": "run-s build test:dev:*", - "test:dev:tsd": "tsd", - "test:dev:vitest": "vitest", - "test:ci": "run-s test:ci:*", - "test:ci:vitest": "npm run build && vitest run", - "publint": "npx -y publint --strict" - }, - "ava": { - "files": [ - "test/unit/*.js" - ], - "verbose": true - }, - "tsd": { - "directory": "test/types/" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/functions/prod" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "directories": { - "test": "test" - }, - "dependencies": { - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "npm-run-all2": "^5.0.0", - "semver": "^7.6.3", - "tsd": "^0.32.0", - "tsup": "^8.0.2", - "vitest": "^3.0.0" - }, - "engines": { - "node": ">=18.0.0" - } -} diff --git a/packages/functions/prod/src/function/handler.ts b/packages/functions/prod/src/function/handler.ts deleted file mode 100644 index d441082..0000000 --- a/packages/functions/prod/src/function/handler.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { HandlerContext } from './handler_context.js' -import type { HandlerEvent } from './handler_event.js' -import type { HandlerResponse, BuilderResponse, StreamingResponse } from './handler_response.js' - -export interface HandlerCallback { - (error: any, response: ResponseType): void -} - -export interface BaseHandler< - ResponseType extends HandlerResponse = HandlerResponse, - C extends HandlerContext = HandlerContext, -> { - (event: HandlerEvent, context: C, callback?: HandlerCallback): void | Promise -} - -export interface BackgroundHandler { - (event: HandlerEvent, context: C): void | Promise -} - -export type Handler = BaseHandler -export type BuilderHandler = BaseHandler - -export interface StreamingHandler { - (event: HandlerEvent, context: HandlerContext): Promise -} diff --git a/packages/functions/prod/src/function/handler_context.ts b/packages/functions/prod/src/function/handler_context.ts deleted file mode 100644 index 03a08a9..0000000 --- a/packages/functions/prod/src/function/handler_context.ts +++ /dev/null @@ -1,24 +0,0 @@ -// From https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html. -export interface HandlerContext { - callbackWaitsForEmptyEventLoop: boolean - functionName: string - functionVersion: string - invokedFunctionArn: string - memoryLimitInMB: string - awsRequestId: string - logGroupName: string - logStreamName: string - identity?: Record - clientContext?: Record - - getRemainingTimeInMillis(): number - - /** @deprecated Use handler callback or promise result */ - done(error?: Error, result?: any): void - /** @deprecated Use handler callback with first argument or reject a promise result */ - fail(error: Error | string): void - /** @deprecated Use handler callback with second argument or resolve a promise result */ - succeed(messageOrObject: any): void - /** @deprecated Use handler callback or promise result */ - succeed(message: string, object: any): void -} diff --git a/packages/functions/prod/src/function/handler_event.ts b/packages/functions/prod/src/function/handler_event.ts deleted file mode 100644 index 63a3067..0000000 --- a/packages/functions/prod/src/function/handler_event.ts +++ /dev/null @@ -1,21 +0,0 @@ -type EventHeaders = Record - -type EventMultiValueHeaders = Record - -type EventQueryStringParameters = Record - -type EventMultiValueQueryStringParameters = Record - -export interface HandlerEvent { - rawUrl: string - rawQuery: string - path: string - httpMethod: string - headers: EventHeaders - multiValueHeaders: EventMultiValueHeaders - queryStringParameters: EventQueryStringParameters | null - multiValueQueryStringParameters: EventMultiValueQueryStringParameters | null - body: string | null - isBase64Encoded: boolean - route?: string -} diff --git a/packages/functions/prod/src/function/handler_response.ts b/packages/functions/prod/src/function/handler_response.ts deleted file mode 100644 index 86fed46..0000000 --- a/packages/functions/prod/src/function/handler_response.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { PipelineSource } from 'node:stream' - -export interface HandlerResponse { - statusCode: number - headers?: Record - multiValueHeaders?: Record - body?: string - isBase64Encoded?: boolean -} -export interface BuilderResponse extends HandlerResponse { - ttl?: number -} - -export interface StreamingResponse extends Omit { - body?: string | PipelineSource -} diff --git a/packages/functions/prod/src/function/index.ts b/packages/functions/prod/src/function/index.ts deleted file mode 100644 index 9aaa827..0000000 --- a/packages/functions/prod/src/function/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -export { HandlerContext } from './handler_context.js' -export { HandlerEvent } from './handler_event.js' -export { BuilderHandler, Handler, BackgroundHandler, HandlerCallback, StreamingHandler } from './handler.js' -export { BuilderResponse, HandlerResponse, StreamingResponse } from './handler_response.js' -export { Context, Config } from './v2.js' -export { NetlifyFunction } from './netlify_function.js' - -export type { - Deploy, - DeploySite, - DeployBuildingEvent, - DeploySucceededEvent, - DeployFailedEvent, - DeployDeletedEvent, - DeployLockedEvent, - DeployUnlockedEvent, - DeployBuildingHandler, - DeploySucceededHandler, - DeployFailedHandler, - DeployDeletedHandler, - DeployLockedHandler, - DeployUnlockedHandler, - User, - UserLoginEvent, - UserSignupEvent, - UserValidateEvent, - UserModifiedEvent, - UserDeletedEvent, - UserLoginHandler, - UserSignupHandler, - UserValidateHandler, - UserModifiedHandler, - UserDeletedHandler, - FormSubmittedEvent, - FormSubmittedHandler, -} from '@netlify/types' diff --git a/packages/functions/prod/src/function/netlify_function.ts b/packages/functions/prod/src/function/netlify_function.ts deleted file mode 100644 index fe0cd21..0000000 --- a/packages/functions/prod/src/function/netlify_function.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Context, Config } from './v2.js' -import type { - DeployBuildingHandler, - DeploySucceededHandler, - DeployFailedHandler, - DeployDeletedHandler, - DeployLockedHandler, - DeployUnlockedHandler, - UserLoginHandler, - UserSignupHandler, - UserValidateHandler, - UserModifiedHandler, - UserDeletedHandler, - FormSubmittedHandler, -} from '@netlify/types' - -type FetchHandler = (req: Request, context: Context) => Response | Promise -type BackgroundFetchHandler = (req: Request, context: Context) => void | Promise - -interface BaseNetlifyFunction { - deployBuilding?: DeployBuildingHandler - deploySucceeded?: DeploySucceededHandler - deployFailed?: DeployFailedHandler - deployDeleted?: DeployDeletedHandler - deployLocked?: DeployLockedHandler - deployUnlocked?: DeployUnlockedHandler - formSubmitted?: FormSubmittedHandler - userLogin?: UserLoginHandler - userSignup?: UserSignupHandler - userValidate?: UserValidateHandler - userModified?: UserModifiedHandler - userDeleted?: UserDeletedHandler -} - -// `config.background` discriminates between a regular `fetch` handler (must -// return `Response`) and a background one (response is discarded). -export type NetlifyFunction = - | (BaseNetlifyFunction & { - fetch?: FetchHandler - config?: Config & { background?: false } - }) - | (BaseNetlifyFunction & { - fetch?: BackgroundFetchHandler - config: Config & { background: true } - }) diff --git a/packages/functions/prod/src/function/v2.ts b/packages/functions/prod/src/function/v2.ts deleted file mode 100644 index 0821abd..0000000 --- a/packages/functions/prod/src/function/v2.ts +++ /dev/null @@ -1,131 +0,0 @@ -export type { Context } from '@netlify/types' - -import type { FunctionRegion } from '@netlify/types' - -type Path = `/${string}` -type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' -type CronSchedule = string -type RateLimitAggregator = 'domain' | 'ip' -type RateLimitAction = 'rate_limit' | 'rewrite' - -interface RateLimitConfig { - action?: RateLimitAction - aggregateBy?: RateLimitAggregator | RateLimitAggregator[] - to?: string - windowSize: number - windowLimit: number -} - -interface BaseConfig { - /** - * If `true`, the function runs in background (fire-and-forget) mode: the - * platform returns an immediate response to the client and the function's - * return value is discarded. - */ - background?: boolean - - /** - * Defines metadata about the framework or extension that has generated the - * function, if applicable. Typically contains the nane and the version. - * Should not be used for functions authored by users. - */ - generator?: string - - /** - * Limits the HTTP methods for which the function will run. If not set, the - * function will run for all supported methods. - */ - method?: HTTPMethod | HTTPMethod[] - - /** - * Configures the function to serve any static files that match the request - * URL and render the function only if no matching files exist. - */ - preferStatic?: boolean - - /** - * Set rate-limiting rules for this function. - * - * {@link} https://ntl.fyi/rate-limiting-code - */ - rateLimit?: RateLimitConfig - - /** - * Airport code for the region where the function should be deployed. - * - * @example - * 'iad' - */ - region?: FunctionRegion -} - -type MemoryOrVcpu = - | { - /** - * Maximum amount of memory (in MB) the function can use. Accepts either - * a number (e.g. `2048`) or a human-friendly string (e.g. `"2gb"`, - * `"1024mb"`). - * - * Mutually exclusive with `vcpu`. - */ - memory?: number | string - - vcpu?: never - } - | { - memory?: never - - /** - * Number of vCPUs the function should be provisioned with. Allowed - * range is 0.5–2. - * - * Mutually exclusive with `memory`. - */ - vcpu?: number - } - -interface ConfigWithPath extends BaseConfig { - /** - * One or more URL paths for which the function will not run, even if they - * match a path defined with the `path` property. Paths must begin with a - * forward slash. - * - * {@link} https://ntl.fyi/func-routing - */ - excludedPath?: Path | Path[] - - /** - * One or more URL paths for which the function will run. Paths must begin - * with a forward slash. - * - * {@link} https://ntl.fyi/func-routing - */ - path?: Path | Path[] - - /** - * The `schedule` property cannot be used when `path` is used. - */ - schedule?: never -} - -interface ConfigWithSchedule extends BaseConfig { - /** - * The `excludedPath` property cannot be used when `schedule` is used. - */ - excludedPath?: never - - /** - * The `path` property cannot be used when `schedule` is used. - */ - path?: never - - /** - * Cron expression representing the schedule at which the function will be - * automatically invoked. - * - * {@link} https://ntl.fyi/sched-func - */ - schedule: CronSchedule -} - -export type Config = (ConfigWithPath | ConfigWithSchedule) & MemoryOrVcpu diff --git a/packages/functions/prod/src/global-types.test.ts b/packages/functions/prod/src/global-types.test.ts deleted file mode 100644 index 4ec4295..0000000 --- a/packages/functions/prod/src/global-types.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, test, expectTypeOf } from 'vitest' -import type { NetlifyGlobal } from '@netlify/types' - -// Import the main module to ensure global augmentation is loaded -import './main.js' - -describe('Netlify global type declaration regression test', () => { - test('should augment global scope with `Netlify` global', () => { - expectTypeOf().toEqualTypeOf() - expectTypeOf().toHaveProperty('env') - expectTypeOf().toHaveProperty('context') - }) -}) diff --git a/packages/functions/prod/src/internal.ts b/packages/functions/prod/src/internal.ts deleted file mode 100644 index 14ce81c..0000000 --- a/packages/functions/prod/src/internal.ts +++ /dev/null @@ -1,5 +0,0 @@ -// this file is exported as @netlify/functions/internal, -// and only meant for consumption by Netlify Teams. -// While we try to adhere to semver, this file is not considered part of the public API. - -export { systemLogger, LogLevel } from './lib/system_logger.js' diff --git a/packages/functions/prod/src/lib/builder.test.ts b/packages/functions/prod/src/lib/builder.test.ts deleted file mode 100644 index ee224a3..0000000 --- a/packages/functions/prod/src/lib/builder.test.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { expect, test } from 'vitest' - -import { invokeLambda } from '../../test/helpers/main.mjs' -import { BaseHandler } from '../function/handler.js' -import { HandlerEvent } from '../main.js' - -import { builder } from './builder.js' - -const METADATA_OBJECT = { metadata: { version: 1, builder_function: true, ttl: 0 } } - -test('Injects the metadata object into an asynchronous handler', async () => { - const ttl = 3600 - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - ttl, - } - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - return originalResponse - } - const response = await invokeLambda(builder(myHandler)) - - expect(response).toStrictEqual({ ...originalResponse, metadata: { version: 1, builder_function: true, ttl } }) -}) - -test('Injects the metadata object into a synchronous handler', async () => { - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - } - const myHandler: BaseHandler = (event, context, callback) => { - callback?.(null, originalResponse) - } - const response = await invokeLambda(builder(myHandler)) - - expect(response).toStrictEqual({ ...originalResponse, ...METADATA_OBJECT }) -}) - -test('Injects the metadata object for non-200 responses', async () => { - const originalResponse = { - body: ':thumbsdown:', - statusCode: 404, - } - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - return originalResponse - } - const response = await invokeLambda(builder(myHandler)) - - expect(response).toStrictEqual({ ...originalResponse, ...METADATA_OBJECT }) -}) - -test('Returns a 405 error for requests using the POST method', async () => { - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - } - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - return originalResponse - } - const response = await invokeLambda(builder(myHandler), { method: 'POST' }) - - expect(response).toStrictEqual({ body: 'Method Not Allowed', statusCode: 405 }) -}) - -test('Returns a 405 error for requests using the PUT method', async () => { - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - } - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - return originalResponse - } - const response = await invokeLambda(builder(myHandler), { method: 'PUT' }) - - expect(response).toStrictEqual({ body: 'Method Not Allowed', statusCode: 405 }) -}) - -test('Returns a 405 error for requests using the DELETE method', async () => { - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - } - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - return originalResponse - } - const response = await invokeLambda(builder(myHandler), { method: 'DELETE' }) - - expect(response).toStrictEqual({ body: 'Method Not Allowed', statusCode: 405 }) -}) - -test('Returns a 405 error for requests using the PATCH method', async () => { - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - } - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - return originalResponse - } - const response = await invokeLambda(builder(myHandler), { method: 'PATCH' }) - - expect(response).toStrictEqual({ body: 'Method Not Allowed', statusCode: 405 }) -}) - -test('Preserves errors thrown inside the wrapped handler', async () => { - const error = new Error('Uh-oh!') - - // @ts-expect-error There's no type for this custom property. - error.someProperty = ':thumbsdown:' - - const myHandler = async () => { - const asyncTask = new Promise((resolve) => { - setTimeout(resolve, 0) - }) - - await asyncTask - - throw error - } - - try { - await invokeLambda(builder(myHandler)) - - throw new Error('Invocation should have failed') - } catch {} -}) - -test('Does not pass query parameters to the wrapped handler', async () => { - const originalResponse = { - body: ':thumbsup:', - statusCode: 200, - } - - const myHandler = async (event: HandlerEvent) => { - expect(event.multiValueQueryStringParameters).toStrictEqual({}) - expect(event.queryStringParameters).toStrictEqual({}) - - return originalResponse - } - const multiValueQueryStringParameters = { foo: ['bar'], bar: ['baz'] } - const queryStringParameters = { foo: 'bar', bar: 'baz' } - const response = await invokeLambda(builder(myHandler), { - // @ts-expect-error TODO: Fic types. - multiValueQueryStringParameters, - queryStringParameters, - }) - - expect(response).toStrictEqual({ ...originalResponse, ...METADATA_OBJECT }) -}) diff --git a/packages/functions/prod/src/lib/builder.ts b/packages/functions/prod/src/lib/builder.ts deleted file mode 100644 index 28d1f72..0000000 --- a/packages/functions/prod/src/lib/builder.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { BuilderHandler, Handler, HandlerCallback } from '../function/handler.js' -import { BuilderResponse } from '../function/handler_response.js' -import { HandlerContext, HandlerEvent } from '../function/index.js' - -import { BUILDER_FUNCTIONS_FLAG, HTTP_STATUS_METHOD_NOT_ALLOWED, METADATA_VERSION } from './consts.js' - -const augmentResponse = (response: BuilderResponse) => { - if (!response) { - return response - } - const metadata = { version: METADATA_VERSION, builder_function: BUILDER_FUNCTIONS_FLAG, ttl: response.ttl || 0 } - - return { - ...response, - metadata, - } -} - -const wrapHandler = - (handler: BuilderHandler): Handler => - (event: HandlerEvent, context: HandlerContext, callback?: HandlerCallback) => { - if (event.httpMethod !== 'GET' && event.httpMethod !== 'HEAD') { - return Promise.resolve({ - body: 'Method Not Allowed', - statusCode: HTTP_STATUS_METHOD_NOT_ALLOWED, - }) - } - - // Removing query string parameters from the builder function. - const modifiedEvent = { - ...event, - multiValueQueryStringParameters: {}, - queryStringParameters: {}, - } - - const wrappedCallback = (error: unknown, response: BuilderResponse) => - callback ? callback(error, augmentResponse(response)) : null - const execution = handler(modifiedEvent, context, wrappedCallback) - - if (typeof execution === 'object' && typeof execution.then === 'function') { - return execution.then(augmentResponse) - } - - return execution - } - -export { wrapHandler as builder } diff --git a/packages/functions/prod/src/lib/consts.test.ts b/packages/functions/prod/src/lib/consts.test.ts deleted file mode 100644 index 6a52df1..0000000 --- a/packages/functions/prod/src/lib/consts.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import { BACKGROUND_FUNCTION_TIMEOUT, SYNCHRONOUS_FUNCTION_TIMEOUT } from './consts.js' - -describe('Function timeout constants', () => { - test('exports correct timeout values', () => { - expect(SYNCHRONOUS_FUNCTION_TIMEOUT).toBe(30) - expect(BACKGROUND_FUNCTION_TIMEOUT).toBe(900) - }) -}) diff --git a/packages/functions/prod/src/lib/consts.ts b/packages/functions/prod/src/lib/consts.ts deleted file mode 100644 index aa62027..0000000 --- a/packages/functions/prod/src/lib/consts.ts +++ /dev/null @@ -1,23 +0,0 @@ -const BUILDER_FUNCTIONS_FLAG = true -const HTTP_STATUS_METHOD_NOT_ALLOWED = 405 -const HTTP_STATUS_OK = 200 -const METADATA_VERSION = 1 - -/** - * Default timeout for synchronous functions in seconds - */ -const SYNCHRONOUS_FUNCTION_TIMEOUT = 30 - -/** - * Default timeout for background functions in seconds - */ -const BACKGROUND_FUNCTION_TIMEOUT = 900 - -export { - BUILDER_FUNCTIONS_FLAG, - HTTP_STATUS_METHOD_NOT_ALLOWED, - HTTP_STATUS_OK, - METADATA_VERSION, - SYNCHRONOUS_FUNCTION_TIMEOUT, - BACKGROUND_FUNCTION_TIMEOUT, -} diff --git a/packages/functions/prod/src/lib/context_store.ts b/packages/functions/prod/src/lib/context_store.ts deleted file mode 100644 index 2477b0e..0000000 --- a/packages/functions/prod/src/lib/context_store.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AsyncLocalStorage } from 'node:async_hooks' - -import type { Context } from '@netlify/types' - -export interface ContextStoreContent { - context: Context -} - -// Registered via the global symbol registry so that other packages running in -// the same process (notably `@netlify/serverless-functions-api`) can resolve -// the exact same `AsyncLocalStorage` instance, regardless of how the modules -// were bundled or installed. -const STORE_KEY = Symbol.for('@netlify/functions/request-context-store') - -const getOrCreateStore = (): AsyncLocalStorage => { - const globalRef = globalThis as Record - const existing = globalRef[STORE_KEY] - - if (existing instanceof AsyncLocalStorage) { - return existing as AsyncLocalStorage - } - - const store = new AsyncLocalStorage() - globalRef[STORE_KEY] = store - - return store -} - -export const contextStore = getOrCreateStore() diff --git a/packages/functions/prod/src/lib/get_context.test.ts b/packages/functions/prod/src/lib/get_context.test.ts deleted file mode 100644 index 06554e1..0000000 --- a/packages/functions/prod/src/lib/get_context.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { describe, expect, test } from 'vitest' -import type { Context } from '@netlify/types' - -import { contextStore } from './context_store.js' -import { getContext } from './get_context.js' - -const mockContext = { requestId: 'test-request-123' } as unknown as Context - -describe('getContext', () => { - test('returns the context when called from within a request scope', () => { - contextStore.run({ context: mockContext }, () => { - expect(getContext()).toBe(mockContext) - }) - }) - - test('returns the context from a child async scope', async () => { - const childScope = async () => { - await Promise.resolve() - return getContext() - } - - const result = await contextStore.run({ context: mockContext }, childScope) - - expect(result).toBe(mockContext) - }) - - test('throws when called outside a request scope', () => { - expect(() => getContext()).toThrow(/only be called within a Netlify serverless function/) - }) -}) diff --git a/packages/functions/prod/src/lib/get_context.ts b/packages/functions/prod/src/lib/get_context.ts deleted file mode 100644 index 4c2451d..0000000 --- a/packages/functions/prod/src/lib/get_context.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Context } from '@netlify/types' - -import { contextStore } from './context_store.js' - -export const getContext = (): Context => { - const context = contextStore.getStore()?.context - - if (!context) { - throw new Error( - "getContext() can only be called within a Netlify serverless function's request handler or one of its async children.", - ) - } - - return context -} diff --git a/packages/functions/prod/src/lib/purge_cache.test.ts b/packages/functions/prod/src/lib/purge_cache.test.ts deleted file mode 100644 index 9eb8684..0000000 --- a/packages/functions/prod/src/lib/purge_cache.test.ts +++ /dev/null @@ -1,152 +0,0 @@ -import process from 'node:process' - -import semver from 'semver' -import { beforeEach, afterEach, expect, test } from 'vitest' - -import { invokeLambda } from '../../test/helpers/main.mjs' -import { MockFetch } from '../../test/helpers/mock_fetch.mjs' - -import { purgeCache } from './purge_cache.js' - -const globalFetch = globalThis.fetch -const hasFetchAPI = semver.gte(process.version, '18.0.0') - -beforeEach(() => { - delete process.env.NETLIFY_PURGE_API_TOKEN - delete process.env.SITE_ID - delete process.env.NETLIFY_LOCAL -}) - -afterEach(() => { - globalThis.fetch = globalFetch -}) - -test('Calls the purge API endpoint and returns `undefined` if the operation was successful', async () => { - if (!hasFetchAPI) { - console.warn('Skipping test requires the fetch API') - - return - } - - const mockSiteID = '123456789' - const mockToken = '1q2w3e4r5t6y7u8i9o0p' - - process.env.NETLIFY_PURGE_API_TOKEN = mockToken - process.env.SITE_ID = mockSiteID - - const mockAPI = new MockFetch().post({ - body: (payload: string) => { - const data = JSON.parse(payload) - - expect(data.site_id).toBe(mockSiteID) - }, - headers: { Authorization: `Bearer ${mockToken}` }, - method: 'post', - response: new Response(null, { status: 202 }), - url: `https://api.netlify.com/api/v1/purge`, - }) - const myFunction = async () => { - await purgeCache() - } - - globalThis.fetch = mockAPI.fetcher - - const response = await invokeLambda(myFunction) - - expect(response).toBeUndefined() - expect(mockAPI.fulfilled).toBeTruthy() -}) - -test('Throws if the API response does not have a successful status code', async () => { - if (!hasFetchAPI) { - console.warn('Skipping test requires the fetch API') - } - - const mockSiteID = '123456789' - const mockToken = '1q2w3e4r5t6y7u8i9o0p' - - process.env.NETLIFY_PURGE_API_TOKEN = mockToken - process.env.SITE_ID = mockSiteID - - const mockAPI = new MockFetch().post({ - body: (payload: string) => { - const data = JSON.parse(payload) - - expect(data.site_id).toBe(mockSiteID) - }, - headers: { Authorization: `Bearer ${mockToken}` }, - method: 'post', - response: new Response(null, { status: 500 }), - url: `https://api.netlify.com/api/v1/purge`, - }) - const myFunction = async () => { - await purgeCache() - } - - globalThis.fetch = mockAPI.fetcher - - await expect(invokeLambda(myFunction)).rejects.toThrow('Cache purge API call returned an unexpected status code: 500') -}) - -test('Ignores purgeCache if in local dev with no token or site', async () => { - if (!hasFetchAPI) { - console.warn('Skipping test requires the fetch API') - - return - } - - process.env.NETLIFY_LOCAL = '1' - - const mockAPI = new MockFetch().post({ - body: () => { - throw new Error('Unexpected request') - }, - }) - const myFunction = async () => { - await purgeCache() - } - - globalThis.fetch = mockAPI.fetcher - - const response = await invokeLambda(myFunction) - - expect(response).toBeUndefined() -}) - -test('Accepts a custom user-agent', async () => { - if (!hasFetchAPI) { - console.warn('Skipping test requires the fetch API') - - return - } - - const userAgent = 'Netlify' - const mockSiteID = '123456789' - const mockToken = '1q2w3e4r5t6y7u8i9o0p' - - process.env.NETLIFY_PURGE_API_TOKEN = mockToken - process.env.SITE_ID = mockSiteID - - const mockAPI = new MockFetch().post({ - body: (payload: string) => { - const data = JSON.parse(payload) - - expect(data.site_id).toBe(mockSiteID) - }, - headers: { Authorization: `Bearer ${mockToken}`, 'user-agent': userAgent }, - method: 'post', - response: new Response(null, { status: 202 }), - url: `https://api.netlify.com/api/v1/purge`, - }) - - const myFunction = async () => { - await purgeCache({ userAgent }) - } - - globalThis.fetch = mockAPI.fetcher - - const response = await invokeLambda(myFunction) - - expect(response).toBeUndefined() - expect(mockAPI.fulfilled).toBeTruthy() -}) diff --git a/packages/functions/prod/src/lib/purge_cache.ts b/packages/functions/prod/src/lib/purge_cache.ts deleted file mode 100644 index edfd699..0000000 --- a/packages/functions/prod/src/lib/purge_cache.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { env } from 'process' - -interface BasePurgeCacheOptions { - apiURL?: string - deployAlias?: string - tags?: string[] - token?: string - userAgent?: string -} - -interface PurgeCacheOptionsWithSiteID extends BasePurgeCacheOptions { - siteID?: string -} - -interface PurgeCacheOptionsWithSiteSlug extends BasePurgeCacheOptions { - siteSlug: string -} - -interface PurgeCacheOptionsWithDomain extends BasePurgeCacheOptions { - domain: string -} - -type PurgeCacheOptions = PurgeCacheOptionsWithSiteID | PurgeCacheOptionsWithSiteSlug | PurgeCacheOptionsWithDomain - -interface PurgeAPIPayload { - cache_tags?: string[] - deploy_alias?: string - domain?: string - site_id?: string - site_slug?: string -} - -export const purgeCache = async (options: PurgeCacheOptions = {}) => { - if (globalThis.fetch === undefined) { - throw new Error( - "`fetch` is not available. Please ensure you're using Node.js version 18.0.0 or above. Refer to https://ntl.fyi/functions-runtime for more information.", - ) - } - - const payload: PurgeAPIPayload = { - cache_tags: options.tags, - deploy_alias: options.deployAlias, - } - const token = env.NETLIFY_PURGE_API_TOKEN || options.token - - if (env.NETLIFY_LOCAL && !token) { - const scope = options.tags?.length ? ` for tags ${options.tags?.join(', ')}` : '' - console.log(`Skipping purgeCache${scope} in local development.`) - return - } - - if ('siteSlug' in options) { - payload.site_slug = options.siteSlug - } else if ('domain' in options) { - payload.domain = options.domain - } else { - // The `siteID` from `options` takes precedence over the one from the - // environment. - const siteID = options.siteID || env.SITE_ID - - if (!siteID) { - throw new Error( - 'The Netlify site ID was not found in the execution environment. Please supply it manually using the `siteID` property.', - ) - } - - payload.site_id = siteID - } - - if (!token) { - throw new Error( - 'The cache purge API token was not found in the execution environment. Please supply it manually using the `token` property.', - ) - } - - const headers: Record = { - 'Content-Type': 'application/json; charset=utf8', - Authorization: `Bearer ${token}`, - } - - if (options.userAgent) { - headers['user-agent'] = options.userAgent - } - - const apiURL = options.apiURL || 'https://api.netlify.com' - const response = await fetch(`${apiURL}/api/v1/purge`, { - method: 'POST', - headers, - body: JSON.stringify(payload), - }) - - if (!response.ok) { - throw new Error(`Cache purge API call returned an unexpected status code: ${response.status}`) - } -} diff --git a/packages/functions/prod/src/lib/schedule.ts b/packages/functions/prod/src/lib/schedule.ts deleted file mode 100644 index d3cfcfc..0000000 --- a/packages/functions/prod/src/lib/schedule.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Handler } from '../function/index.js' - -/** - * Declares a function to run on a cron schedule. - * Not reachable via HTTP. - * - * @example - * ``` - * export const handler = cron("5 4 * * *", async () => { - * // ... - * }) - * ``` - * - * @param schedule expressed as cron string. - * @param handler - * @see https://ntl.fyi/sched-func - */ -const schedule = (cron: string, handler: Handler): Handler => handler - -export { schedule } diff --git a/packages/functions/prod/src/lib/stream.ts b/packages/functions/prod/src/lib/stream.ts deleted file mode 100644 index d0680f8..0000000 --- a/packages/functions/prod/src/lib/stream.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { pipeline as pipelineSync } from 'node:stream' -import { promisify } from 'node:util' - -import type { Handler, HandlerEvent, HandlerContext, StreamingHandler, StreamingResponse } from '../function/index.js' - -// Node v14 doesn't have node:stream/promises -const pipeline = promisify(pipelineSync) - -// eslint-disable-next-line @typescript-eslint/no-namespace -declare namespace awslambda { - function streamifyResponse( - handler: (event: HandlerEvent, responseStream: NodeJS.WritableStream, context: HandlerContext) => Promise, - ): Handler - - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace HttpResponseStream { - function from(stream: NodeJS.WritableStream, metadata: Omit): NodeJS.WritableStream - } -} - -/** - * Enables streaming responses. `body` accepts a Node.js `Readable` stream or a WHATWG `ReadableStream`. - * - * @example - * ``` - * const { Readable } = require('stream'); - * - * export const handler = stream(async (event, context) => { - * const stream = Readable.from(Buffer.from(JSON.stringify(event))) - * return { - * statusCode: 200, - * body: stream, - * } - * }) - * ``` - * - * @example - * ``` - * export const handler = stream(async (event, context) => { - * const response = await fetch('https://api.openai.com/', { ... }) - * // ... - * return { - * statusCode: 200, - * body: response.body, // Web stream - * } - * }) - * ``` - * - * @param handler - * @see https://ntl.fyi/streaming-func - */ -const stream = (handler: StreamingHandler): Handler => - awslambda.streamifyResponse(async (event, responseStream, context) => { - const { body, ...httpResponseMetadata } = await handler(event, context) - - const responseBody = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata) - - if (typeof body === 'undefined') { - responseBody.end() - } else if (typeof body === 'string') { - responseBody.write(body) - responseBody.end() - } else { - await pipeline(body, responseBody) - } - }) - -export { stream } diff --git a/packages/functions/prod/src/lib/system_logger.test.ts b/packages/functions/prod/src/lib/system_logger.test.ts deleted file mode 100644 index b912a0f..0000000 --- a/packages/functions/prod/src/lib/system_logger.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import process from 'node:process' - -import { expect, test } from 'vitest' - -import { LogLevel, systemLogger } from '../internal.js' - -test('Log Level', () => { - const originalDebug = console.debug - - const debugLogs = [] - console.debug = (...message) => debugLogs.push(message) - - systemLogger.debug('hello!') - expect(debugLogs.length).toBe(0) - - systemLogger.withLogLevel(LogLevel.Debug).debug('hello!') - expect(debugLogs.length).toBe(1) - - systemLogger.withLogLevel(LogLevel.Log).debug('hello!') - expect(debugLogs.length).toBe(1) - - console.debug = originalDebug -}) - -test('Fields', () => { - const originalLog = console.log - const logs: string[][] = [] - console.log = (...message) => logs.push(message) - systemLogger.withError(new Error('boom')).withFields({ foo: 'bar' }).log('hello!') - expect(logs.length).toBe(1) - expect(logs[0][0]).toBe('__nfSystemLog') - const log = JSON.parse(logs[0][1]) - expect(log.msg).toBe('hello!') - expect(log.fields.foo).toBe('bar') - expect(log.fields.error).toBe('boom') - expect(log.fields.error_stack.split('\n').length > 2).toBe(true) - - console.log = originalLog -}) - -test('Local Dev', () => { - const originalLog = console.log - const logs = [] - console.log = (...message) => logs.push(message) - systemLogger.log('hello!') - expect(logs.length).toBe(1) - - process.env.NETLIFY_DEV = 'true' - systemLogger.log('hello!') - expect(logs.length).toBe(1) - - process.env.NETLIFY_ENABLE_SYSTEM_LOGGING = 'true' - systemLogger.log('hello!') - expect(logs.length).toBe(2) - - delete process.env.NETLIFY_DEV - delete process.env.NETLIFY_ENABLE_SYSTEM_LOGGING - console.log = originalLog -}) diff --git a/packages/functions/prod/src/lib/system_logger.ts b/packages/functions/prod/src/lib/system_logger.ts deleted file mode 100644 index 71f0ddf..0000000 --- a/packages/functions/prod/src/lib/system_logger.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { env } from 'process' - -const systemLogTag = '__nfSystemLog' - -const serializeError = (error: Error): Record => { - const cause = error?.cause instanceof Error ? serializeError(error.cause) : error.cause - - return { - error: error.message, - error_cause: cause, - error_stack: error.stack, - } -} - -// eslint pretends there's a different enum at the same place - it's wrong! - -export enum LogLevel { - Debug = 1, - Log, - Error, -} - -class SystemLogger { - private readonly fields: Record - private readonly logLevel: LogLevel - - constructor(fields: Record = {}, logLevel = LogLevel.Log) { - this.fields = fields - this.logLevel = logLevel - } - - private doLog(logger: typeof console.log, message: string) { - if (env.NETLIFY_DEV && !env.NETLIFY_ENABLE_SYSTEM_LOGGING) { - return - } - - logger(systemLogTag, JSON.stringify({ msg: message, fields: this.fields })) - } - - log(message: string) { - if (this.logLevel > LogLevel.Log) { - return - } - - this.doLog(console.log, message) - } - - debug(message: string) { - if (this.logLevel > LogLevel.Debug) { - return - } - - this.doLog(console.debug, message) - } - - error(message: string) { - if (this.logLevel > LogLevel.Error) { - return - } - - this.doLog(console.error, message) - } - - withLogLevel(level: LogLevel) { - return new SystemLogger(this.fields, level) - } - - withFields(fields: Record) { - return new SystemLogger( - { - ...this.fields, - ...fields, - }, - this.logLevel, - ) - } - - withError(error: unknown) { - const fields = error instanceof Error ? serializeError(error) : { error } - - return this.withFields(fields) - } -} - -export const systemLogger = new SystemLogger() diff --git a/packages/functions/prod/src/main.ts b/packages/functions/prod/src/main.ts deleted file mode 100644 index 8b7d1ee..0000000 --- a/packages/functions/prod/src/main.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { NetlifyGlobal } from '@netlify/types' - -declare global { - // Using `var` instead of `const` to allow TypeScript declaration merging. - // Multiple packages can declare the same global with `var`, but `const` cannot be redeclared. - var Netlify: NetlifyGlobal -} - -export { builder } from './lib/builder.js' -export { getContext } from './lib/get_context.js' -export { purgeCache } from './lib/purge_cache.js' -export { schedule } from './lib/schedule.js' -export { stream } from './lib/stream.js' -export { SYNCHRONOUS_FUNCTION_TIMEOUT, BACKGROUND_FUNCTION_TIMEOUT } from './lib/consts.js' -export * from './function/index.js' diff --git a/packages/functions/prod/test/helpers/main.mjs b/packages/functions/prod/test/helpers/main.mjs deleted file mode 100644 index 8979778..0000000 --- a/packages/functions/prod/test/helpers/main.mjs +++ /dev/null @@ -1,18 +0,0 @@ -export const invokeLambda = (handler, { method = 'GET', ...options } = {}) => { - const event = { - ...options, - httpMethod: method, - } - - return new Promise((resolve, reject) => { - const callback = (error, response) => { - if (error) { - reject(error) - } else { - resolve(response) - } - } - - resolve(handler(event, {}, callback)) - }) -} diff --git a/packages/functions/prod/test/helpers/mock_fetch.mjs b/packages/functions/prod/test/helpers/mock_fetch.mjs deleted file mode 100644 index 3b725d8..0000000 --- a/packages/functions/prod/test/helpers/mock_fetch.mjs +++ /dev/null @@ -1,73 +0,0 @@ -import assert from 'node:assert' - -export class MockFetch { - constructor() { - this.requests = [] - } - - addExpectedRequest({ body, headers = {}, method, response, url }) { - this.requests.push({ body, fulfilled: false, headers, method, response, url }) - - return this - } - - delete(options) { - return this.addExpectedRequest({ ...options, method: 'delete' }) - } - - get(options) { - return this.addExpectedRequest({ ...options, method: 'get' }) - } - - post(options) { - return this.addExpectedRequest({ ...options, method: 'post' }) - } - - put(options) { - return this.addExpectedRequest({ ...options, method: 'put' }) - } - - get fetcher() { - return async (...args) => { - const [url, options] = args - const headers = options?.headers - const urlString = url.toString() - const match = this.requests.find( - (request) => - request.method.toLowerCase() === options?.method.toLowerCase() && - request.url === urlString && - !request.fulfilled, - ) - - if (!match) { - throw new Error(`Unexpected fetch call: ${url}`) - } - - for (const key in match.headers) { - assert.equal(headers[key], match.headers[key]) - } - - if (typeof match.body === 'string') { - assert.equal(options?.body, match.body) - } else if (typeof match.body === 'function') { - const bodyFn = match.body - - bodyFn(options?.body) - } else { - assert.equal(options?.body, undefined) - } - - match.fulfilled = true - - if (match.response instanceof Error) { - throw match.response - } - - return match.response - } - } - - get fulfilled() { - return this.requests.every((request) => request.fulfilled) - } -} diff --git a/packages/functions/prod/test/types/BackgroundHandler.test-d.ts b/packages/functions/prod/test/types/BackgroundHandler.test-d.ts deleted file mode 100644 index e99e6ad..0000000 --- a/packages/functions/prod/test/types/BackgroundHandler.test-d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { expectType } from 'tsd' - -import { BackgroundHandler } from '../../src/main.js' - -// Ensure void is a valid return type in async handlers -const handler: BackgroundHandler = async () => { - // void -} - -expectType(handler) diff --git a/packages/functions/prod/test/types/Config.test-d.ts b/packages/functions/prod/test/types/Config.test-d.ts deleted file mode 100644 index aad714c..0000000 --- a/packages/functions/prod/test/types/Config.test-d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { expectAssignable, expectError } from 'tsd' - -import { Config } from '../../src/main.js' - -// `memory` alone is valid. -expectAssignable({ path: '/x', memory: 2048 }) -expectAssignable({ path: '/x', memory: '2gb' }) - -// `vcpu` alone is valid. -expectAssignable({ path: '/x', vcpu: 1.5 }) -expectAssignable({ schedule: '5 4 * * *', vcpu: 1 }) - -// Neither is valid (both are optional). -expectAssignable({ path: '/x' }) - -// `background` is a boolean toggle on the config. -expectAssignable({ path: '/x', background: true }) -expectAssignable({ path: '/x', background: false }) -expectAssignable({ path: '/x', background: true, vcpu: 1.5 }) - -// Setting both `memory` and `vcpu` is rejected. -expectError({ path: '/x', memory: 2048, vcpu: 1.5 }) -expectError({ schedule: '5 4 * * *', memory: '2gb', vcpu: 1 }) diff --git a/packages/functions/prod/test/types/Handler.test-d.ts b/packages/functions/prod/test/types/Handler.test-d.ts deleted file mode 100644 index ed84997..0000000 --- a/packages/functions/prod/test/types/Handler.test-d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { expectError } from 'tsd' - -import { Handler } from '../../src/main.js' - -// Ensure void is NOT a valid return type in async handlers -expectError(() => { - const handler: Handler = async () => { - // void - } -}) diff --git a/packages/functions/prod/test/types/NetlifyFunction.test-d.ts b/packages/functions/prod/test/types/NetlifyFunction.test-d.ts deleted file mode 100644 index 41061aa..0000000 --- a/packages/functions/prod/test/types/NetlifyFunction.test-d.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { expectAssignable, expectError } from 'tsd' - -import { NetlifyFunction } from '../../src/main.js' - -// Regular fetch: must return Response. -expectAssignable({ - fetch: () => new Response('hi'), - config: { path: '/hi' }, -}) - -// Regular fetch: returning void is rejected. -expectError({ - fetch: () => {}, - config: { path: '/hi' }, -}) - -// Background fetch: returning void is fine. -expectAssignable({ - fetch: () => {}, - config: { path: '/hi', background: true }, -}) - -// Background fetch: returning Response is rejected (strict Option A — the -// runtime discards the response, so a Response return type is misleading). -expectError({ - fetch: () => new Response('hi'), - config: { path: '/hi', background: true }, -}) - -// Async background fetch returning Promise is fine. -expectAssignable({ - fetch: async () => {}, - config: { path: '/hi', background: true }, -}) - -// `background: false` keeps the regular fetch contract. -expectAssignable({ - fetch: () => new Response('hi'), - config: { path: '/hi', background: false }, -}) - -// Function with no config still requires Response from fetch. -expectAssignable({ - fetch: () => new Response('hi'), -}) - -// Event handlers coexist with either variant. -expectAssignable({ - fetch: () => new Response('hi'), - deploySucceeded: () => {}, - config: { path: '/hi' }, -}) -expectAssignable({ - fetch: () => {}, - deploySucceeded: () => {}, - config: { path: '/hi', background: true }, -}) diff --git a/packages/functions/prod/test/types/Netlify_Global.test-d.ts b/packages/functions/prod/test/types/Netlify_Global.test-d.ts deleted file mode 100644 index ff4aa65..0000000 --- a/packages/functions/prod/test/types/Netlify_Global.test-d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { expectAssignable } from 'tsd' - -import '../../src/main.js' - -expectAssignable<{ env: unknown }>(Netlify) diff --git a/packages/functions/prod/tsconfig.json b/packages/functions/prod/tsconfig.json deleted file mode 100644 index c8b61a2..0000000 --- a/packages/functions/prod/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "esnext", - "rootDir": "./", - "outDir": "./dist", - "allowJs": true, - "declaration": true, - "esModuleInterop": true, - "sourceMap": false, - "removeComments": false, - "strict": true, - "moduleResolution": "node", - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/functions/prod/tsup.config.ts b/packages/functions/prod/tsup.config.ts deleted file mode 100644 index b99bff9..0000000 --- a/packages/functions/prod/tsup.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - entry: ['src/main.ts', 'src/internal.ts'], - outDir: 'dist', - format: ['cjs', 'esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, -}) diff --git a/packages/functions/prod/vitest.config.ts b/packages/functions/prod/vitest.config.ts deleted file mode 100644 index 1f197ac..0000000 --- a/packages/functions/prod/vitest.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - typecheck: { - enabled: true, - }, - }, -}) diff --git a/packages/headers/.gitignore b/packages/headers/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/headers/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/headers/CHANGELOG.md b/packages/headers/CHANGELOG.md deleted file mode 100644 index 176c82b..0000000 --- a/packages/headers/CHANGELOG.md +++ /dev/null @@ -1,254 +0,0 @@ -# Changelog - -## [2.1.11](https://github.com/netlify/primitives/compare/headers-v2.1.10...headers-v2.1.11) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.5 to ^4.4.6 - -## [2.1.10](https://github.com/netlify/primitives/compare/headers-v2.1.9...headers-v2.1.10) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.4 to ^4.4.5 - -## [2.1.9](https://github.com/netlify/primitives/compare/headers-v2.1.8...headers-v2.1.9) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.3 to ^4.4.4 - -## [2.1.8](https://github.com/netlify/primitives/compare/headers-v2.1.7...headers-v2.1.8) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.2 to ^4.4.3 - -## [2.1.7](https://github.com/netlify/primitives/compare/headers-v2.1.6...headers-v2.1.7) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.1 to ^4.4.2 - -## [2.1.6](https://github.com/netlify/primitives/compare/headers-v2.1.5...headers-v2.1.6) (2026-03-13) - - -### Bug Fixes - -* **deps:** update netlify packages ([#626](https://github.com/netlify/primitives/issues/626)) ([a87ba84](https://github.com/netlify/primitives/commit/a87ba84fa23c3a4ff506cd9c3d5f3b5cd78d9f3c)) - -## [2.1.5](https://github.com/netlify/primitives/compare/headers-v2.1.4...headers-v2.1.5) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.0 to ^4.4.1 - -## [2.1.4](https://github.com/netlify/primitives/compare/headers-v2.1.3...headers-v2.1.4) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.3 to ^4.4.0 - -## [2.1.3](https://github.com/netlify/primitives/compare/headers-v2.1.2...headers-v2.1.3) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.2 to ^4.3.3 - -## [2.1.2](https://github.com/netlify/primitives/compare/headers-v2.1.1...headers-v2.1.2) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.1 to ^4.3.2 - -## [2.1.1](https://github.com/netlify/primitives/compare/headers-v2.1.0...headers-v2.1.1) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.0 to ^4.3.1 - -## [2.1.0](https://github.com/netlify/primitives/compare/headers-v2.0.12...headers-v2.1.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.2.0 to ^4.3.0 - -## [2.0.12](https://github.com/netlify/primitives/compare/headers-v2.0.11...headers-v2.0.12) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.3 to ^4.2.0 - -## [2.0.11](https://github.com/netlify/primitives/compare/headers-v2.0.10...headers-v2.0.11) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.2 to ^4.1.3 - -## [2.0.10](https://github.com/netlify/primitives/compare/headers-v2.0.9...headers-v2.0.10) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.1 to ^4.1.2 - -## [2.0.9](https://github.com/netlify/primitives/compare/headers-v2.0.8...headers-v2.0.9) (2025-08-14) - - -### Bug Fixes - -* **deps:** update netlify packages ([#411](https://github.com/netlify/primitives/issues/411)) ([bad2dce](https://github.com/netlify/primitives/commit/bad2dceae8b5e5f56d947ce2332372d148819ccc)) - -## [2.0.8](https://github.com/netlify/primitives/compare/headers-v2.0.7...headers-v2.0.8) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.0 to ^4.1.1 - -## [2.0.7](https://github.com/netlify/primitives/compare/headers-v2.0.6...headers-v2.0.7) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.0.0 to ^4.1.0 - -## [2.0.6](https://github.com/netlify/primitives/compare/headers-v2.0.5...headers-v2.0.6) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.3.0 to ^4.0.0 - -## [2.0.5](https://github.com/netlify/primitives/compare/headers-v2.0.4...headers-v2.0.5) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.2 to ^3.3.0 - -## [2.0.4](https://github.com/netlify/primitives/compare/headers-v2.0.3...headers-v2.0.4) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.1 to ^3.2.2 - -## [2.0.3](https://github.com/netlify/primitives/compare/headers-v2.0.2...headers-v2.0.3) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.0 to ^3.2.1 - -## [2.0.2](https://github.com/netlify/primitives/compare/headers-v2.0.1...headers-v2.0.2) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.1.1 to ^3.2.0 - -## [2.0.1](https://github.com/netlify/primitives/compare/headers-v2.0.0...headers-v2.0.1) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.1.0 to ^3.1.1 - -## [2.0.0](https://github.com/netlify/primitives/compare/headers-v1.0.0...headers-v2.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Bug Fixes - -* **deps:** update netlify packages ([#236](https://github.com/netlify/primitives/issues/236)) ([630e675](https://github.com/netlify/primitives/commit/630e675822ece3d4bca58673b0a899f5a6c06bd9)) -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) -* improve static file handler ([#248](https://github.com/netlify/primitives/issues/248)) ([eb6c134](https://github.com/netlify/primitives/commit/eb6c134965a1653b3f3bebd9ec44df334589551e)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.0.0 to ^3.1.0 - -## 1.0.0 (2025-05-28) - - -### Features - -* add support for headers config ([#200](https://github.com/netlify/primitives/issues/200)) ([dca313e](https://github.com/netlify/primitives/commit/dca313ec82980231724a2d801bcc739df1d27924)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^2.2.0 to ^3.0.0 - -## Changelog diff --git a/packages/headers/package.json b/packages/headers/package.json deleted file mode 100644 index d374f51..0000000 --- a/packages/headers/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@netlify/headers", - "version": "2.1.11", - "description": "TypeScript implementation of Netlify's headers engine", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.js", - "exports": "./dist/main.js", - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "publint": "npx -y publint --strict", - "test": "vitest run", - "test:ci": "npm run build && vitest run", - "test:dev": "vitest" - }, - "keywords": [ - "netlify", - "headers" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/headers" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/node": "^20.17.57", - "tsup": "^8.0.0", - "vitest": "^3.1.4" - }, - "dependencies": { - "@netlify/headers-parser": "^9.0.3" - } -} diff --git a/packages/headers/src/lib/headersForPath.test.ts b/packages/headers/src/lib/headersForPath.test.ts deleted file mode 100644 index eae9a5c..0000000 --- a/packages/headers/src/lib/headersForPath.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import path from 'node:path' - -import { expect, it } from 'vitest' -import { Fixture } from '@netlify/dev-utils' - -import { parseHeaders } from './parseHeaders.js' -import { headersForPath } from './headersForPath.js' - -const headers = [ - { path: '/', headers: ['X-Frame-Options: SAMEORIGIN'] }, - { path: '/*', headers: ['X-Frame-Thing: SAMEORIGIN'] }, - { - path: '/static-path/*', - headers: [ - 'X-Frame-Options: DENY', - 'X-XSS-Protection: 1; mode=block', - 'cache-control: max-age=0', - 'cache-control: no-cache', - 'cache-control: no-store', - 'cache-control: must-revalidate', - ], - }, - { path: '/:placeholder/index.html', headers: ['X-Frame-Options: SAMEORIGIN'] }, - /** - * Do not force * to appear at end of path. - * - * @see https://github.com/netlify/next-on-netlify/issues/151 - * @see https://github.com/netlify/cli/issues/1148 - */ - { - path: '/*/_next/static/chunks/*', - headers: ['cache-control: public', 'cache-control: max-age=31536000', 'cache-control: immutable'], - }, - { - path: '/directory/*/test.html', - headers: ['X-Frame-Options: test'], - }, - { - path: '/with-colon', - headers: ['Custom-header: http://www.example.com'], - }, -] - -it('returns headers matching given header rules', async () => { - const fixture = new Fixture().withHeadersFile({ headers }) - const directory = await fixture.create() - - const headersFile = path.resolve(directory, '_headers') - const rules = await parseHeaders({ configHeaders: [], headersFiles: [headersFile] }) - - expect(headersForPath(rules, '/')).toEqual({ - 'X-Frame-Options': 'SAMEORIGIN', - 'X-Frame-Thing': 'SAMEORIGIN', - }) - expect(headersForPath(rules, '/placeholder')).toEqual({ - 'X-Frame-Thing': 'SAMEORIGIN', - }) - expect(headersForPath(rules, '/static-path/placeholder')).toEqual({ - 'X-Frame-Thing': 'SAMEORIGIN', - 'X-Frame-Options': 'DENY', - 'X-XSS-Protection': '1; mode=block', - 'cache-control': 'max-age=0, no-cache, no-store, must-revalidate', - }) - expect(headersForPath(rules, '/static-path')).toEqual({ - 'X-Frame-Thing': 'SAMEORIGIN', - 'X-Frame-Options': 'DENY', - 'X-XSS-Protection': '1; mode=block', - 'cache-control': 'max-age=0, no-cache, no-store, must-revalidate', - }) - expect(headersForPath(rules, '/placeholder/index.html')).toEqual({ - 'X-Frame-Options': 'SAMEORIGIN', - 'X-Frame-Thing': 'SAMEORIGIN', - }) - expect(headersForPath(rules, '/placeholder/_next/static/chunks/placeholder')).toEqual({ - 'X-Frame-Thing': 'SAMEORIGIN', - 'cache-control': 'public, max-age=31536000, immutable', - }) - expect(headersForPath(rules, '/directory/placeholder/test.html')).toEqual({ - 'X-Frame-Thing': 'SAMEORIGIN', - 'X-Frame-Options': 'test', - }) - - await fixture.destroy() -}) diff --git a/packages/headers/src/lib/headersForPath.ts b/packages/headers/src/lib/headersForPath.ts deleted file mode 100644 index b40c2d5..0000000 --- a/packages/headers/src/lib/headersForPath.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { type Header } from '@netlify/headers-parser' - -/** - * Get the matching headers for `path` given a set of header rules. - */ -export const headersForPath = function (headerRules: Header[], path: string) { - const matchingHeaderRules = headerRules.filter(({ forRegExp }) => forRegExp.test(path)).map(({ values }) => values) - // Return as a single flat object for simplicity - return matchingHeaderRules.reduce((acc, val) => ({ ...acc, ...val }), {}) -} diff --git a/packages/headers/src/lib/parseHeaders.test.ts b/packages/headers/src/lib/parseHeaders.test.ts deleted file mode 100644 index 7586847..0000000 --- a/packages/headers/src/lib/parseHeaders.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -import path from 'node:path' - -import { expect, it, vi } from 'vitest' -import { Fixture, createMockLogger } from '@netlify/dev-utils' - -import { parseHeaders } from './parseHeaders.js' - -const headers = [ - { path: '/', headers: ['X-Frame-Options: SAMEORIGIN'] }, - { path: '/*', headers: ['X-Frame-Thing: SAMEORIGIN'] }, - { - path: '/static-path/*', - headers: [ - 'X-Frame-Options: DENY', - 'X-XSS-Protection: 1; mode=block', - 'cache-control: max-age=0', - 'cache-control: no-cache', - 'cache-control: no-store', - 'cache-control: must-revalidate', - ], - }, - { path: '/:placeholder/index.html', headers: ['X-Frame-Options: SAMEORIGIN'] }, - { - path: '/directory/*/test.html', - headers: ['X-Frame-Options: test'], - }, - { - path: '/with-colon', - headers: ['Custom-header: http://www.example.com'], - }, -] - -it('allows valid syntax', async () => { - const fixture = new Fixture().withHeadersFile({ headers }) - const directory = await fixture.create() - - const headersFile = path.resolve(directory, '_headers') - const logger = { ...createMockLogger(), error: vi.fn() } - await expect(parseHeaders({ configHeaders: [], headersFiles: [headersFile], logger })).resolves.not.toThrowError() - - expect(logger.error).not.toHaveBeenCalled() - - await fixture.destroy() -}) - -it('logs an error without throwing on invalid syntax', async () => { - const fixture = new Fixture().withFile( - '_invalid_headers', - ` -/ -# This is valid -X-Frame-Options: SAMEORIGIN -# This is not valid -X-Frame-Thing: -`, - ) - const directory = await fixture.create() - - const invalidHeadersFile = path.resolve(directory, '_invalid_headers') - const logger = { ...createMockLogger(), error: vi.fn() } - await expect( - parseHeaders({ configHeaders: [], headersFiles: [invalidHeadersFile], logger }), - ).resolves.not.toThrowError() - - expect(logger.error).toHaveBeenCalledExactlyOnceWith(`Headers syntax errors: -Could not parse header line 6: - X-Frame-Thing: -Missing header value`) - - await fixture.destroy() -}) - -it('parses header rules', async () => { - const fixture = new Fixture().withHeadersFile({ headers }) - const directory = await fixture.create() - - const headersFile = path.resolve(directory, '_headers') - const logger = createMockLogger() - const rules = await parseHeaders({ configHeaders: [], headersFiles: [headersFile], logger }) - - const normalizedHeaders = rules.map(({ for: path, values }) => ({ for: path, values })) - expect(normalizedHeaders).toEqual([ - { - for: '/', - values: { - 'X-Frame-Options': 'SAMEORIGIN', - }, - }, - { - for: '/*', - values: { - 'X-Frame-Thing': 'SAMEORIGIN', - }, - }, - { - for: '/static-path/*', - values: { - 'X-Frame-Options': 'DENY', - 'X-XSS-Protection': '1; mode=block', - 'cache-control': 'max-age=0, no-cache, no-store, must-revalidate', - }, - }, - { - for: '/:placeholder/index.html', - values: { - 'X-Frame-Options': 'SAMEORIGIN', - }, - }, - { - for: '/directory/*/test.html', - values: { - 'X-Frame-Options': 'test', - }, - }, - { - for: '/with-colon', - values: { - 'Custom-header': 'http://www.example.com', - }, - }, - ]) - - await fixture.destroy() -}) diff --git a/packages/headers/src/lib/parseHeaders.ts b/packages/headers/src/lib/parseHeaders.ts deleted file mode 100644 index b929d7f..0000000 --- a/packages/headers/src/lib/parseHeaders.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Logger } from '@netlify/dev-utils' -import { type Header, type MinimalHeader as ConfigHeader, parseAllHeaders } from '@netlify/headers-parser' - -export type { ConfigHeader, Header } - -export const parseHeaders = async function ({ - configHeaders, - configPath, - headersFiles, - logger, -}: { - configHeaders?: ConfigHeader[] | undefined - configPath?: string | undefined - headersFiles?: string[] | undefined - logger: Logger -}): Promise { - const { errors, headers } = await parseAllHeaders({ - headersFiles, - netlifyConfigPath: configPath, - minimal: false, - configHeaders: configHeaders ?? [], - }) - handleHeadersErrors(errors, logger) - // TODO(serhalp): Make `parseAllHeaders()` smart enough to conditionally return a refined type based on `minimal` - return headers as Header[] -} - -const handleHeadersErrors = function (errors: Error[], logger: Logger) { - if (errors.length === 0) { - return - } - - const errorMessage = errors.map(({ message }) => message).join('\n\n') - logger.error(`Headers syntax errors:\n${errorMessage}`) -} diff --git a/packages/headers/src/main.test.ts b/packages/headers/src/main.test.ts deleted file mode 100644 index d0cbe5b..0000000 --- a/packages/headers/src/main.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import path from 'node:path' - -import { describe, expect, test } from 'vitest' -import { Fixture } from '@netlify/dev-utils' - -import { HeadersHandler } from './main.js' - -describe('constructor', () => { - test('de-duplicates `headersFiles` when project and publish directories resolve to the same path', async () => { - const fixture = new Fixture().withHeadersFile({ - headers: [{ path: '/test-*', headers: ['foo: bar'] }], - }) - const projectDir = await fixture.create() - - const handler = new HeadersHandler({ - logger: console, - projectDir, - publishDir: '.', // resolves to the same path as `projectDir` - configHeaders: [{ for: '/test-*', values: { 'X-Config-Header': 'config-value' } }], - }) - - expect(handler.headersFiles).toEqual([path.resolve(projectDir, '_headers')]) - - await fixture.destroy() - }) -}) - -describe('apply', () => { - test('sets response headers matching rules in provided `configHeaders`', async () => { - const fixture = new Fixture() - const projectDir = await fixture.create() - - const handler = new HeadersHandler({ - logger: console, - projectDir, - configHeaders: [{ for: '/test-*', values: { 'X-Config-Header': 'config-value' } }], - }) - const request = new Request('http://example.com/test-path') - const response = new Response(null, { - headers: { - 'Existing-Header': 'existing-value', - }, - }) - const result = await handler.apply(request, response) - - expect(result).toStrictEqual({ 'X-Config-Header': 'config-value' }) - expect(response.headers.get('X-Config-Header')).toBe('config-value') - expect(response.headers.get('Existing-Header')).toBe('existing-value') - - await fixture.destroy() - }) - - test('sets response headers matching rules from `_headers` file in project dir', async () => { - const fixture = new Fixture().withHeadersFile({ - headers: [{ path: '/test-*', headers: ['X-Project-Dir-Header: project-dir-value'] }], - }) - const projectDir = await fixture.create() - const handler = new HeadersHandler({ - logger: console, - projectDir, - configHeaders: undefined, - }) - - const request = new Request('http://example.com/test-path') - const response = new Response(null, { - headers: { - 'Existing-Header': 'existing-value', - }, - }) - const result = await handler.apply(request, response) - - expect(result).toStrictEqual({ 'X-Project-Dir-Header': 'project-dir-value' }) - expect(response.headers.get('X-Project-Dir-Header')).toBe('project-dir-value') - expect(response.headers.get('Existing-Header')).toBe('existing-value') - - await fixture.destroy() - }) - - test('sets response headers matching rules from `_headers` file in publish dir', async () => { - const fixture = new Fixture().withHeadersFile({ - pathPrefix: '/my-dist', - headers: [{ path: '/test-*', headers: ['X-Publish-Dir-Header: publish-dir-value'] }], - }) - const projectDir = await fixture.create() - - const handler = new HeadersHandler({ - logger: console, - projectDir, - publishDir: 'my-dist', - configHeaders: undefined, - }) - const request = new Request('http://example.com/test-path') - const response = new Response(null, { - headers: { - 'Existing-Header': 'existing-value', - }, - }) - const result = await handler.apply(request, response) - - expect(result).toStrictEqual({ 'X-Publish-Dir-Header': 'publish-dir-value' }) - expect(response.headers.get('X-Publish-Dir-Header')).toBe('publish-dir-value') - expect(response.headers.get('Existing-Header')).toBe('existing-value') - - await fixture.destroy() - }) - - test('sets response headers matching rules in multiple sources', async () => { - const fixture = new Fixture() - .withHeadersFile({ - headers: [{ path: '/test-*', headers: ['X-Project-Dir-Header: project-dir-value'] }], - }) - .withHeadersFile({ - pathPrefix: '/my-dist', - headers: [{ path: '/test-p*', headers: ['X-Publish-Dir-Header: publish-dir-value'] }], - }) - const projectDir = await fixture.create() - const handler = new HeadersHandler({ - logger: console, - projectDir, - publishDir: 'my-dist', - configHeaders: [{ for: '/test-pa*', values: { 'X-Config-Header': 'config-value' } }], - }) - - const request = new Request('http://example.com/test-path') - const response = new Response(null, { - headers: { - 'Existing-Header': 'existing-value', - }, - }) - const expected = { - 'X-Project-Dir-Header': 'project-dir-value', - 'X-Publish-Dir-Header': 'publish-dir-value', - 'X-Config-Header': 'config-value', - } - const collected: Record = {} - const result = await handler.apply(request, response, (key, value) => { - collected[key] = value - }) - - expect(result).toStrictEqual(expected) - expect(collected).toStrictEqual(expected) - expect(response.headers.get('X-Project-Dir-Header')).toBe('project-dir-value') - expect(response.headers.get('X-Publish-Dir-Header')).toBe('publish-dir-value') - expect(response.headers.get('X-Config-Header')).toBe('config-value') - expect(response.headers.get('Existing-Header')).toBe('existing-value') - - await fixture.destroy() - }) - - test('leaves response intact when no header rules match', async () => { - const fixture = new Fixture().withHeadersFile({ - headers: [{ path: '/no-match', headers: ['X-Project-Dir-Header: no-match-value'] }], - }) - const projectDir = await fixture.create() - const handler = new HeadersHandler({ - logger: console, - projectDir, - configHeaders: [{ for: '/no-match', values: { 'X-Config-Header': 'no-match-value' } }], - }) - - const request = new Request('http://example.com/test-path') - const response = new Response(null, { - headers: { - 'Existing-Header': 'existing-value', - }, - }) - const originalHeaders = new Headers(response.headers) - const result = await handler.apply(request, response) - - expect(result).toStrictEqual({}) - expect(response.headers).toEqual(originalHeaders) - - await fixture.destroy() - }) -}) diff --git a/packages/headers/src/main.ts b/packages/headers/src/main.ts deleted file mode 100644 index 025059b..0000000 --- a/packages/headers/src/main.ts +++ /dev/null @@ -1,67 +0,0 @@ -import path from 'node:path' - -import type { Logger } from '@netlify/dev-utils' - -import { type ConfigHeader, parseHeaders } from './lib/parseHeaders.js' -import { headersForPath } from './lib/headersForPath.js' - -const HEADERS_FILE_NAME = '_headers' - -export type HeadersCollector = (key: string, value: string) => void - -interface HeadersHandlerOptions { - configPath?: string | undefined - configHeaders?: ConfigHeader[] | undefined - /** - * Base directory of the project. This can be absolute or relative - * to the current working directory. - */ - projectDir: string - /** - * Publish directory of the project, relative to the `projectDir`. - */ - publishDir?: string | undefined - logger: Logger -} - -export class HeadersHandler { - #configHeaders: ConfigHeader[] | undefined - #configPath: string | undefined - #headersFiles: string[] - #logger: Logger - - constructor({ configPath, configHeaders, projectDir, publishDir, logger }: HeadersHandlerOptions) { - this.#configHeaders = configHeaders - this.#configPath = configPath - this.#logger = logger - // Project dir is resolved relative to cwd - const projectDirHeadersFile = path.resolve(projectDir, HEADERS_FILE_NAME) - // Publish dir is resolved relative to project dir - const publishDirHeadersFile = publishDir ? path.resolve(projectDir, publishDir, HEADERS_FILE_NAME) : undefined - this.#headersFiles = [ - ...new Set([projectDirHeadersFile, ...(publishDirHeadersFile ? [publishDirHeadersFile] : [])]), - ] - } - - get headersFiles() { - return this.#headersFiles - } - - async apply(request: Request, response?: Response, collector?: HeadersCollector) { - const headerRules = await parseHeaders({ - headersFiles: this.#headersFiles, - configPath: this.#configPath, - configHeaders: this.#configHeaders, - logger: this.#logger, - }) - const matchingHeaderRules = headersForPath(headerRules, new URL(request.url).pathname) - - for (const [key, value] of Object.entries(matchingHeaderRules)) { - response?.headers.set(key, value) - - collector?.(key, value) - } - - return matchingHeaderRules - } -} diff --git a/packages/headers/tsconfig.json b/packages/headers/tsconfig.json deleted file mode 100644 index 7b592ea..0000000 --- a/packages/headers/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/headers/tsup.config.ts b/packages/headers/tsup.config.ts deleted file mode 100644 index 9a08857..0000000 --- a/packages/headers/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['esm'], - entry: ['src/main.ts'], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/identity/.gitignore b/packages/identity/.gitignore deleted file mode 100644 index 1eae0cf..0000000 --- a/packages/identity/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist/ -node_modules/ diff --git a/packages/identity/prod/.gitignore b/packages/identity/prod/.gitignore deleted file mode 100644 index 6a5f751..0000000 --- a/packages/identity/prod/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -*~ -*.swp -npm-debug.log -node_modules -/core -.eslintcache -.npmrc -.yarn-error.log -/coverage -/build -.vscode -/dist diff --git a/packages/identity/prod/CHANGELOG.md b/packages/identity/prod/CHANGELOG.md deleted file mode 100644 index 3863b7b..0000000 --- a/packages/identity/prod/CHANGELOG.md +++ /dev/null @@ -1,13 +0,0 @@ -# Changelog - -## [1.2.0](https://github.com/netlify/primitives/compare/identity-v1.1.0...identity-v1.2.0) (2026-05-18) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Bug Fixes - -* try a little release ([#691](https://github.com/netlify/primitives/issues/691)) ([0e124f1](https://github.com/netlify/primitives/commit/0e124f10f7445c1d13c23d7aa6ef2408393a5e00)) diff --git a/packages/identity/prod/README.md b/packages/identity/prod/README.md deleted file mode 100644 index f0bb980..0000000 --- a/packages/identity/prod/README.md +++ /dev/null @@ -1,1261 +0,0 @@ -# @netlify/identity - -A lightweight, no-config headless authentication library for projects using Netlify Identity. Works in both browser and -server contexts. This is NOT the Netlify Identity Widget. This library exports standalone async functions (e.g., import -{ login, getUser } from '@netlify/identity'). There is no class to instantiate and no .init() call. Just import the -functions you need and call them. - -**Prerequisites:** - -- [Netlify Identity](https://docs.netlify.com/security/secure-access-to-sites/identity/) must be enabled on your Netlify - project. This happens automatically when running within a - [Netlify Agent Runner](https://docs.netlify.com/agent-runner/overview/) -- **Server-side** functions (`getUser`, `login`, `admin.*`, etc.) require - [Netlify Functions](https://docs.netlify.com/build/functions/get-started/) (modern/v2, with `export default`) or - [Edge Functions](https://docs.netlify.com/edge-functions/overview/). - [Lambda-compatible functions](https://docs.netlify.com/build/functions/lambda-compatibility/) (v1, with - `export { handler }`) are **not supported** -- For local development, use [`netlify dev`](https://docs.netlify.com/cli/local-development/) so the Identity endpoint - is available - -## How this library relates to other Netlify auth packages - -`@netlify/identity` is the recommended library for all new projects. It works in both browser and server contexts, -handles cookie management, and normalizes the user object. - -You may encounter two older packages in existing code or documentation: - -| Package | Status | What it was | -| ------------------------------------------------------------------------------- | -------------------------------- | --------------------------------------------- | -| [`netlify-identity-widget`](https://github.com/netlify/netlify-identity-widget) | Not recommended for new projects | Pre-built login/signup modal with built-in UI | -| [`gotrue-js`](https://github.com/netlify/gotrue-js) | Not recommended for new projects | Low-level GoTrue HTTP client (browser only) | - -If you need a pre-built login UI, the widget still works. For everything else (custom UI, server-side auth, admin -operations, framework integration), use `@netlify/identity`. - -## Table of contents - -- [Installation](#installation) -- [Quick start](#quick-start) -- [API](#api) - - [Functions](#functions) -- `getUser`, `login`, `signup`, `logout`, `oauthLogin`, `handleAuthCallback`, - `onAuthChange`, `hydrateSession`, `refreshSession`, `verifyRequestOrigin`, and more - - [Admin Operations](#admin-operations) -- `admin.listUsers`, `admin.getUser`, `admin.createUser`, `admin.updateUser`, - `admin.deleteUser` - - [Types](#types) -- `User`, `AuthEvent`, `CallbackResult`, `Settings`, `Admin`, `ListUsersOptions`, - `CreateUserParams`, `VerifyRequestOriginOptions`, etc. - - [Errors](#errors) -- `AuthError`, `MissingIdentityError` -- [Security: CSRF protection](#security-csrf-protection) -- [Framework integration](#framework-integration) -- Next.js, Remix, TanStack Start, Astro, SvelteKit -- [Guides](#guides) - - [React `useAuth` hook](#react-useauth-hook) - - [Listening for auth changes](#listening-for-auth-changes) - - [OAuth login](#oauth-login) - - [Password recovery](#password-recovery) - - [Invite acceptance](#invite-acceptance) - - [Session lifetime](#session-lifetime) - - [Caching and authenticated content](#caching-and-authenticated-content) - -## Installation - -```bash -npm install @netlify/identity -``` - -## Quick start - -### Log in (browser) - -```ts -import { login, getUser } from '@netlify/identity' - -// Log in -const user = await login('jane@example.com', 'password123') -console.log(`Hello, ${user.name}`) - -// Later, check auth state -const currentUser = await getUser() -``` - -### Protect a Netlify Function - -```ts -import { getUser } from '@netlify/identity' -import type { Context } from '@netlify/functions' - -export default async (req: Request, context: Context) => { - const user = await getUser() - if (!user) return new Response('Unauthorized', { status: 401 }) - return Response.json({ id: user.id, email: user.email }) -} -``` - -### Protect an Edge Function - -```ts -import { getUser } from '@netlify/identity' -import type { Context } from '@netlify/edge-functions' - -export default async (req: Request, context: Context) => { - const user = await getUser() - if (!user) return new Response('Unauthorized', { status: 401 }) - return Response.json({ id: user.id, email: user.email }) -} -``` - -## API - -### Functions - -#### `getUser` - -```ts -getUser(): Promise -``` - -Returns the current authenticated user, or `null` if not logged in. Returns the best available normalized `User` from -the current context. When the Identity API is reachable, most persisted and profile fields are populated, but -state-dependent fields (invite, recovery, email-change) may still be `undefined` if the user is not in that state. When -falling back to JWT claims (e.g., Identity API unreachable), only `id`, `email`, `provider`, `name`, `pictureUrl`, -`roles`, `userMetadata`, and `appMetadata` are available. Never throws. - -> **Next.js note:** Calling `getUser()` in a Server Component opts the page into -> [dynamic rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#dynamic-rendering) -> because it reads cookies. This is expected and correct for authenticated pages. Next.js handles the internal dynamic -> rendering signal automatically. - -#### `isAuthenticated` - -```ts -isAuthenticated(): Promise -``` - -Returns `true` if a user is currently authenticated. Equivalent to `(await getUser()) !== null`. Never throws. - -#### `getIdentityConfig` - -```ts -getIdentityConfig(): IdentityConfig | null -``` - -Returns the Identity endpoint URL (and operator token on the server), or `null` if Identity is not available. Never -throws. - -#### `getSettings` - -```ts -getSettings(): Promise -``` - -Fetches your project's Identity settings (enabled providers, autoconfirm, signup disabled). - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if the endpoint is unreachable. - -#### `login` - -```ts -login(email: string, password: string): Promise -``` - -Logs in with email and password. Works in both browser and server contexts. - -In the browser, emits a `'login'` event. On the server (Netlify Functions, Edge Functions), calls the Identity API -directly and sets the `nf_jwt` cookie via the Netlify runtime. - -**Throws:** `AuthError` on invalid credentials or network failure. In the browser, `MissingIdentityError` if Identity is -not configured. On the server, `AuthError` if the Netlify Functions runtime is not available. - -#### `signup` - -```ts -signup(email: string, password: string, data?: SignupData): Promise -``` - -Creates a new account. Works in both browser and server contexts. - -If autoconfirm is enabled in your Identity settings, the user is logged in immediately: cookies are set and a `'login'` -event is emitted. If autoconfirm is **disabled** (the default), the user receives a confirmation email and must click -the link before they can log in. In that case, no cookies are set and no auth event is emitted. - -The optional `data` parameter sets user metadata (e.g., `{ full_name: 'Jane Doe' }`), stored in the user's -`user_metadata` field. - -**Throws:** `AuthError` on failure (e.g., email already registered, signup disabled). In the browser, -`MissingIdentityError` if Identity is not configured. On the server, `AuthError` if the Netlify Functions runtime is not -available. - -#### `logout` - -```ts -logout(): Promise -``` - -Logs out the current user and clears the session. Works in both browser and server contexts. - -In the browser, emits a `'logout'` event. On the server, calls the Identity `/logout` endpoint with the JWT from the -`nf_jwt` cookie, then deletes the cookie. Auth cookies are always cleared, even if the server call fails. - -**Throws:** In the browser, `MissingIdentityError` if Identity is not configured. On the server, `AuthError` if the -Netlify Functions runtime is not available. - -#### `oauthLogin` - -```ts -oauthLogin(provider: string): never -``` - -Redirects to an OAuth provider. The page navigates away, so this function never returns normally. Browser only. - -The `provider` argument should be one of the `AuthProvider` values: `'google'`, `'github'`, `'gitlab'`, `'bitbucket'`, -or `'facebook'`. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if called on the server. - -#### `handleAuthCallback` - -```ts -handleAuthCallback(): Promise -``` - -Processes the URL hash after an OAuth redirect, email confirmation, password recovery, invite acceptance, or email -change. Call on page load. Returns `null` if the hash contains no auth parameters. Browser only. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if token exchange fails. - -#### `onAuthChange` - -```ts -onAuthChange(callback: AuthCallback): () => void -``` - -Subscribes to auth state changes (login, logout, token refresh, user updates, and recovery). Returns an unsubscribe -function. Also fires on cross-tab session changes. No-op on the server. The `'recovery'` event fires when -`handleAuthCallback()` processes a password recovery token; listen for it to redirect users to a password reset form. - -#### `hydrateSession` - -```ts -hydrateSession(): Promise -``` - -Bootstraps the browser-side session from server-set auth cookies (`nf_jwt`, `nf_refresh`). Returns the hydrated `User`, -or `null` if no auth cookies are present. No-op on the server. - -**When to use:** After a server-side login (e.g., via a Netlify Function or Server Action), the `nf_jwt` cookie is set -but no browser session exists yet. `getUser()` calls `hydrateSession()` automatically, but account operations like -`updateUser()` or `verifyEmailChange()` require a live browser session. Call `hydrateSession()` explicitly if you need -the session ready before calling those operations. - -If a browser session already exists (e.g., from a browser-side login), this is a no-op and returns the existing user. - -```ts -import { hydrateSession, updateUser } from '@netlify/identity' - -// On page load, hydrate the session from server-set cookies -await hydrateSession() - -// Now browser account operations work -await updateUser({ data: { full_name: 'Jane Doe' } }) -``` - -#### `refreshSession` - -```ts -refreshSession(): Promise -``` - -Refreshes an expired or near-expired session. Returns the new access token on success, or `null` if no refresh is needed -or the refresh token is invalid/missing. - -**Browser:** Checks if the current access token is near expiry and refreshes it if needed, syncing the new token to the -`nf_jwt` cookie. Note: the library automatically refreshes tokens in the background after any browser flow that -establishes a session (`login()`, `signup()`, `hydrateSession()`, `handleAuthCallback()`, `confirmEmail()`, -`recoverPassword()`, `acceptInvite()`), so you typically don't need to call this manually. `getUser()` also restarts the -refresh timer when it finds an existing session. Browser-side errors return `null`, not an `AuthError`. - -**Server:** Reads the `nf_jwt` and `nf_refresh` cookies. If the access token is expired or within 60 seconds of expiry, -exchanges the refresh token for a new access token via the Identity `/token` endpoint and updates both cookies on the -response. Call this in framework middleware or at the start of server-side request handlers to ensure the JWT is valid -for downstream processing. - -**Throws:** `AuthError` on network failure or if the Identity endpoint URL cannot be determined. Does **not** throw for -invalid/expired refresh tokens (returns `null` instead). - -```ts -// Example: Astro middleware -import { refreshSession } from '@netlify/identity' - -export async function onRequest(context, next) { - await refreshSession() - return next() -} -``` - -#### `verifyRequestOrigin` - -```ts -verifyRequestOrigin(request: Request, options?: VerifyRequestOriginOptions): void -``` - -CSRF protection helper for server-side endpoints that call `login()`, `signup()`, or `logout()`. Compares the request's -`Origin` header against the request's own origin (or an explicit allowlist via `options.allowedOrigins`) and throws if -they don't match. Server-only. - -The check runs unconditionally on every call: any HTTP method, with or without an `Origin` header. If you don't want the -check on a particular route, don't call the helper there. - -**Throws:** `AuthError` with status `403` when the request has no `Origin` header. `AuthError` with status `403` when -the request's `Origin` is not in the allowed origins. - -See [Security: CSRF protection](#security-csrf-protection) for the full threat model and per-framework guidance. - -#### `requestPasswordRecovery` - -```ts -requestPasswordRecovery(email: string): Promise -``` - -Sends a password recovery email to the given address. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` on network failure. - -#### `confirmEmail` - -```ts -confirmEmail(token: string): Promise -``` - -Confirms an email address using the token from a confirmation email. Logs the user in on success. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if the token is invalid or expired. - -#### `acceptInvite` - -```ts -acceptInvite(token: string, password: string): Promise -``` - -Accepts an invite token and sets a password for the new account. Logs the user in on success. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if the token is invalid or expired. - -#### `verifyEmailChange` - -```ts -verifyEmailChange(token: string): Promise -``` - -Verifies an email change using the token from a verification email. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if the token is invalid. - -#### `recoverPassword` - -```ts -recoverPassword(token: string, newPassword: string): Promise -``` - -Redeems a recovery token and sets a new password. Logs the user in on success. - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if the token is invalid or expired. - -#### `updateUser` - -```ts -updateUser(updates: UserUpdates): Promise -``` - -Updates the current user's metadata or credentials. Requires an active session. Pass `email` or `password` to change -credentials, or `data` to update user metadata (e.g., `{ data: { full_name: 'New Name' } }`). - -**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if no user is logged in, or the update -fails. - -### Admin Operations - -The `admin` namespace provides server-only user management functions. Admin methods use the operator token from the -Netlify runtime, which is automatically available in Netlify Functions and Edge Functions. - -Calling any admin method from a browser environment throws an `AuthError`. - -```ts -import { admin } from '@netlify/identity' -``` - -**Example: managing users in a Netlify Function** - -```ts -import { admin } from '@netlify/identity' -import type { Context } from '@netlify/functions' - -export default async (req: Request, context: Context) => { - // List all users - const users = await admin.listUsers() - - // Create a new user (auto-confirmed, no email sent) - const newUser = await admin.createUser({ - email: 'jane@example.com', - password: 'securepassword', - data: { user_metadata: { full_name: 'Jane Doe' } }, - }) - - // Update a user's role - await admin.updateUser(newUser.id, { role: 'editor' }) - - return Response.json({ created: newUser.id, total: users.length }) -} -``` - -#### `admin.listUsers` - -```ts -admin.listUsers(options?: ListUsersOptions): Promise -``` - -Lists all users. Pagination options (`page`, `perPage`) are forwarded as query parameters. - -**Throws:** `AuthError` if called from a browser, or if the operator token is missing. - -#### `admin.getUser` - -```ts -admin.getUser(userId: string): Promise -``` - -Gets a single user by ID. - -**Throws:** `AuthError` if called from a browser, the user is not found, or the operator token is missing. - -#### `admin.createUser` - -```ts -admin.createUser(params: CreateUserParams): Promise -``` - -Creates a new user. The user is auto-confirmed. Optional `data` forwards allowed fields (`role`, `app_metadata`, -`user_metadata`) to the request body. Other keys are silently ignored. `data` cannot override `email`, `password`, or -`confirm`. - -**Throws:** `AuthError` if called from a browser, the email already exists, or the operator token is missing. - -#### `admin.updateUser` - -```ts -admin.updateUser(userId: string, attributes: AdminUserUpdates): Promise -``` - -Updates an existing user by ID. Only typed `AdminUserUpdates` fields are forwarded (e.g., -`{ email: 'new@example.com' }`, `{ role: 'editor' }`). - -**Throws:** `AuthError` if called from a browser, the user is not found, or the update fails. - -#### `admin.deleteUser` - -```ts -admin.deleteUser(userId: string): Promise -``` - -Deletes a user by ID. - -**Throws:** `AuthError` if called from a browser, the user is not found, or the deletion fails. - -### Types - -#### `User` - -```ts -interface User { - id: string - email?: string - confirmedAt?: string - createdAt?: string - updatedAt?: string - role?: string - provider?: AuthProvider - name?: string - pictureUrl?: string - roles?: string[] - invitedAt?: string - confirmationSentAt?: string - recoverySentAt?: string - pendingEmail?: string - emailChangeSentAt?: string - lastSignInAt?: string - userMetadata?: Record - appMetadata?: Record -} -``` - -#### `Settings` - -```ts -interface Settings { - autoconfirm: boolean - disableSignup: boolean - providers: Record -} -``` - -#### `IdentityConfig` - -```ts -interface IdentityConfig { - url: string - token?: string -} -``` - -#### `AuthProvider` - -```ts -type AuthProvider = 'google' | 'github' | 'gitlab' | 'bitbucket' | 'facebook' | 'email' -``` - -#### `UserUpdates` - -```ts -interface UserUpdates { - email?: string - password?: string - data?: Record - [key: string]: unknown -} -``` - -Fields accepted by `updateUser()`. All fields are optional. - -#### `AdminUserUpdates` - -```ts -interface AdminUserUpdates { - email?: string - password?: string - role?: string - confirm?: boolean - app_metadata?: Record - user_metadata?: Record -} -``` - -Fields accepted by `admin.updateUser()`. Unlike `UserUpdates`, admin updates can set `role`, force-confirm a user, and -write to `app_metadata`. Only these typed fields are forwarded. - -#### `SignupData` - -```ts -type SignupData = Record -``` - -User metadata passed as the third argument to `signup()`. Stored in the user's `user_metadata` field. - -#### `AppMetadata` - -```ts -interface AppMetadata { - provider: AuthProvider - roles?: string[] - [key: string]: unknown -} -``` - -#### `ListUsersOptions` - -```ts -interface ListUsersOptions { - page?: number - perPage?: number -} -``` - -Pagination options for `admin.listUsers()`. - -#### `CreateUserParams` - -```ts -interface CreateUserParams { - email: string - password: string - data?: Record -} -``` - -Parameters for `admin.createUser()`. Optional `data` forwards allowed fields (`role`, `app_metadata`, `user_metadata`) -to the request body. Other keys are silently ignored. - -#### `Admin` - -```ts -interface Admin { - listUsers: (options?: ListUsersOptions) => Promise - getUser: (userId: string) => Promise - createUser: (params: CreateUserParams) => Promise - updateUser: (userId: string, attributes: AdminUserUpdates) => Promise - deleteUser: (userId: string) => Promise -} -``` - -The type of the `admin` export. Useful for passing the admin namespace as a dependency. - -#### `AUTH_EVENTS` - -```ts -const AUTH_EVENTS: { - LOGIN: 'login' - LOGOUT: 'logout' - TOKEN_REFRESH: 'token_refresh' - USER_UPDATED: 'user_updated' - RECOVERY: 'recovery' -} -``` - -Constants for auth event names. Use these instead of string literals for type safety and autocomplete. - -| Event | When it fires | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `LOGIN` | `login()`, `signup()` (with autoconfirm), `recoverPassword()`, `confirmEmail()`, `acceptInvite()`, `handleAuthCallback()` (OAuth/confirmation), `hydrateSession()` | -| `LOGOUT` | `logout()` | -| `TOKEN_REFRESH` | The library's auto-refresh timer refreshes an expiring access token and syncs the new token to the `nf_jwt` cookie. Fires automatically after any session-establishing flow: `login()`, `signup()`, `hydrateSession()`, `handleAuthCallback()`, `confirmEmail()`, `recoverPassword()`, `acceptInvite()`. `getUser()` also restarts the timer when it finds an existing session. | -| `USER_UPDATED` | `updateUser()`, `verifyEmailChange()`, `handleAuthCallback()` (email change) | -| `RECOVERY` | `handleAuthCallback()` (recovery token only). The user is authenticated but has **not** set a new password yet. Listen for this to redirect to a password reset form. `recoverPassword()` emits `LOGIN` instead because it completes both steps (token redemption + password change). | - -#### `AuthEvent` - -```ts -type AuthEvent = 'login' | 'logout' | 'token_refresh' | 'user_updated' | 'recovery' -``` - -#### `AuthCallback` - -```ts -type AuthCallback = (event: AuthEvent, user: User | null) => void -``` - -#### `CallbackResult` - -```ts -interface CallbackResult { - type: 'oauth' | 'confirmation' | 'recovery' | 'invite' | 'email_change' - user: User | null - token?: string -} -``` - -The `token` field is only present for `invite` callbacks, where the user hasn't set a password yet. Pass `token` to -`acceptInvite(token, password)` to finish. - -For all other types (`oauth`, `confirmation`, `recovery`, `email_change`), the user is logged in directly and `token` is -not set. - -#### `VerifyRequestOriginOptions` - -```ts -interface VerifyRequestOriginOptions { - allowedOrigins?: string[] -} -``` - -Options for [`verifyRequestOrigin`](#verifyrequestorigin). When `allowedOrigins` is set, the list replaces the default -same-origin check, so include the request's own origin if you still want it allowed. Each value is a full origin string -with scheme and host (`'https://example.com'`). - -### Errors - -#### `AuthError` - -```ts -class AuthError extends Error { - status?: number - cause?: unknown -} -``` - -#### `MissingIdentityError` - -```ts -class MissingIdentityError extends Error {} -``` - -Thrown when Identity is not configured in the current environment. - -## Security: CSRF protection - -If you expose server-side `login()`, `signup()`, or `logout()` through an HTTP endpoint, that endpoint needs Cross-Site -Request Forgery (CSRF) protection. The library cannot enforce this itself because it only sees the email and password -arguments handed to it, not the incoming request. - -**Why it matters.** A specific flavor called _login CSRF_ lets an attacker trick a victim's browser into logging into -the attacker's account. The victim then performs actions inside that session (saving payment info, linking third-party -services, uploading content), and the attacker harvests the result later by signing in with the credentials they always -controlled. `SameSite=Lax` cookies do not catch this attack because the session is being created on the victim's -browser, not ridden from an existing one. - -### `verifyRequestOrigin` - -`verifyRequestOrigin(request, options?)` compares the request's `Origin` header against the request's own origin (or an -explicit allowlist) and throws `AuthError` with status 403 on mismatch. Call it at the start of any handler that -performs an auth mutation. - -```ts -// netlify/functions/login.ts -import { login, verifyRequestOrigin } from '@netlify/identity' -import type { Context } from '@netlify/functions' - -export default async (req: Request, context: Context) => { - verifyRequestOrigin(req) - const { email, password } = await req.json() - await login(email, password) - return new Response(null, { status: 302, headers: { Location: '/dashboard' } }) -} -``` - -The helper runs unconditionally on every call. It checks any HTTP method, with or without an `Origin` header. If you -don't want the check on a particular route, don't call the helper there. - -### Custom allowed origins - -By default, the helper accepts only the request's own origin. Pass `allowedOrigins` to allow additional trusted origins -(for example, a separate frontend domain that POSTs to an API on another domain). The list replaces the default, so -include the request's own origin if you still want it allowed: - -```ts -verifyRequestOrigin(req, { - allowedOrigins: ['https://app.example.com', 'https://www.example.com'], -}) -``` - -### When to call the helper - -Some frameworks check the request's `Origin` on state-changing requests by default; others don't. Check your framework's -documentation. If same-origin enforcement is already on by default for the endpoint where you invoke `login()` / -`signup()` / `logout()`, calling `verifyRequestOrigin` yourself is redundant. If it isn't, call -`verifyRequestOrigin(request)` at the start of the handler before invoking the auth function. - -## Framework integration - -### Recommended pattern for SSR frameworks - -For SSR frameworks (Next.js, Remix, Astro, TanStack Start), the recommended pattern is: - -- **Browser-side** for auth mutations: `login()`, `signup()`, `logout()`, `oauthLogin()` -- **Server-side** for reading auth state: `getUser()`, `getSettings()`, `getIdentityConfig()` - -Browser-side auth mutations call the Identity API directly from the browser, set the `nf_jwt` cookie, and emit -`onAuthChange` events. This keeps the client UI in sync immediately. Server-side reads work because the cookie is sent -with every request. - -The library also supports server-side mutations (`login()`, `signup()`, `logout()` inside Netlify Functions), but these -require the Netlify Functions runtime to set cookies. After a server-side mutation, you need a full page navigation so -the browser sends the new cookie. - -### Next.js (App Router) - -**Server Actions return results; the client handles navigation:** - -```tsx -// app/actions.ts -'use server' -import { login, logout } from '@netlify/identity' - -export async function loginAction(formData: FormData) { - const email = formData.get('email') as string - const password = formData.get('password') as string - await login(email, password) - return { success: true } -} - -export async function logoutAction() { - await logout() - return { success: true } -} -``` - -```tsx -// app/login/page.tsx -'use client' -import { loginAction } from '../actions' - -export default function LoginPage() { - async function handleSubmit(formData: FormData) { - const result = await loginAction(formData) - if (result.success) { - window.location.href = '/dashboard' // full page load - } - } - - return
...
-} -``` - -```tsx -// app/dashboard/page.tsx -import { getUser } from '@netlify/identity' -import { redirect } from 'next/navigation' - -export default async function Dashboard() { - const user = await getUser() - if (!user) redirect('/login') - - return

Hello, {user.email}

-} -``` - -Use `window.location.href` instead of Next.js `redirect()` after server-side auth mutations. Next.js `redirect()` -triggers a soft navigation via the Router, which may not include the newly-set auth cookie. A full page load ensures the -cookie is sent and the server sees the updated auth state. Reading auth state with `getUser()` in Server Components -works normally, and `redirect()` is fine for auth gates (where no cookie was just set). - -### Remix - -**Login with Action (server-side pattern):** - -```tsx -// app/routes/login.tsx -import { login, verifyRequestOrigin } from '@netlify/identity' -import { redirect, json } from '@remix-run/node' -import type { ActionFunctionArgs } from '@remix-run/node' - -export async function action({ request }: ActionFunctionArgs) { - verifyRequestOrigin(request) - const formData = await request.formData() - const email = formData.get('email') as string - const password = formData.get('password') as string - - try { - await login(email, password) - return redirect('/dashboard') - } catch (error) { - return json({ error: (error as Error).message }, { status: 400 }) - } -} -``` - -```tsx -// app/routes/dashboard.tsx -import { getUser } from '@netlify/identity' -import { redirect } from '@remix-run/node' - -export async function loader() { - const user = await getUser() - if (!user) return redirect('/login') - return { user } -} -``` - -Remix `redirect()` works after server-side `login()` because Remix actions return real HTTP responses. The browser -receives a 302 with the `Set-Cookie` header already applied, so the next request includes the auth cookie. This is -different from Next.js, where `redirect()` in a Server Action triggers a client-side (soft) navigation that may not -include newly-set cookies. - -> The example calls [`verifyRequestOrigin`](#verifyrequestorigin) at the top of the action. See -> [Security: CSRF protection](#security-csrf-protection) for when this is needed. - -### TanStack Start - -**Login from the browser (recommended):** - -```tsx -// app/server/auth.ts - server functions for reads only -import { createServerFn } from '@tanstack/react-start' -import { getUser } from '@netlify/identity' - -export const getServerUser = createServerFn({ method: 'GET' }).handler(async () => { - const user = await getUser() - return user ?? null -}) -``` - -```tsx -// app/routes/login.tsx - browser-side auth for mutations -import { login, signup, onAuthChange } from '@netlify/identity' -import { getServerUser } from '~/server/auth' - -export const Route = createFileRoute('/login')({ - beforeLoad: async () => { - const user = await getServerUser() - if (user) throw redirect({ to: '/dashboard' }) - }, - component: Login, -}) - -function Login() { - const handleLogin = async (email: string, password: string) => { - await login(email, password) // browser-side: sets cookie + localStorage - window.location.href = '/dashboard' - } - // ... -} -``` - -```tsx -// app/routes/dashboard.tsx -import { logout } from '@netlify/identity' -import { getServerUser } from '~/server/auth' - -export const Route = createFileRoute('/dashboard')({ - beforeLoad: async () => { - const user = await getServerUser() - if (!user) throw redirect({ to: '/login' }) - }, - loader: async () => { - const user = await getServerUser() - return { user: user! } - }, - component: Dashboard, -}) - -function Dashboard() { - const { user } = Route.useLoaderData() - - const handleLogout = async () => { - await logout() // browser-side: clears cookie + localStorage - window.location.href = '/' - } - // ... -} -``` - -Use `window.location.href` instead of TanStack Router's `navigate()` after auth changes. This ensures the browser sends -the updated cookie on the next request. - -### Astro (SSR) - -**Login via API endpoint (server-side pattern):** - -```ts -// src/pages/api/login.ts -import type { APIRoute } from 'astro' -import { login } from '@netlify/identity' - -export const POST: APIRoute = async ({ request }) => { - const { email, password } = await request.json() - - try { - await login(email, password) - return new Response(null, { - status: 302, - headers: { Location: '/dashboard' }, - }) - } catch (error) { - return Response.json({ error: (error as Error).message }, { status: 400 }) - } -} -``` - -```astro ---- -// src/pages/dashboard.astro -import { getUser } from '@netlify/identity' - -const user = await getUser() -if (!user) return Astro.redirect('/login') ---- -

Hello, {user.email}

-``` - -### SvelteKit - -**Login from the browser (recommended):** - -```svelte - - - -
- - - - {#if error}

{error}

{/if} -
-``` - -```ts -// src/routes/dashboard/+page.server.ts -import { getUser } from '@netlify/identity' -import { redirect } from '@sveltejs/kit' - -export async function load() { - const user = await getUser() - if (!user) redirect(302, '/login') - return { user } -} -``` - -### Handling OAuth callbacks in SPAs - -All SPA frameworks need a callback handler that runs on page load to process OAuth redirects, email confirmations, and -password recovery tokens. Use a **wrapper component** that blocks page content while processing tokens. This prevents a -flash of unauthenticated content that occurs when the page renders before the callback completes. - -```tsx -// React component (works with Next.js, Remix, TanStack Start) -import { useEffect, useState } from 'react' -import { handleAuthCallback } from '@netlify/identity' - -const AUTH_HASH_PATTERN = /^#(confirmation_token|recovery_token|invite_token|email_change_token|access_token)=/ - -export function CallbackHandler({ children }: { children: React.ReactNode }) { - const [processing, setProcessing] = useState( - () => typeof window !== 'undefined' && AUTH_HASH_PATTERN.test(window.location.hash), - ) - const [error, setError] = useState(null) - - useEffect(() => { - if (!window.location.hash || !AUTH_HASH_PATTERN.test(window.location.hash)) return - - handleAuthCallback() - .then((result) => { - if (!result) { - setProcessing(false) - return - } - if (result.type === 'invite') { - window.location.href = `/accept-invite?token=${result.token}` - } else if (result.type === 'recovery') { - window.location.href = '/reset-password' - } else { - window.location.href = '/dashboard' - } - }) - .catch((err) => { - setError(err instanceof Error ? err.message : 'Callback failed') - setProcessing(false) - }) - }, []) - - if (error) return
Auth error: {error}
- if (processing) return
Confirming your account...
- return <>{children} -} -``` - -Wrap your page content with this component in your **root layout** so it runs on every page: - -```tsx -// Root layout - - {/* or {children} in Next.js */} - -``` - -If you only mount it on a `/callback` route, OAuth redirects and email confirmation links that land on other pages will -not be processed. - -## Guides - -### React `useAuth` hook - -The library is framework-agnostic, but here's a simple React hook for keeping components in sync with auth state: - -```tsx -import { useState, useEffect } from 'react' -import { getUser, onAuthChange } from '@netlify/identity' -import type { User } from '@netlify/identity' - -export function useAuth() { - const [user, setUser] = useState(null) - - useEffect(() => { - getUser().then(setUser) - return onAuthChange((_event, user) => setUser(user)) - }, []) - - return user -} -``` - -```tsx -function NavBar() { - const user = useAuth() - return user ?

Hello, {user.name}

: Log in -} -``` - -### Listening for auth changes - -Use `onAuthChange` to keep your UI in sync with auth state. It fires on login, logout, token refresh, user updates, and -recovery. It also detects session changes in other browser tabs (via `localStorage`). - -```ts -import { onAuthChange, AUTH_EVENTS } from '@netlify/identity' - -const unsubscribe = onAuthChange((event, user) => { - switch (event) { - case AUTH_EVENTS.LOGIN: - console.log('Logged in:', user?.email) - break - case AUTH_EVENTS.LOGOUT: - console.log('Logged out') - break - case AUTH_EVENTS.TOKEN_REFRESH: - console.log('Token refreshed for:', user?.email) - break - case AUTH_EVENTS.USER_UPDATED: - console.log('User updated:', user?.email) - break - case AUTH_EVENTS.RECOVERY: - console.log('Recovery login:', user?.email) - // Redirect to password reset form, then call updateUser({ password }) - break - } -}) - -// Later, to stop listening: -unsubscribe() -``` - -On the server, `onAuthChange` is a no-op and the returned unsubscribe function does nothing. - -### OAuth login - -OAuth login is a two-step flow: redirect the user to the provider, then process the callback when they return. - -**Step by step:** - -```ts -import { oauthLogin, handleAuthCallback } from '@netlify/identity' - -// 1. Kick off the OAuth flow (e.g., from a "Sign in with GitHub" button). -// This navigates away from the page and does not return. -oauthLogin('github') -``` - -```ts -// 2. On page load, handle the redirect back from the provider. -const result = await handleAuthCallback() - -if (result?.type === 'oauth') { - console.log('Logged in via OAuth:', result.user?.email) -} -``` - -`handleAuthCallback()` exchanges the token in the URL hash, logs the user in, clears the hash, and emits an auth event -via `onAuthChange` (`'login'` for OAuth/confirmation, `'recovery'` for password recovery). - -### Password recovery - -Password recovery is a two-step flow. The library handles the token exchange automatically via `handleAuthCallback()`, -which logs the user in and returns `{type: 'recovery', user}`. A `'recovery'` event (not `'login'`) is emitted via -`onAuthChange`, so event-based listeners can also detect this flow. You then show a "set new password" form and call -`updateUser()` to save it. - -**Step by step:** - -```ts -import { requestPasswordRecovery, handleAuthCallback, updateUser } from '@netlify/identity' - -// 1. Send recovery email (e.g., from a "forgot password" form) -await requestPasswordRecovery('jane@example.com') - -// 2-3. On page load, handle the callback -const result = await handleAuthCallback() - -if (result?.type === 'recovery') { - // 4. User is now logged in. Show your "set new password" form. - // When they submit: - const newPassword = document.getElementById('new-password').value - await updateUser({ password: newPassword }) -} -``` - -If you use the event-based pattern instead of checking `result.type`, listen for the `'recovery'` event: - -```ts -import { onAuthChange, AUTH_EVENTS } from '@netlify/identity' - -onAuthChange((event, user) => { - if (event === AUTH_EVENTS.RECOVERY) { - // Redirect to password reset form. - // The user is authenticated, so call updateUser({ password }) to set the new password. - } -}) -``` - -### Invite acceptance - -When an admin invites a user, they receive an email with an invite link. Clicking it redirects to your site with an -`invite_token` in the URL hash. Unlike other callback types, the user is not logged in automatically because they need -to set a password first. - -**Step by step:** - -```ts -import { handleAuthCallback, acceptInvite } from '@netlify/identity' - -// 1. On page load, handle the callback. -const result = await handleAuthCallback() - -if (result?.type === 'invite' && result.token) { - // 2. The user is NOT logged in yet. Show a "set your password" form. - // When they submit: - const password = document.getElementById('password').value - const user = await acceptInvite(result.token, password) - console.log('Account created:', user.email) -} -``` - -### Session lifetime - -Sessions are managed by Netlify Identity on the server side. The library stores two cookies: - -- **`nf_jwt`**: A short-lived JWT access token (default: 1 hour). -- **`nf_refresh`**: A long-lived refresh token used to obtain new access tokens without re-authenticating. - -**Browser auto-refresh:** After any session-establishing flow (`login()`, `signup()`, `hydrateSession()`, -`handleAuthCallback()`, `confirmEmail()`, `recoverPassword()`, `acceptInvite()`), the library automatically schedules a -background refresh 60 seconds before the access token expires. `getUser()` also restarts the refresh timer when it finds -an existing session (e.g., after a page reload). When the refresh fires, it obtains a new access token, syncs it to the -`nf_jwt` cookie, and emits a `TOKEN_REFRESH` event. This keeps the cookie fresh as long as the user has the tab open. If -the refresh fails (e.g., the refresh token was revoked), the timer stops and the user will need to log in again. - -**Server-side refresh:** On the server, the access token in the `nf_jwt` cookie is validated as-is. If it has expired -and no refresh happens, `getUser()` returns `null`. To handle this, call `refreshSession()` in your framework middleware -or request handler. This checks if the token is near expiry, exchanges the refresh token for a new one, and updates the -cookies on the response. - -Session lifetime is configured in your Netlify Identity settings, not in this library. - -### Caching and authenticated content - -Pages that display user-specific data (names, emails, roles, account settings) should not be served from a shared cache. -If a cache stores an authenticated response and serves it to a different user, that user sees someone else's data. This -applies to any authentication system, not just Netlify Identity. - -**Next.js App Router** has multiple caching layers that are active by default: - -- **Static rendering:** Server Components are statically rendered at build time unless they call a - [Dynamic API](https://nextjs.org/docs/app/guides/caching#dynamic-rendering) like `cookies()`. This library's - `getUser()` already calls `headers()` internally to opt the route into dynamic rendering, but if you check auth state - without calling `getUser()` (e.g., reading the `nf_jwt` cookie directly), the page may still be statically cached. - Always use `getUser()` rather than reading cookies directly. -- **ISR (Incremental Static Regeneration):** Do not use ISR for pages that display user-specific content. ISR - regenerates the page for the first visitor after the revalidation window and caches the result for all subsequent - visitors. -- **`use cache` / `unstable_cache`:** These directives cannot access `cookies()` or `headers()` directly. If you need to - cache part of an authenticated page, read cookies outside the cache scope and pass relevant values as arguments. - -> **Note:** Next.js caching defaults have changed across versions. For example, -> [Next.js 15 changed `fetch` requests, `GET` Route Handlers, and the client Router Cache to be uncached by default](https://nextjs.org/blog/next-15#caching-semantics), -> reversing the previous opt-out model. Check the [caching guide](https://nextjs.org/docs/app/guides/caching) for your -> specific Next.js version. - -**Other SSR frameworks (Remix, Astro, SvelteKit, TanStack Start):** These frameworks do not cache SSR responses by -default. If you add caching headers to improve performance, exclude routes that call `getUser()` or read auth cookies. - -## License - -MIT diff --git a/packages/identity/prod/package.json b/packages/identity/prod/package.json deleted file mode 100644 index a841208..0000000 --- a/packages/identity/prod/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "@netlify/identity", - "version": "1.2.0", - "type": "module", - "engines": { - "node": ">=18.0.0" - }, - "description": "Headless auth functions for Netlify Identity. Import { login, getUser } and call them. No init, no class, no UI.", - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json" - }, - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "publint": "npx -y publint --strict" - }, - "keywords": [ - "netlify", - "identity", - "authentication", - "jwt", - "auth", - "oauth", - "login", - "signup", - "gotrue", - "serverless", - "edge-functions" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/identity/prod" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@types/node": "^22.0.0", - "jsdom": "^28.1.0", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "gotrue-js": "^1.0.1" - } -} diff --git a/packages/identity/prod/src/account.ts b/packages/identity/prod/src/account.ts deleted file mode 100644 index 074067f..0000000 --- a/packages/identity/prod/src/account.ts +++ /dev/null @@ -1,165 +0,0 @@ -import type { UserData, User as GoTrueUser } from 'gotrue-js' - -import type { UserUpdates, GoTrueErrorBody } from './types.js' -import type { User } from './user.js' -import { toUser } from './user.js' -import { getClient, isBrowser, IDENTITY_PATH } from './environment.js' -import { persistSession, hydrateSession } from './auth.js' -import { AUTH_EVENTS, emitAuthEvent } from './events.js' -import { AuthError } from './errors.js' -import { startTokenRefresh } from './refresh.js' - -/** - * Returns the current Identity user, attempting hydration from cookies if - * no in-memory session exists. Throws if no user can be resolved. - */ -const resolveCurrentUser = async (): Promise => { - const client = getClient() - - let currentUser = client.currentUser() - if (!currentUser && isBrowser()) { - try { - await hydrateSession() - } catch { - // hydration failed (e.g. expired cookie, network error) — fall through - } - currentUser = client.currentUser() - } - if (!currentUser) throw new AuthError('No user is currently logged in') - - return currentUser -} - -/** - * Sends a password recovery email to the given address. - * - * @throws {AuthError} On network failure or if the request is rejected. - */ -export const requestPasswordRecovery = async (email: string): Promise => { - const client = getClient() - - try { - await client.requestPasswordRecovery(email) - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Redeems a recovery token and sets a new password. Logs the user in on success. - * - * @throws {AuthError} If the token is invalid, expired, or the update fails. - */ -export const recoverPassword = async (token: string, newPassword: string): Promise => { - const client = getClient() - - try { - const gotrueUser = await client.recover(token, persistSession) - const updatedUser = await gotrueUser.update({ password: newPassword }) - const user = toUser(updatedUser) - startTokenRefresh() - // Emits LOGIN because the recovery is fully complete - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return user - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Confirms an email address using the token from a confirmation email. Logs the user in on success. - * - * @throws {AuthError} If the token is invalid or expired. - */ -export const confirmEmail = async (token: string): Promise => { - const client = getClient() - - try { - const gotrueUser = await client.confirm(token, persistSession) - const user = toUser(gotrueUser) - startTokenRefresh() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return user - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Accepts an invite token and sets a password for the new account. Logs the user in on success. - * - * @throws {AuthError} If the token is invalid or expired. - */ -export const acceptInvite = async (token: string, password: string): Promise => { - const client = getClient() - - try { - const gotrueUser = await client.acceptInvite(token, password, persistSession) - const user = toUser(gotrueUser) - startTokenRefresh() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return user - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Verifies an email change using the token from a verification email. - * Auto-hydrates from auth cookies if no browser session exists. Browser only. - * - * @throws {AuthError} If called on the server, no user is logged in, or the token is invalid. - */ -export const verifyEmailChange = async (token: string): Promise => { - if (!isBrowser()) throw new AuthError('verifyEmailChange() is only available in the browser') - - const currentUser = await resolveCurrentUser() - - try { - const jwt = (await currentUser.jwt()) as string - const identityUrl = `${window.location.origin}${IDENTITY_PATH}` - - const res = await fetch(`${identityUrl}/user`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - body: JSON.stringify({ email_change_token: token }), - }) - - if (!res.ok) { - const errorBody = (await res.json().catch(() => ({}))) as GoTrueErrorBody - throw new AuthError(errorBody.msg ?? `Email change verification failed (${String(res.status)})`, res.status) - } - - const userData = (await res.json()) as UserData - const user = toUser(userData) - emitAuthEvent(AUTH_EVENTS.USER_UPDATED, user) - return user - } catch (error) { - if (error instanceof AuthError) throw error - throw AuthError.from(error) - } -} - -/** - * Updates the current user's email, password, or user metadata. - * Auto-hydrates from auth cookies if no browser session exists. - * - * @param updates - Fields to update. Pass `email` or `password` to change credentials, - * or `data` to update user metadata (e.g., `{ data: { full_name: 'New Name' } }`). - * @throws {AuthError} If no user is logged in or the update fails. - */ -export const updateUser = async (updates: UserUpdates): Promise => { - const currentUser = await resolveCurrentUser() - - try { - const updatedUser = await currentUser.update(updates) - const user = toUser(updatedUser) - emitAuthEvent(AUTH_EVENTS.USER_UPDATED, user) - return user - } catch (error) { - throw AuthError.from(error) - } -} diff --git a/packages/identity/prod/src/admin.ts b/packages/identity/prod/src/admin.ts deleted file mode 100644 index 7563790..0000000 --- a/packages/identity/prod/src/admin.ts +++ /dev/null @@ -1,261 +0,0 @@ -import type { UserData } from 'gotrue-js' - -import { isBrowser, getIdentityContext } from './environment.js' -import { AuthError } from './errors.js' -import { fetchWithTimeout } from './fetch.js' -import type { AdminUserUpdates, CreateUserParams, GoTrueErrorBody, ListUsersOptions } from './types.js' -import { toUser, type User } from './user.js' - -const SERVER_ONLY_MESSAGE = - 'Admin operations are server-only. Call admin methods from a Netlify Function or Edge Function, not from browser code.' - -/** - * Validates that a userId is a valid UUID and returns a URL-safe version. - * Identity user IDs are always UUIDs; rejecting anything else prevents - * path traversal (e.g., "../../settings") from reaching unintended endpoints. - */ -const sanitizeUserId = (userId: string): string => { - const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i - if (!uuidRegex.test(userId)) { - throw new AuthError('User ID is not a valid UUID') - } - return encodeURIComponent(userId) -} - -/** Throws if called in a browser environment. */ -const assertServer = (): void => { - if (isBrowser()) { - throw new AuthError(SERVER_ONLY_MESSAGE) - } -} - -/** - * Returns the operator token and Identity URL for server-side admin requests. - * @throws {AuthError} If the Identity endpoint URL or operator token is unavailable. - */ -const getAdminAuth = (): { url: string; token: string } => { - const ctx = getIdentityContext() - if (!ctx?.url) { - throw new AuthError('Could not determine the Identity endpoint URL on the server') - } - if (!ctx.token) { - throw new AuthError('Admin operations require an operator token (only available in Netlify Functions)') - } - return { url: ctx.url, token: ctx.token } -} - -/** - * Makes an authenticated admin request to the Identity API on the server. - * @throws {AuthError} If the request fails or the Identity API returns a non-OK status. - */ -const adminFetch = async (path: string, options: RequestInit = {}): Promise => { - const { url, token } = getAdminAuth() - let res: Response - try { - res = await fetchWithTimeout(`${url}${path}`, { - ...options, - headers: { - ...(options.headers as Record | undefined), - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - }) - } catch (error) { - throw new AuthError((error as Error).message, undefined, { cause: error }) - } - if (!res.ok) { - const errorBody = await res.json().catch(() => ({})) - throw new AuthError( - (errorBody as GoTrueErrorBody).msg ?? `Admin request failed (${String(res.status)})`, - res.status, - ) - } - return res -} - -/** - * Lists all users. Server-only. - * - * Calls `GET /admin/users` with the operator token. Pagination - * options (`page`, `perPage`) are forwarded as query parameters. - * - * @throws {AuthError} If called from a browser, or if the operator token is missing. - */ -const listUsers = async (options?: ListUsersOptions): Promise => { - assertServer() - - const params = new URLSearchParams() - if (options?.page != null) params.set('page', String(options.page)) - if (options?.perPage != null) params.set('per_page', String(options.perPage)) - const query = params.toString() - const path = `/admin/users${query ? `?${query}` : ''}` - - const res = await adminFetch(path) - const body = (await res.json()) as { users: UserData[] } - return body.users.map(toUser) -} - -/** - * Gets a single user by ID. Server-only. - * - * Calls `GET /admin/users/:id` with the operator token. - * - * @throws {AuthError} If called from a browser, the user is not found, - * or the operator token is missing. - */ -const getUser = async (userId: string): Promise => { - assertServer() - const sanitizedUserId = sanitizeUserId(userId) - const res = await adminFetch(`/admin/users/${sanitizedUserId}`) - const userData = (await res.json()) as UserData - return toUser(userData) -} - -/** - * Creates a new user. The user is auto-confirmed (no confirmation email is sent). - * Server-only. - * - * The optional `data` fields are forwarded as top-level attributes in the Identity API - * request body. Accepted fields: `role`, `app_metadata`, `user_metadata`. - * Any other keys in `data` are silently ignored. `data` cannot override `email`, - * `password`, or `confirm`. - * - * Calls `POST /admin/users` with the operator token. - * - * @throws {AuthError} If called from a browser, the email already exists, - * or the operator token is missing. - */ -const createUser = async (params: CreateUserParams): Promise => { - assertServer() - - const body: Record = { - email: params.email, - password: params.password, - confirm: true, - } - - if (params.data) { - const allowedKeys = ['role', 'app_metadata', 'user_metadata'] as const - for (const key of allowedKeys) { - if (key in params.data) { - body[key] = params.data[key] - } - } - } - - const res = await adminFetch('/admin/users', { - method: 'POST', - body: JSON.stringify(body), - }) - const userData = (await res.json()) as UserData - return toUser(userData) -} - -/** - * Updates an existing user by ID. Server-only. - * - * Calls `PUT /admin/users/:id` with the operator token. - * - * @throws {AuthError} If called from a browser, the user is not found, - * the update fails, or the operator token is missing. - */ -const updateUser = async (userId: string, attributes: AdminUserUpdates): Promise => { - assertServer() - const sanitizedUserId = sanitizeUserId(userId) - - const body: Record = {} - const allowedKeys = ['email', 'password', 'role', 'confirm', 'app_metadata', 'user_metadata'] as const - for (const key of allowedKeys) { - if (key in attributes) { - body[key] = attributes[key] - } - } - - const res = await adminFetch(`/admin/users/${sanitizedUserId}`, { - method: 'PUT', - body: JSON.stringify(body), - }) - const userData = (await res.json()) as UserData - return toUser(userData) -} - -/** - * Deletes a user by ID. Server-only. - * - * Calls `DELETE /admin/users/:id` with the operator token. - * - * @throws {AuthError} If called from a browser, the user is not found, - * the deletion fails, or the operator token is missing. - */ -const deleteUser = async (userId: string): Promise => { - assertServer() - const sanitizedUserId = sanitizeUserId(userId) - await adminFetch(`/admin/users/${sanitizedUserId}`, { method: 'DELETE' }) -} - -/** - * The admin namespace for privileged user management operations. - * All methods are server-only and require the operator token - * (automatically available in Netlify Functions and Edge Functions). - * - * Calling any admin method from a browser environment throws an `AuthError`. - */ -export interface Admin { - /** - * Lists all users. Server-only. - * - * Calls `GET /admin/users` with the operator token. Pagination - * options (`page`, `perPage`) are forwarded as query parameters. - * - * @throws {AuthError} If called from a browser, or if the operator token is missing. - */ - listUsers: (options?: ListUsersOptions) => Promise - - /** - * Gets a single user by ID. Server-only. - * - * Calls `GET /admin/users/:id` with the operator token. - * - * @throws {AuthError} If called from a browser, the user is not found, - * or the operator token is missing. - */ - getUser: (userId: string) => Promise - - /** - * Creates a new user. The user is auto-confirmed (no confirmation email is sent). - * Server-only. - * - * The optional `data` fields are forwarded as top-level attributes in the Identity API - * request body. Accepted fields: `role`, `app_metadata`, `user_metadata`. - * Any other keys in `data` are silently ignored. `data` cannot override `email`, - * `password`, or `confirm`. - * - * Calls `POST /admin/users` with the operator token. - * - * @throws {AuthError} If called from a browser, the email already exists, - * or the operator token is missing. - */ - createUser: (params: CreateUserParams) => Promise - - /** - * Updates an existing user by ID. Server-only. - * - * Calls `PUT /admin/users/:id` with the operator token. - * - * @throws {AuthError} If called from a browser, the user is not found, - * the update fails, or the operator token is missing. - */ - updateUser: (userId: string, attributes: AdminUserUpdates) => Promise - - /** - * Deletes a user by ID. Server-only. - * - * Calls `DELETE /admin/users/:id` with the operator token. - * - * @throws {AuthError} If called from a browser, the user is not found, - * the deletion fails, or the operator token is missing. - */ - deleteUser: (userId: string) => Promise -} - -export const admin: Admin = { listUsers, getUser, createUser, updateUser, deleteUser } diff --git a/packages/identity/prod/src/auth.ts b/packages/identity/prod/src/auth.ts deleted file mode 100644 index ee2e75d..0000000 --- a/packages/identity/prod/src/auth.ts +++ /dev/null @@ -1,486 +0,0 @@ -import type GoTrue from 'gotrue-js' -import type { UserData } from 'gotrue-js' -import type { AuthProvider, NetlifyCookies, SignupData, TokenResponse, GoTrueErrorBody } from './types.js' -import { toUser, decodeJwtPayload } from './user.js' - -import { getClient, getIdentityContext, isBrowser, IDENTITY_PATH } from './environment.js' -import { - getCookie, - setAuthCookies, - deleteAuthCookies, - setBrowserAuthCookies, - deleteBrowserAuthCookies, - NF_JWT_COOKIE, - NF_REFRESH_COOKIE, -} from './cookies.js' -import { AuthError } from './errors.js' -import { AUTH_EVENTS, emitAuthEvent } from './events.js' -import { startTokenRefresh, stopTokenRefresh } from './refresh.js' -import { fetchWithTimeout } from './fetch.js' - -const getCookies = (): NetlifyCookies => { - const cookies = globalThis.Netlify?.context?.cookies - if (!cookies) { - throw new AuthError('Server-side auth requires Netlify Functions runtime') - } - return cookies -} - -const getServerIdentityUrl = (): string => { - const ctx = getIdentityContext() - if (!ctx?.url) { - throw new AuthError('Could not determine the Identity endpoint URL on the server') - } - return ctx.url -} - -/** Persist the session to localStorage so it survives page reloads. */ -export const persistSession = true - -/** - * Logs in with email and password. Works in both browser and server contexts. - * - * On success, sets `nf_jwt` and `nf_refresh` cookies and returns the authenticated {@link User}. - * In the browser, also emits a `'login'` event via {@link onAuthChange}. - * - * @throws {AuthError} On invalid credentials, network failure, or missing Netlify runtime. - * - * @remarks - * In Next.js server actions, call `redirect()` **after** `login()` returns, not inside a - * try/catch. Next.js implements `redirect()` by throwing a special error; wrapping it in - * try/catch will swallow the redirect. - * - * **Server-side CSRF:** When called from a server endpoint, the endpoint must have CSRF - * protection. If your framework does not check the request's `Origin` by default, call - * {@link verifyRequestOrigin} at the start of the handler before invoking `login()`. - * - * @example - * ```ts - * // Next.js server action - * const user = await login(email, password) - * redirect('/dashboard') // after login, not inside try/catch - * ``` - */ -export const login = async (email: string, password: string): Promise => { - if (!isBrowser()) { - const identityUrl = getServerIdentityUrl() - const cookies = getCookies() - - const body = new URLSearchParams({ - grant_type: 'password', - username: email, - password, - }) - - let res: Response - try { - res = await fetchWithTimeout(`${identityUrl}/token`, { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: body.toString(), - }) - } catch (error) { - throw AuthError.from(error) - } - - if (!res.ok) { - const errorBody = (await res.json().catch(() => ({}))) as GoTrueErrorBody - throw new AuthError( - errorBody.msg ?? errorBody.error_description ?? `Login failed (${String(res.status)})`, - res.status, - ) - } - - const data = (await res.json()) as TokenResponse - const accessToken = data.access_token - - let userRes: Response - try { - userRes = await fetchWithTimeout(`${identityUrl}/user`, { - headers: { Authorization: `Bearer ${accessToken}` }, - }) - } catch (error) { - throw AuthError.from(error) - } - - if (!userRes.ok) { - const errorBody = (await userRes.json().catch(() => ({}))) as GoTrueErrorBody - throw new AuthError(errorBody.msg ?? `Failed to fetch user data (${String(userRes.status)})`, userRes.status) - } - - const userData = (await userRes.json()) as UserData - const user = toUser(userData) - - setAuthCookies(cookies, accessToken, data.refresh_token) - - return user - } - - const client = getClient() - - try { - const gotrueUser = await client.login(email, password, persistSession) - const jwt = await gotrueUser.jwt() - setBrowserAuthCookies(jwt, gotrueUser.tokenDetails()?.refresh_token) - const user = toUser(gotrueUser) - startTokenRefresh() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return user - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Creates a new account. Works in both browser and server contexts. - * - * If autoconfirm is enabled in your Identity settings, the user is logged in immediately: - * cookies are set and a `'login'` event is emitted. If autoconfirm is **disabled** (the default), - * the user receives a confirmation email and must click the link before they can log in. - * In that case, no cookies are set and no auth event is emitted. - * - * @throws {AuthError} On duplicate email, validation failure, network error, or missing Netlify runtime. - * - * @remarks - * **Server-side CSRF:** When called from a server endpoint, the endpoint must have CSRF - * protection. If your framework does not check the request's `Origin` by default, call - * {@link verifyRequestOrigin} at the start of the handler before invoking `signup()`. - */ -export const signup = async (email: string, password: string, data?: SignupData): Promise => { - if (!isBrowser()) { - const identityUrl = getServerIdentityUrl() - const cookies = getCookies() - - let res: Response - try { - res = await fetchWithTimeout(`${identityUrl}/signup`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email, password, data }), - }) - } catch (error) { - throw AuthError.from(error) - } - - if (!res.ok) { - const errorBody = (await res.json().catch(() => ({}))) as GoTrueErrorBody - throw new AuthError(errorBody.msg ?? `Signup failed (${String(res.status)})`, res.status) - } - - const responseData = (await res.json()) as UserData & Partial - const user = toUser(responseData) - - if (responseData.confirmed_at) { - const accessToken = responseData.access_token - if (accessToken) { - setAuthCookies(cookies, accessToken, responseData.refresh_token) - } - } - - return user - } - - const client = getClient() - - try { - const response = await client.signup(email, password, data) - const user = toUser(response as UserData) - if (response.confirmed_at) { - const jwt = await (response as { jwt?: () => Promise }).jwt?.() - if (jwt) { - const refreshToken = (response as { tokenDetails?: () => { refresh_token: string } | null }).tokenDetails?.() - ?.refresh_token - setBrowserAuthCookies(jwt, refreshToken) - } - startTokenRefresh() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - } - return user - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Logs out the current user and clears the session. Works in both browser and server contexts. - * - * Always deletes `nf_jwt` and `nf_refresh` cookies, even if the server-side token - * invalidation request fails. In the browser, emits a `'logout'` event via {@link onAuthChange}. - * - * @throws {AuthError} On missing Netlify runtime (server) or logout failure (browser). - * - * @remarks - * **Server-side CSRF:** When called from a server endpoint, the endpoint must have CSRF - * protection. If your framework does not check the request's `Origin` by default, call - * {@link verifyRequestOrigin} at the start of the handler before invoking `logout()`. - */ -export const logout = async (): Promise => { - if (!isBrowser()) { - const identityUrl = getServerIdentityUrl() - const cookies = getCookies() - - const jwt = cookies.get(NF_JWT_COOKIE) - if (jwt) { - try { - await fetchWithTimeout(`${identityUrl}/logout`, { - method: 'POST', - headers: { Authorization: `Bearer ${jwt}` }, - }) - } catch { - // Best-effort: token invalidation may fail, but we always clear cookies below - } - } - - deleteAuthCookies(cookies) - return - } - - const client = getClient() - - try { - const currentUser = client.currentUser() - if (currentUser) { - await currentUser.logout() - } - deleteBrowserAuthCookies() - stopTokenRefresh() - emitAuthEvent(AUTH_EVENTS.LOGOUT, null) - } catch (error) { - throw AuthError.from(error) - } -} - -/** - * Initiates an OAuth login by redirecting to the given provider (e.g., `'google'`, `'github'`). - * The page navigates away; this function never returns normally. Browser only. - * - * After the provider redirects back, call {@link handleAuthCallback} on page load - * to complete the login and obtain the {@link User}. - * - * @throws {AuthError} If called on the server. - */ -export const oauthLogin = (provider: AuthProvider): never => { - if (!isBrowser()) { - throw new AuthError('oauthLogin() is only available in the browser') - } - const client = getClient() - - window.location.href = client.loginExternalUrl(provider) - throw new AuthError('Redirecting to OAuth provider') -} - -/** - * Result returned by {@link handleAuthCallback} after processing a URL hash. - * - * - `'oauth'`: OAuth provider redirect completed. `user` is the authenticated user. - * - `'confirmation'`: Email confirmed via token. `user` is the confirmed user. - * - `'recovery'`: Password recovery token redeemed. `user` is logged in but must set a new password. - * - `'invite'`: Invite token found. `user` is `null`; `token` contains the invite token for {@link acceptInvite}. - * - `'email_change'`: Email change verified. `user` reflects the updated email. - * - * @example - * ```ts - * const result = await handleAuthCallback() - * if (result?.type === 'recovery') { - * redirect('/reset-password') - * } else if (result?.type === 'invite') { - * redirect(`/join?token=${result.token}`) - * } - * ``` - */ -export interface CallbackResult { - /** The type of auth callback that was processed. */ - type: 'oauth' | 'confirmation' | 'recovery' | 'invite' | 'email_change' - /** The authenticated user, or `null` for invite callbacks. */ - user: import('./user.js').User | null - /** The invite token, only present when `type` is `'invite'`. */ - token?: string -} - -/** - * Processes the URL hash after an OAuth redirect, email confirmation, password - * recovery, invite acceptance, or email change. Call on page load. Browser only. - * Returns `null` if the hash contains no auth parameters. - * - * Call this early in your app's initialization (e.g., in a layout component or - * root loader), **not** inside a route that requires authentication, because - * the callback URL must match the page where this function runs. - * - * For recovery callbacks (`result.type === 'recovery'`), the user is logged in - * but has **not** set a new password yet. Your app must check the result type - * and redirect to a password form that calls `updateUser({ password })`. - * A `'recovery'` event (not `'login'`) is emitted via {@link onAuthChange}. - * - * @throws {AuthError} If the callback token is invalid or the verification request fails. - */ -export const handleAuthCallback = async (): Promise => { - if (!isBrowser()) return null - - const hash = window.location.hash.substring(1) - if (!hash) return null - - const client = getClient() - const params = new URLSearchParams(hash) - - try { - const accessToken = params.get('access_token') - if (accessToken) return await handleOAuthCallback(client, params, accessToken) - - const confirmationToken = params.get('confirmation_token') - if (confirmationToken) return await handleConfirmationCallback(client, confirmationToken) - - const recoveryToken = params.get('recovery_token') - if (recoveryToken) return await handleRecoveryCallback(client, recoveryToken) - - const inviteToken = params.get('invite_token') - if (inviteToken) return handleInviteCallback(inviteToken) - - const emailChangeToken = params.get('email_change_token') - if (emailChangeToken) return await handleEmailChangeCallback(client, emailChangeToken) - - return null - } catch (error) { - if (error instanceof AuthError) throw error - throw AuthError.from(error) - } -} - -const handleOAuthCallback = async ( - client: GoTrue, - params: URLSearchParams, - accessToken: string, -): Promise => { - const refreshToken = params.get('refresh_token') ?? '' - const expiresIn = parseInt(params.get('expires_in') ?? '', 10) - const expiresAt = parseInt(params.get('expires_at') ?? '', 10) - const gotrueUser = await client.createUser( - { - access_token: accessToken, - token_type: (params.get('token_type') ?? 'bearer') as 'bearer', - expires_in: isFinite(expiresIn) ? expiresIn : 3600, - expires_at: isFinite(expiresAt) ? expiresAt : Math.floor(Date.now() / 1000) + 3600, - refresh_token: refreshToken, - }, - persistSession, - ) - setBrowserAuthCookies(accessToken, refreshToken || undefined) - const user = toUser(gotrueUser) - startTokenRefresh() - clearHash() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return { type: 'oauth', user } -} - -const handleConfirmationCallback = async (client: GoTrue, token: string): Promise => { - const gotrueUser = await client.confirm(token, persistSession) - const jwt = await gotrueUser.jwt() - setBrowserAuthCookies(jwt, gotrueUser.tokenDetails()?.refresh_token) - const user = toUser(gotrueUser) - startTokenRefresh() - clearHash() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return { type: 'confirmation', user } -} - -const handleRecoveryCallback = async (client: GoTrue, token: string): Promise => { - const gotrueUser = await client.recover(token, persistSession) - const jwt = await gotrueUser.jwt() - setBrowserAuthCookies(jwt, gotrueUser.tokenDetails()?.refresh_token) - const user = toUser(gotrueUser) - startTokenRefresh() - clearHash() - emitAuthEvent(AUTH_EVENTS.RECOVERY, user) - return { type: 'recovery', user } -} - -const handleInviteCallback = (token: string): CallbackResult => { - clearHash() - return { type: 'invite', user: null, token } -} - -const handleEmailChangeCallback = async (client: GoTrue, emailChangeToken: string): Promise => { - const currentUser = client.currentUser() - if (!currentUser) { - throw new AuthError('Email change verification requires an active browser session') - } - - const jwt = (await currentUser.jwt()) as string - const identityUrl = `${window.location.origin}${IDENTITY_PATH}` - - const emailChangeRes = await fetch(`${identityUrl}/user`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - body: JSON.stringify({ email_change_token: emailChangeToken }), - }) - - if (!emailChangeRes.ok) { - const errorBody = (await emailChangeRes.json().catch(() => ({}))) as GoTrueErrorBody - throw new AuthError( - errorBody.msg ?? `Email change verification failed (${String(emailChangeRes.status)})`, - emailChangeRes.status, - ) - } - - const emailChangeData = (await emailChangeRes.json()) as UserData - const user = toUser(emailChangeData) - clearHash() - emitAuthEvent(AUTH_EVENTS.USER_UPDATED, user) - return { type: 'email_change', user } -} - -const clearHash = (): void => { - history.replaceState(null, '', window.location.pathname + window.location.search) -} - -/** - * Hydrates the browser-side session from server-set auth cookies. - * Call this on page load when using server-side login to enable browser - * account operations (updateUser, verifyEmailChange, etc.). - * - * No-op if a browser session already exists or no auth cookies are present. - * No-op on the server. - */ -export const hydrateSession = async (): Promise => { - if (!isBrowser()) return null - - const client = getClient() - const currentUser = client.currentUser() - if (currentUser) { - startTokenRefresh() - return toUser(currentUser) - } - - const accessToken = getCookie(NF_JWT_COOKIE) - if (!accessToken) return null - - const refreshToken = getCookie(NF_REFRESH_COOKIE) ?? '' - - const decoded = decodeJwtPayload(accessToken) - const expiresAt = decoded?.exp ?? Math.floor(Date.now() / 1000) + 3600 - const expiresIn = Math.max(0, expiresAt - Math.floor(Date.now() / 1000)) - - let gotrueUser - try { - gotrueUser = await client.createUser( - { - access_token: accessToken, - token_type: 'bearer', - expires_in: expiresIn, - expires_at: expiresAt, - refresh_token: refreshToken, - }, - persistSession, - ) - } catch { - deleteBrowserAuthCookies() - return null - } - - const user = toUser(gotrueUser) - startTokenRefresh() - emitAuthEvent(AUTH_EVENTS.LOGIN, user) - return user -} diff --git a/packages/identity/prod/src/config.ts b/packages/identity/prod/src/config.ts deleted file mode 100644 index e4c5a99..0000000 --- a/packages/identity/prod/src/config.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { AuthProvider, IdentityConfig, Settings } from './types.js' -import { getClient, getIdentityContext, IDENTITY_PATH, isBrowser } from './environment.js' -import { AuthError } from './errors.js' - -/** - * Returns the identity configuration for the current environment. - * Browser: always returns `{ url }` derived from `window.location.origin`. - * Server: returns `{ url, token }` from the identity context, or `null` if unavailable. - * Never throws. - */ -export const getIdentityConfig = (): IdentityConfig | null => { - if (isBrowser()) { - return { url: `${window.location.origin}${IDENTITY_PATH}` } - } - - return getIdentityContext() -} - -/** - * Fetches your project's Identity settings (enabled providers, autoconfirm, signup disabled). - * - * @throws {MissingIdentityError} If Identity is not configured. - * @throws {AuthError} If the endpoint is unreachable. - */ -export const getSettings = async (): Promise => { - const client = getClient() - - try { - const raw = await client.settings() - const external: Partial> = raw.external ?? {} - return { - autoconfirm: raw.autoconfirm, - disableSignup: raw.disable_signup, - providers: { - google: external.google ?? false, - github: external.github ?? false, - gitlab: external.gitlab ?? false, - bitbucket: external.bitbucket ?? false, - facebook: external.facebook ?? false, - email: external.email ?? false, - }, - } - } catch (err) { - throw new AuthError(err instanceof Error ? err.message : 'Failed to fetch identity settings', 502, { cause: err }) - } -} diff --git a/packages/identity/prod/src/cookies.ts b/packages/identity/prod/src/cookies.ts deleted file mode 100644 index e11c089..0000000 --- a/packages/identity/prod/src/cookies.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { NetlifyCookies } from './types.js' - -export const NF_JWT_COOKIE = 'nf_jwt' -export const NF_REFRESH_COOKIE = 'nf_refresh' - -/** Reads a cookie value from `document.cookie` by name. Returns `null` if not found or not in a browser. */ -export const getCookie = (name: string): string | null => { - if (typeof document === 'undefined') return null - const match = new RegExp(`(?:^|; )${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}=([^;]*)`).exec(document.cookie) - if (!match) return null - try { - return decodeURIComponent(match[1]) - } catch { - return match[1] - } -} - -/** Sets the `nf_jwt` and (optionally) `nf_refresh` auth cookies via the Netlify runtime. */ -export const setAuthCookies = (cookies: NetlifyCookies, accessToken: string, refreshToken?: string): void => { - cookies.set({ - name: NF_JWT_COOKIE, - value: accessToken, - httpOnly: false, - secure: true, - path: '/', - sameSite: 'Lax', - }) - - if (refreshToken) { - // httpOnly: false because browser-side hydration (backgroundHydrate, hydrateSession) - // reads nf_refresh via document.cookie to bootstrap the gotrue-js session. - cookies.set({ - name: NF_REFRESH_COOKIE, - value: refreshToken, - httpOnly: false, - secure: true, - path: '/', - sameSite: 'Lax', - }) - } -} - -/** Deletes both auth cookies via the Netlify runtime. */ -export const deleteAuthCookies = (cookies: NetlifyCookies): void => { - cookies.delete(NF_JWT_COOKIE) - cookies.delete(NF_REFRESH_COOKIE) -} - -/** Sets auth cookies via document.cookie (browser-side). No-op on the server. */ -export const setBrowserAuthCookies = (accessToken: string, refreshToken?: string): void => { - if (typeof document === 'undefined') return - document.cookie = `${NF_JWT_COOKIE}=${encodeURIComponent(accessToken)}; path=/; secure; samesite=lax` - if (refreshToken) { - document.cookie = `${NF_REFRESH_COOKIE}=${encodeURIComponent(refreshToken)}; path=/; secure; samesite=lax` - } -} - -/** Deletes auth cookies via document.cookie (browser-side). No-op on the server. */ -export const deleteBrowserAuthCookies = (): void => { - if (typeof document === 'undefined') return - document.cookie = `${NF_JWT_COOKIE}=; path=/; secure; samesite=lax; expires=Thu, 01 Jan 1970 00:00:00 GMT` - document.cookie = `${NF_REFRESH_COOKIE}=; path=/; secure; samesite=lax; expires=Thu, 01 Jan 1970 00:00:00 GMT` -} - -/** Reads a cookie from the server-side Netlify runtime. Returns `null` if not available. */ -export const getServerCookie = (name: string): string | null => { - const cookies = globalThis.Netlify?.context?.cookies - if (!cookies || typeof cookies.get !== 'function') return null - return cookies.get(name) ?? null -} diff --git a/packages/identity/prod/src/csrf.ts b/packages/identity/prod/src/csrf.ts deleted file mode 100644 index 4207847..0000000 --- a/packages/identity/prod/src/csrf.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { AuthError } from './errors.js' - -/** - * Options for {@link verifyRequestOrigin}. - */ -export interface VerifyRequestOriginOptions { - /** - * Origins that are allowed to make state-changing requests to this endpoint. - * - * If omitted, the request is only accepted from its own origin (the origin of `request.url`), - * which is the right default for sites whose login form and login endpoint live on the same origin. - * - * Pass an explicit list when you trust additional origins (for example, a separate frontend domain - * posting to an API on another domain). The list replaces the default, so it must include every - * origin you want to allow, including the request's own origin if applicable. - * - * Each value should be a full origin string with scheme and host: `'https://example.com'`. - */ - allowedOrigins?: string[] -} - -/** - * Same-origin check for state-changing requests, can be used to defend against Cross-Site Request - * Forgery (CSRF) on server-side endpoints that call {@link login}, {@link signup}, or {@link logout}. - * - * Compares the incoming request's `Origin` header against the request's own origin (or an explicit - * allowlist via `options.allowedOrigins`) and throws if they don't match. Call this at the start of - * any server-side handler that performs an auth mutation, before invoking the auth function. - * - * The check runs unconditionally on every call: any HTTP method, with or without an `Origin` header. - * If you don't want the check to apply to a given method or path, simply don't call the helper there. - * - * @throws {AuthError} with status `403` when the request has no `Origin` header. - * @throws {AuthError} with status `403` when the request's `Origin` is not in the allowed origins. - * - * @example - * ```ts - * // Netlify Function - * import { login, verifyRequestOrigin } from '@netlify/identity' - * import type { Context } from '@netlify/functions' - * - * export default async (req: Request, context: Context) => { - * verifyRequestOrigin(req) - * const { email, password } = await req.json() - * await login(email, password) - * return new Response(null, { status: 302, headers: { Location: '/dashboard' } }) - * } - * ``` - * - * @example - * ```ts - * // Allow a separate trusted origin (e.g. a marketing site posting to an app domain). - * // The list replaces the default, so include the request's own origin if you still want it allowed. - * verifyRequestOrigin(request, { - * allowedOrigins: ['https://app.example.com', 'https://www.example.com'], - * }) - * ``` - */ -export const verifyRequestOrigin = (request: Request, options?: VerifyRequestOriginOptions): void => { - const origin = request.headers.get('origin') - if (!origin) { - throw new AuthError('Cross-origin request refused: missing Origin header.', 403) - } - - const allowed = options?.allowedOrigins ?? [new URL(request.url).origin] - if (!allowed.includes(origin)) { - throw new AuthError(`Cross-origin request refused: Origin ${origin} did not match an allowed origin.`, 403) - } -} diff --git a/packages/identity/prod/src/environment.ts b/packages/identity/prod/src/environment.ts deleted file mode 100644 index 562ee2c..0000000 --- a/packages/identity/prod/src/environment.ts +++ /dev/null @@ -1,102 +0,0 @@ -import GoTrue from 'gotrue-js' - -import type { IdentityConfig } from './types.js' -import { MissingIdentityError } from './errors.js' - -export const IDENTITY_PATH = '/.netlify/identity' - -let goTrueClient: GoTrue | null = null -let cachedApiUrl: string | null | undefined -let warnedMissingUrl = false - -export const isBrowser = (): boolean => typeof window !== 'undefined' && typeof window.location !== 'undefined' - -/** - * Discovers and caches the Identity API URL. - * - * Browser: uses `window.location.origin` + IDENTITY_PATH. - * Server: reads from `globalThis.netlifyIdentityContext`. - */ -const discoverApiUrl = (): string | null => { - if (cachedApiUrl !== undefined) return cachedApiUrl - - if (isBrowser()) { - cachedApiUrl = `${window.location.origin}${IDENTITY_PATH}` - } else { - const identityContext = getIdentityContext() - if (identityContext?.url) { - cachedApiUrl = identityContext.url - } else if (globalThis.Netlify?.context?.url) { - cachedApiUrl = new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href - } else if (typeof process !== 'undefined' && process.env?.URL) { - cachedApiUrl = new URL(IDENTITY_PATH, process.env.URL).href - } - } - - return cachedApiUrl ?? null -} - -/** - * Returns (and lazily creates) a singleton Identity client. - * Returns `null` and logs a warning if no identity URL can be discovered. - */ -export const getGoTrueClient = (): GoTrue | null => { - if (goTrueClient) return goTrueClient - - const apiUrl = discoverApiUrl() - if (!apiUrl) { - if (!warnedMissingUrl) { - console.warn( - '@netlify/identity: Could not determine the Identity endpoint URL. ' + - 'Make sure your site has Netlify Identity enabled, or run your app with `netlify dev`.', - ) - warnedMissingUrl = true - } - return null - } - - goTrueClient = new GoTrue({ APIUrl: apiUrl, setCookie: false }) - return goTrueClient -} - -/** - * Returns the singleton Identity client, or throws if Identity is not configured. - */ -export const getClient = (): GoTrue => { - const client = getGoTrueClient() - if (!client) throw new MissingIdentityError() - return client -} - -/** - * Reads the server-side identity context set by the Netlify bootstrap. - * Returns `null` outside the Netlify serverless environment. - */ -export const getIdentityContext = (): IdentityConfig | null => { - const identityContext = globalThis.netlifyIdentityContext - if (identityContext?.url) { - return { - url: identityContext.url, - token: identityContext.token, - } - } - - if (globalThis.Netlify?.context?.url) { - return { url: new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href } - } - - // Fallback: Netlify sets the URL env var on all deployed sites - const siteUrl = typeof process !== 'undefined' ? process.env?.URL : undefined - if (siteUrl) { - return { url: new URL(IDENTITY_PATH, siteUrl).href } - } - - return null -} - -/** Reset cached state for tests. */ -export const resetTestGoTrueClient = (): void => { - goTrueClient = null - cachedApiUrl = undefined - warnedMissingUrl = false -} diff --git a/packages/identity/prod/src/errors.ts b/packages/identity/prod/src/errors.ts deleted file mode 100644 index 7743973..0000000 --- a/packages/identity/prod/src/errors.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Thrown by auth operations when something goes wrong: invalid credentials, - * network failures, missing runtime context, etc. - * - * The `status` field contains the HTTP status code from the Identity API when available - * (e.g., 401 for bad credentials, 422 for validation errors). - * The `cause` field preserves the original error for debugging. - * - * @example - * ```ts - * try { - * await login(email, password) - * } catch (error) { - * if (error instanceof AuthError) { - * console.error(error.message, error.status) - * } - * } - * ``` - */ -export class AuthError extends Error { - override name = 'AuthError' - /** HTTP status code from the Identity API, if the error originated from an API response. */ - status?: number - declare cause?: unknown - - constructor(message: string, status?: number, options?: { cause?: unknown }) { - super(message) - this.status = status - if (options && 'cause' in options) { - this.cause = options.cause - } - } - - static from(error: unknown): AuthError { - if (error instanceof AuthError) return error - const message = error instanceof Error ? error.message : String(error) - return new AuthError(message, undefined, { cause: error }) - } -} - -/** - * Thrown when a function requires the Identity client but Netlify Identity - * is not configured (no endpoint URL could be discovered). - * - * This typically means the site does not have Identity enabled, or the app - * is not running via `netlify dev` / deployed on Netlify. - */ -export class MissingIdentityError extends Error { - override name = 'MissingIdentityError' - - constructor(message = 'Netlify Identity is not available.') { - super(message) - } -} diff --git a/packages/identity/prod/src/events.ts b/packages/identity/prod/src/events.ts deleted file mode 100644 index 9ce362d..0000000 --- a/packages/identity/prod/src/events.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { getGoTrueClient, isBrowser } from './environment.js' -import { toUser, type User } from './user.js' - -/** - * Constants for the auth events emitted by the library. - * Use these instead of string literals when comparing event types. - * - * @example - * ```ts - * onAuthChange((event, user) => { - * if (event === AUTH_EVENTS.LOGIN) console.log('Logged in:', user) - * if (event === AUTH_EVENTS.RECOVERY) redirect('/reset-password') - * }) - * ``` - */ -export const AUTH_EVENTS = { - LOGIN: 'login', - LOGOUT: 'logout', - TOKEN_REFRESH: 'token_refresh', - USER_UPDATED: 'user_updated', - RECOVERY: 'recovery', -} as const - -/** - * Union of all auth event names: `'login' | 'logout' | 'token_refresh' | 'user_updated' | 'recovery'`. - * Passed as the first argument to {@link AuthCallback} subscribers. - */ -export type AuthEvent = (typeof AUTH_EVENTS)[keyof typeof AUTH_EVENTS] - -/** - * Callback function signature for {@link onAuthChange} subscribers. - * `user` is `null` on logout events. - */ -export type AuthCallback = (event: AuthEvent, user: User | null) => void - -const GOTRUE_STORAGE_KEY = 'gotrue.user' - -const listeners = new Set() - -export const emitAuthEvent = (event: AuthEvent, user: User | null): void => { - for (const listener of listeners) { - try { - listener(event, user) - } catch { - // Prevent one subscriber from breaking others - } - } -} - -let storageListenerAttached = false - -const attachStorageListener = (): void => { - if (storageListenerAttached || !isBrowser()) return - storageListenerAttached = true - - window.addEventListener('storage', (event: StorageEvent) => { - if (event.key !== GOTRUE_STORAGE_KEY) return - - if (event.newValue) { - const client = getGoTrueClient() - const currentUser = client?.currentUser() - emitAuthEvent(AUTH_EVENTS.LOGIN, currentUser ? toUser(currentUser) : null) - } else { - emitAuthEvent(AUTH_EVENTS.LOGOUT, null) - } - }) -} - -/** - * Subscribes to auth state changes (login, logout, token refresh, user updates, - * and recovery). Returns an unsubscribe function. No-op on the server. - * - * The `'recovery'` event fires when {@link handleAuthCallback} processes a - * password recovery token. The user is logged in but has not yet set a new - * password. Redirect them to a password reset form and call - * `updateUser({ password })` to complete the flow. - */ -export const onAuthChange = (callback: AuthCallback): (() => void) => { - if (!isBrowser()) { - return () => {} - } - - listeners.add(callback) - attachStorageListener() - - return () => { - listeners.delete(callback) - } -} diff --git a/packages/identity/prod/src/fetch.ts b/packages/identity/prod/src/fetch.ts deleted file mode 100644 index 91c8fea..0000000 --- a/packages/identity/prod/src/fetch.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AuthError } from './errors.js' - -/** Default timeout for server-side Identity API requests (ms). */ -const DEFAULT_TIMEOUT_MS = 5000 - -/** - * Wraps `fetch` with an AbortController timeout for server-side requests. - * If the request doesn't complete within `timeoutMs`, the connection is - * aborted and an AuthError is thrown. - * - * Not exported from the package; used internally by auth, admin, refresh, - * and user modules for all server-side Identity API calls. - */ -export const fetchWithTimeout = async ( - url: string, - options: RequestInit = {}, - timeoutMs = DEFAULT_TIMEOUT_MS, -): Promise => { - const controller = new AbortController() - const timer = setTimeout(() => { - controller.abort() - }, timeoutMs) - - try { - return await fetch(url, { ...options, signal: controller.signal }) - } catch (error) { - if (error instanceof Error && error.name === 'AbortError') { - const pathname = new URL(url).pathname - throw new AuthError(`Identity request to ${pathname} timed out after ${String(timeoutMs)}ms`) - } - throw error - } finally { - clearTimeout(timer) - } -} diff --git a/packages/identity/prod/src/globals.d.ts b/packages/identity/prod/src/globals.d.ts deleted file mode 100644 index 6a5e9e7..0000000 --- a/packages/identity/prod/src/globals.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { NetlifyCookies } from './types.js' -import type { IdentityUser } from './user.js' - -interface NetlifyIdentityContext { - url?: string - token?: string - user?: IdentityUser -} - -declare global { - var netlifyIdentityContext: NetlifyIdentityContext | undefined - var Netlify: { context?: { url?: string; cookies?: NetlifyCookies } } | undefined -} - -export {} diff --git a/packages/identity/prod/src/main.ts b/packages/identity/prod/src/main.ts deleted file mode 100644 index 6a87b8d..0000000 --- a/packages/identity/prod/src/main.ts +++ /dev/null @@ -1,32 +0,0 @@ -export type { User } from './user.js' -export { getUser, isAuthenticated } from './user.js' -export { getIdentityConfig, getSettings } from './config.js' -export type { AuthCallback, AuthEvent } from './events.js' -export { AUTH_EVENTS, onAuthChange } from './events.js' -export type { CallbackResult } from './auth.js' -export { login, signup, logout, oauthLogin, handleAuthCallback, hydrateSession } from './auth.js' -export { refreshSession } from './refresh.js' -export { AuthError, MissingIdentityError } from './errors.js' -export { verifyRequestOrigin } from './csrf.js' -export type { VerifyRequestOriginOptions } from './csrf.js' -export type { - AdminUserUpdates, - AppMetadata, - AuthProvider, - CreateUserParams, - IdentityConfig, - ListUsersOptions, - Settings, - UserUpdates, - SignupData, -} from './types.js' -export type { Admin } from './admin.js' -export { - requestPasswordRecovery, - recoverPassword, - confirmEmail, - acceptInvite, - verifyEmailChange, - updateUser, -} from './account.js' -export { admin } from './admin.js' diff --git a/packages/identity/prod/src/nextjs.ts b/packages/identity/prod/src/nextjs.ts deleted file mode 100644 index 32c1f0b..0000000 --- a/packages/identity/prod/src/nextjs.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Minimal declaration so we can use require() without @types/node -// eslint-disable-next-line @typescript-eslint/no-explicit-any -declare const require: ((id: string) => any) | undefined - -/** - * Calls `headers()` from `next/headers` if available, to opt Next.js RSC - * routes into dynamic rendering. Without this, Next.js may statically - * optimize pages that call functions in this package, caching the build-time result. - * - * Re-throws DynamicServerError so Next.js can catch it and switch to - * dynamic rendering. Silently ignores if not in a Next.js environment. - */ -let nextHeadersFn: (() => unknown) | null | undefined -export const triggerNextjsDynamic = (): void => { - if (nextHeadersFn === null) return - - if (nextHeadersFn === undefined) { - try { - if (typeof require === 'undefined') { - nextHeadersFn = null - return - } - const mod = require('next/headers') - nextHeadersFn = mod.headers - } catch { - nextHeadersFn = null - return - } - } - - const fn = nextHeadersFn - if (!fn) return - - try { - fn() - } catch (e: unknown) { - // Re-throw DynamicServerError so Next.js can opt into dynamic rendering. - // These errors have a `digest` property containing 'DYNAMIC_SERVER_USAGE' - // or a message about bailing out of prerendering. - if (e instanceof Error && ('digest' in e || /bail\s*out.*prerende/i.test(e.message))) { - throw e - } - } -} - -/** Reset cached state and optionally inject a headers function. Test use only. */ -export const resetNextjsState = (headersFn?: (() => unknown) | null): void => { - nextHeadersFn = headersFn === null ? null : (headersFn ?? undefined) -} diff --git a/packages/identity/prod/src/refresh.ts b/packages/identity/prod/src/refresh.ts deleted file mode 100644 index 28a5124..0000000 --- a/packages/identity/prod/src/refresh.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { getGoTrueClient, isBrowser, getIdentityContext, IDENTITY_PATH } from './environment.js' -import { - NF_JWT_COOKIE, - NF_REFRESH_COOKIE, - setBrowserAuthCookies, - setAuthCookies, - deleteAuthCookies, - getServerCookie, -} from './cookies.js' -import { decodeJwtPayload, toUser } from './user.js' -import { AUTH_EVENTS, emitAuthEvent } from './events.js' -import { AuthError } from './errors.js' -import { fetchWithTimeout } from './fetch.js' -import type { NetlifyCookies, TokenResponse, GoTrueErrorBody } from './types.js' - -/** Seconds before expiry to trigger a refresh. */ -const REFRESH_MARGIN_S = 60 - -let refreshTimer: ReturnType | null = null - -/** - * Starts a browser-side timer that refreshes the access token before it expires - * and syncs the new token back to the `nf_jwt` cookie. Automatically called by - * any browser flow that establishes a session (`login`, `signup`, - * `hydrateSession`, `handleAuthCallback`, `confirmEmail`, `recoverPassword`, - * `acceptInvite`) and by `getUser` when it finds an existing session. - * No-op on the server. - * - * Safe to call multiple times; restarts the timer with the current token's expiry. - */ -export const startTokenRefresh = (): void => { - if (!isBrowser()) return - stopTokenRefresh() - - const client = getGoTrueClient() - const user = client?.currentUser() - if (!user) return - - const token = user.tokenDetails() - if (!token?.expires_at) return - - const nowS = Math.floor(Date.now() / 1000) - const expiresAtS = - typeof token.expires_at === 'number' && token.expires_at > 1e12 - ? Math.floor(token.expires_at / 1000) // gotrue-js stores expires_at in ms - : token.expires_at - const delayMs = Math.max(0, expiresAtS - nowS - REFRESH_MARGIN_S) * 1000 - - refreshTimer = setTimeout(() => { - void (async () => { - try { - const freshJwt = await user.jwt(true) - const freshDetails = user.tokenDetails() - setBrowserAuthCookies(freshJwt, freshDetails?.refresh_token) - emitAuthEvent(AUTH_EVENTS.TOKEN_REFRESH, toUser(user)) - // Schedule next refresh - startTokenRefresh() - } catch { - // Refresh failed (e.g., refresh token revoked). Stop trying. - stopTokenRefresh() - } - })() - }, delayMs) -} - -/** - * Stops the browser-side auto-refresh timer. Automatically called by `logout`. - */ -export const stopTokenRefresh = (): void => { - if (refreshTimer !== null) { - clearTimeout(refreshTimer) - refreshTimer = null - } -} - -/** - * Refreshes the session's access token. - * - * **Browser:** Token refresh is handled automatically after any browser flow - * that establishes a session (`login`, `signup`, `hydrateSession`, - * `handleAuthCallback`, `confirmEmail`, `recoverPassword`, `acceptInvite`) - * and by `getUser` when it finds an existing session. Calling - * `refreshSession()` in the browser triggers an - * immediate refresh if the token is near expiry. Returns the new JWT on - * success, or `null` if no refresh is needed. Browser-side errors (e.g., - * revoked refresh token) do not throw; they return `null`. - * - * **Server:** Reads the `nf_jwt` and `nf_refresh` cookies, checks if the token - * is expired or near expiry, and exchanges the refresh token for a new access - * token via the Identity `/token` endpoint. Updates both cookies on the response. - * Call this in framework middleware or at the start of server-side request - * handlers to ensure subsequent requests carry a valid JWT. - * - * Returns the new access token on success, or `null` if no refresh is needed - * or the refresh token is invalid/missing (400/401). - * - * @throws {AuthError} Server-side only: on network failure or when the Identity URL cannot be determined. - * - * @example - * ```ts - * // In server middleware (e.g., Astro, SvelteKit) - * import { refreshSession } from '@netlify/identity' - * await refreshSession() - * ``` - */ -export const refreshSession = async (): Promise => { - if (isBrowser()) { - const client = getGoTrueClient() - const user = client?.currentUser() - if (!user) return null - - // Check if the token is near expiry before refreshing - const details = user.tokenDetails() - if (details?.expires_at) { - const nowS = Math.floor(Date.now() / 1000) - const expiresAtS = - typeof details.expires_at === 'number' && details.expires_at > 1e12 - ? Math.floor(details.expires_at / 1000) - : details.expires_at - if (expiresAtS - nowS > REFRESH_MARGIN_S) { - return null - } - } - - try { - const jwt = await user.jwt(true) - setBrowserAuthCookies(jwt, user.tokenDetails()?.refresh_token) - emitAuthEvent(AUTH_EVENTS.TOKEN_REFRESH, toUser(user)) - startTokenRefresh() - return jwt - } catch { - stopTokenRefresh() - return null - } - } - - // Server-side: read cookies, check expiry, refresh if needed - const accessToken = getServerCookie(NF_JWT_COOKIE) - const refreshToken = getServerCookie(NF_REFRESH_COOKIE) - - if (!accessToken || !refreshToken) return null - - const decoded = decodeJwtPayload(accessToken) - if (!decoded?.exp) return null - - const nowS = Math.floor(Date.now() / 1000) - if (decoded.exp - nowS > REFRESH_MARGIN_S) { - // Token is still valid, no refresh needed - return null - } - - // Token is expired or near expiry; exchange refresh token for new access token - const ctx = getIdentityContext() - const identityUrl = - ctx?.url ?? (globalThis.Netlify?.context?.url ? new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href : null) - - if (!identityUrl) { - throw new AuthError('Could not determine the Identity endpoint URL for token refresh') - } - - let res: Response - try { - res = await fetchWithTimeout(`${identityUrl}/token`, { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken }).toString(), - }) - } catch (error) { - throw AuthError.from(error) - } - - if (!res.ok) { - // Refresh token is invalid/expired; cannot refresh - const errorBody = (await res.json().catch(() => ({}))) as GoTrueErrorBody - if (res.status === 401 || res.status === 400) { - // Invalid refresh token; clear stale cookies so middleware stops retrying - const cookies = globalThis.Netlify?.context?.cookies as NetlifyCookies | undefined - if (cookies) { - deleteAuthCookies(cookies) - } - return null - } - throw new AuthError(errorBody.msg ?? `Token refresh failed (${String(res.status)})`, res.status) - } - - const data = (await res.json()) as TokenResponse - - const cookies = globalThis.Netlify?.context?.cookies as NetlifyCookies | undefined - if (cookies) { - setAuthCookies(cookies, data.access_token, data.refresh_token) - } - - return data.access_token -} diff --git a/packages/identity/prod/src/types.ts b/packages/identity/prod/src/types.ts deleted file mode 100644 index 94de036..0000000 --- a/packages/identity/prod/src/types.ts +++ /dev/null @@ -1,167 +0,0 @@ -/** The supported OAuth and authentication providers. */ -export const AUTH_PROVIDERS = ['google', 'github', 'gitlab', 'bitbucket', 'facebook', 'email'] as const - -/** A supported authentication provider name (e.g., `'google'`, `'github'`, `'email'`). */ -export type AuthProvider = (typeof AUTH_PROVIDERS)[number] - -/** - * Provider and role metadata stored in a user's `app_metadata` field. - * The `provider` field is set automatically on signup; `roles` controls authorization. - * Additional keys may be present depending on your Identity configuration. - * - * @example - * ```ts - * const meta: AppMetadata = { - * provider: 'github', - * roles: ['admin'], - * custom_claim: 'value', - * } - * ``` - */ -export interface AppMetadata { - provider: AuthProvider - roles?: string[] - [key: string]: unknown -} - -/** - * Identity endpoint configuration for the current environment. - * In the browser, `url` is derived from `window.location.origin`. - * On the server, `token` is the operator token for admin operations. - */ -export interface IdentityConfig { - /** The Identity API endpoint URL (e.g., `https://example.com/.netlify/identity`). */ - url: string - /** Operator token for server-side admin requests. Only available in Netlify Functions. */ - token?: string -} - -/** - * Project-level Identity settings returned by {@link getSettings}. - * Reflects the configuration in your Netlify dashboard. - */ -export interface Settings { - /** Whether new signups are auto-confirmed (no confirmation email sent). */ - autoconfirm: boolean - /** Whether new signups are disabled entirely. */ - disableSignup: boolean - /** Map of provider names to whether they are enabled. */ - providers: Record -} - -/** - * Fields accepted by {@link updateUser}. All fields are optional. - * Pass `data` to update user metadata (e.g., `{ data: { full_name: 'New Name' } }`). - * - * @example - * ```ts - * await updateUser({ data: { full_name: 'Jane Doe' } }) - * await updateUser({ email: 'new@example.com' }) - * await updateUser({ password: 'new-password' }) - * ``` - */ -export interface UserUpdates { - email?: string - password?: string - data?: Record - [key: string]: unknown -} - -/** - * User metadata passed during signup (e.g., `{ full_name: 'Jane Doe' }`). - * Stored in the user's `user_metadata` field. - */ -export type SignupData = Record - -/** OAuth2 token response from the Identity /token endpoint. */ -export interface TokenResponse { - access_token: string - token_type: string - expires_in: number - refresh_token?: string -} - -/** - * Fields accepted by {@link admin.updateUser}. All fields are optional. - * - * Unlike {@link UserUpdates} (used by the self-service `updateUser`), admin updates - * can set `role`, force-confirm a user, and write to `app_metadata`. - * - * @example - * ```ts - * await admin.updateUser(userId, { - * role: 'editor', - * confirm: true, - * app_metadata: { plan: 'pro' }, - * }) - * ``` - */ -export interface AdminUserUpdates { - email?: string - password?: string - /** The user's role (e.g., `'admin'`, `'editor'`). */ - role?: string - /** Set to `true` to force-confirm the user's email without sending a confirmation email. */ - confirm?: boolean - /** Server-managed metadata. Only writable via admin operations. */ - app_metadata?: Record - /** User-managed metadata (display name, avatar, preferences, etc.). */ - user_metadata?: Record -} - -/** Identity API error response body. */ -export interface GoTrueErrorBody { - msg?: string - error_description?: string -} - -/** - * Pagination options for {@link admin.listUsers}. - */ -export interface ListUsersOptions { - /** 1-based page number. */ - page?: number - /** Number of users per page. */ - perPage?: number -} - -/** - * Parameters for {@link admin.createUser}. - * - * The optional `data` fields are forwarded as top-level attributes in the Identity API - * request body. Only these keys are accepted: `role`, `app_metadata`, - * `user_metadata`. Any other keys are silently ignored. `data` cannot override - * `email`, `password`, or `confirm`. - * - * @example - * ```ts - * await admin.createUser({ - * email: 'jane@example.com', - * password: 'secret', - * data: { role: 'editor', user_metadata: { full_name: 'Jane Doe' } }, - * }) - * ``` - */ -export interface CreateUserParams { - email: string - password: string - /** Identity user fields: `role`, `app_metadata`, `user_metadata`. Other keys are ignored. */ - data?: Record -} - -/** - * Cookie interface provided by the Netlify Functions runtime. - * Used internally for server-side auth cookie management. - */ -export interface NetlifyCookies { - get(name: string): string | undefined - set(options: { - name: string - value: string - httpOnly: boolean - secure: boolean - path: string - sameSite: 'Strict' | 'Lax' | 'None' - }): void - delete(name: string): void -} diff --git a/packages/identity/prod/src/user.ts b/packages/identity/prod/src/user.ts deleted file mode 100644 index bab8eb2..0000000 --- a/packages/identity/prod/src/user.ts +++ /dev/null @@ -1,274 +0,0 @@ -import type { UserData } from 'gotrue-js' -import { AUTH_PROVIDERS, type AuthProvider } from './types.js' -import { getGoTrueClient, getIdentityContext, isBrowser, IDENTITY_PATH } from './environment.js' -import { getCookie, getServerCookie, NF_JWT_COOKIE } from './cookies.js' -import { triggerNextjsDynamic } from './nextjs.js' -import { fetchWithTimeout } from './fetch.js' -import { hydrateSession } from './auth.js' -import { startTokenRefresh } from './refresh.js' - -/** Decoded JWT claims from the Identity token. Used internally to construct {@link User}. */ -export interface IdentityUser { - sub?: string - email?: string - exp?: number - app_metadata?: Record - user_metadata?: Record - [key: string]: unknown -} - -const toAuthProvider = (value: unknown): AuthProvider | undefined => - typeof value === 'string' && (AUTH_PROVIDERS as readonly string[]).includes(value) - ? (value as AuthProvider) - : undefined - -const toOptionalString = (value: unknown): string | undefined => - typeof value === 'string' && value !== '' ? value : undefined - -const toRoles = (appMeta: Record): string[] | undefined => { - const roles = appMeta.roles - if (Array.isArray(roles) && roles.every((r) => typeof r === 'string')) { - return roles - } - return undefined -} - -/** - * A normalized user object returned by all auth and admin functions. - * Provides a consistent shape regardless of whether the user was loaded - * from the Identity API, a JWT cookie, or the server-side identity context. - * - * All fields except `id` are optional and may be `undefined`. Empty strings - * are normalized to `undefined`. State-dependent fields (invite, - * recovery, email-change) are only present when the user is in that state. - * - * @example - * ```ts - * const user = await getUser() - * if (user) { - * console.log(user.email, user.name, user.roles) - * } - * ``` - */ -export interface User { - /** The user's unique identifier. */ - id: string - /** The user's email address. */ - email?: string - /** ISO 8601 timestamp of when the user's email was confirmed. `undefined` if not yet confirmed. */ - confirmedAt?: string - /** ISO 8601 timestamp of when the account was created. */ - createdAt?: string - /** ISO 8601 timestamp of the last account update. */ - updatedAt?: string - /** - * The account-level role string (e.g., `"admin"`). This is a single value - * set via the admin API, distinct from `roles` which is an array in `app_metadata`. - * `undefined` when not set or empty. - */ - role?: string - /** The authentication provider used to create the account (from `app_metadata.provider`). */ - provider?: AuthProvider - /** Display name from `user_metadata.full_name` or `user_metadata.name`. */ - name?: string - /** Avatar URL from `user_metadata.avatar_url`. */ - pictureUrl?: string - /** Application-level roles from `app_metadata.roles`, set via the admin API or Netlify UI. */ - roles?: string[] - /** ISO 8601 timestamp of when the user was invited. Only present if the user was created via invitation. */ - invitedAt?: string - /** ISO 8601 timestamp of when the confirmation email was last sent. */ - confirmationSentAt?: string - /** ISO 8601 timestamp of when the recovery email was last sent. */ - recoverySentAt?: string - /** The pending email address during an email change flow. Only present while the change is awaiting confirmation. */ - pendingEmail?: string - /** ISO 8601 timestamp of when the email change verification was last sent. */ - emailChangeSentAt?: string - /** ISO 8601 timestamp of the user's most recent sign-in. */ - lastSignInAt?: string - /** Custom user metadata. Contains profile data like `full_name` and `avatar_url`, and any custom fields set via `updateUser()`. */ - userMetadata?: Record - /** Application metadata managed by the server. Contains `provider`, `roles`, and other system-managed fields. */ - appMetadata?: Record -} - -export const toUser = (userData: UserData): User => { - const userMeta = userData.user_metadata ?? {} - const appMeta = userData.app_metadata ?? {} - const name = userMeta.full_name ?? userMeta.name - const pictureUrl = userMeta.avatar_url - - return { - id: userData.id, - email: userData.email, - confirmedAt: toOptionalString(userData.confirmed_at), - createdAt: userData.created_at, - updatedAt: userData.updated_at, - role: toOptionalString(userData.role), - provider: toAuthProvider(appMeta.provider), - name: typeof name === 'string' ? name : undefined, - pictureUrl: typeof pictureUrl === 'string' ? pictureUrl : undefined, - roles: toRoles(appMeta), - invitedAt: toOptionalString(userData.invited_at), - confirmationSentAt: toOptionalString(userData.confirmation_sent_at), - recoverySentAt: toOptionalString(userData.recovery_sent_at), - pendingEmail: toOptionalString(userData.new_email), - emailChangeSentAt: toOptionalString(userData.email_change_sent_at), - lastSignInAt: toOptionalString(userData.last_sign_in_at), - userMetadata: userMeta, - appMetadata: appMeta, - } -} - -/** - * Converts JWT claims into a User. Used as a fallback when the full user - * object is unavailable (e.g., Identity API is unreachable on the server). - * - * JWT claims only contain `sub`, `email`, `exp`, `app_metadata`, and - * `user_metadata`. All other User fields like timestamps, aud, role, etc. - * will be `undefined`. - */ -const claimsToUser = (claims: IdentityUser): User => { - const appMeta = claims.app_metadata ?? {} - const userMeta = claims.user_metadata ?? {} - const name = userMeta.full_name ?? userMeta.name - const pictureUrl = userMeta.avatar_url - - return { - id: claims.sub ?? '', - email: claims.email, - provider: toAuthProvider(appMeta.provider), - name: typeof name === 'string' ? name : undefined, - pictureUrl: typeof pictureUrl === 'string' ? pictureUrl : undefined, - roles: toRoles(appMeta), - userMetadata: userMeta, - appMetadata: appMeta, - } -} - -/** Decodes a JWT payload without verifying the signature. */ -export const decodeJwtPayload = (token: string): IdentityUser | null => { - try { - const parts = token.split('.') - if (parts.length !== 3) return null - const payload = atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')) - return JSON.parse(payload) as IdentityUser - } catch { - return null - } -} - -/** - * Fetches the full user object from the Identity API using the JWT. - * Returns null if the fetch fails (API unreachable, invalid token, etc.). - */ -const fetchFullUser = async (identityUrl: string, jwt: string): Promise => { - try { - const res = await fetchWithTimeout(`${identityUrl}/user`, { - headers: { Authorization: `Bearer ${jwt}` }, - }) - if (!res.ok) return null - const userData = (await res.json()) as UserData - return toUser(userData) - } catch { - return null - } -} - -/** - * Resolves the Identity URL from available sources, or null if not discoverable. - */ -const resolveIdentityUrl = (): string | null => { - const identityContext = getIdentityContext() - if (identityContext?.url) return identityContext.url - - if (globalThis.Netlify?.context?.url) { - return new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href - } - - const siteUrl = typeof process !== 'undefined' ? process.env?.URL : undefined - if (siteUrl) { - return new URL(IDENTITY_PATH, siteUrl).href - } - - return null -} - -/** - * Returns the currently authenticated user, or `null` if not logged in. - * Never throws; returns `null` on any failure. - * - * Always returns a full {@link User} object with all available fields - * (email, roles, timestamps, metadata, etc.) regardless of whether the - * call happens in the browser or on the server. - * - * In the browser, checks localStorage first. If no localStorage - * session exists, hydrates from the `nf_jwt` cookie (set by server-side login). - * - * On the server, fetches the full user from the Identity API using the JWT from - * the request. Falls back to JWT claims if the Identity API is unreachable. - * - * On the server in a Next.js App Router context, calls `headers()` from - * `next/headers` to opt the route into dynamic rendering. Without this, - * Next.js may statically cache the page at build time. - */ -export const getUser = async (): Promise => { - if (isBrowser()) { - const client = getGoTrueClient() - const currentUser = client?.currentUser() ?? null - - if (currentUser) { - // If gotrue-js has a localStorage session but the nf_jwt cookie is gone, - // the server logged us out. Clear the stale localStorage session. - const jwt = getCookie(NF_JWT_COOKIE) - if (!jwt) { - try { - currentUser.clearSession() - } catch { - // best-effort cleanup - } - return null - } - startTokenRefresh() - return toUser(currentUser) - } - - // No gotrue-js session but cookie exists: hydrate to get the full user - const jwt = getCookie(NF_JWT_COOKIE) - if (!jwt) return null - - // Verify the cookie contains a decodable JWT before attempting hydration - const claims = decodeJwtPayload(jwt) - if (!claims) return null - - const hydrated = await hydrateSession() - return hydrated ?? null - } - - // Trigger Next.js dynamic rendering if in a Next.js RSC context - triggerNextjsDynamic() - - // Get the JWT from the identity context header or cookie - const identityContext = globalThis.netlifyIdentityContext - const serverJwt = identityContext?.token ?? getServerCookie(NF_JWT_COOKIE) - - // Try to fetch the full user from GoTrue for a complete User object - if (serverJwt) { - const identityUrl = resolveIdentityUrl() - if (identityUrl) { - const fullUser = await fetchFullUser(identityUrl, serverJwt) - if (fullUser) return fullUser - } - } - - // Fallback: only use server-validated identity context, never decode an unverified cookie - const claims = identityContext?.user ?? null - return claims ? claimsToUser(claims) : null -} - -/** - * Returns `true` if a user is currently authenticated. - * Never throws; returns `false` on any failure. - */ -export const isAuthenticated = async (): Promise => (await getUser()) !== null diff --git a/packages/identity/prod/test/account.browser.test.ts b/packages/identity/prod/test/account.browser.test.ts deleted file mode 100644 index b0fc67c..0000000 --- a/packages/identity/prod/test/account.browser.test.ts +++ /dev/null @@ -1,263 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser, clearBrowserAuthCookies } from './fixtures.js' - -const mockRequestPasswordRecovery = vi.fn() -const mockRecover = vi.fn() -const mockConfirm = vi.fn() -const mockAcceptInvite = vi.fn() -const mockCurrentUser = vi.fn() -const mockUpdate = vi.fn() -const mockJwt = vi.fn() -const mockCreateUser = vi.fn() - -vi.mock('gotrue-js', () => ({ - default: class MockGoTrue { - requestPasswordRecovery = mockRequestPasswordRecovery - recover = mockRecover - confirm = mockConfirm - acceptInvite = mockAcceptInvite - currentUser = mockCurrentUser - createUser = mockCreateUser - }, -})) - -const gotrueUserWithUpdate = (overrides = {}) => { - const user = makeGoTrueUser(overrides) - return { ...user, update: mockUpdate } -} - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - clearBrowserAuthCookies() -}) - -describe('requestPasswordRecovery', () => { - it('calls client.requestPasswordRecovery', async () => { - const { requestPasswordRecovery } = await import('../src/account.js') - mockRequestPasswordRecovery.mockResolvedValue(undefined) - - await requestPasswordRecovery('jane@example.com') - - expect(mockRequestPasswordRecovery).toHaveBeenCalledWith('jane@example.com') - }) -}) - -describe('recoverPassword', () => { - it('recovers the token then updates the password', async () => { - const { recoverPassword } = await import('../src/account.js') - const recoveredUser = gotrueUserWithUpdate() - mockRecover.mockResolvedValue(recoveredUser) - mockUpdate.mockResolvedValue(makeGoTrueUser()) - - const user = await recoverPassword('recovery-token', 'new-password') - - expect(mockRecover).toHaveBeenCalledWith('recovery-token', true) - expect(mockUpdate).toHaveBeenCalledWith({ password: 'new-password' }) - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('emits a login event', async () => { - const { recoverPassword } = await import('../src/account.js') - const { onAuthChange } = await import('../src/events.js') - mockRecover.mockResolvedValue(gotrueUserWithUpdate()) - mockUpdate.mockResolvedValue(makeGoTrueUser()) - - const cb = vi.fn() - onAuthChange(cb) - await recoverPassword('recovery-token', 'new-password') - - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) -}) - -describe('confirmEmail', () => { - it('confirms the token and returns a user', async () => { - const { confirmEmail } = await import('../src/account.js') - mockConfirm.mockResolvedValue(makeGoTrueUser()) - - const user = await confirmEmail('confirm-token') - - expect(mockConfirm).toHaveBeenCalledWith('confirm-token', true) - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('emits a login event', async () => { - const { confirmEmail } = await import('../src/account.js') - const { onAuthChange } = await import('../src/events.js') - mockConfirm.mockResolvedValue(makeGoTrueUser()) - - const cb = vi.fn() - onAuthChange(cb) - await confirmEmail('confirm-token') - - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) -}) - -describe('acceptInvite', () => { - it('accepts the invite with a password', async () => { - const { acceptInvite } = await import('../src/account.js') - mockAcceptInvite.mockResolvedValue(makeGoTrueUser()) - - const user = await acceptInvite('invite-token', 'my-password') - - expect(mockAcceptInvite).toHaveBeenCalledWith('invite-token', 'my-password', true) - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('emits a login event', async () => { - const { acceptInvite } = await import('../src/account.js') - const { onAuthChange } = await import('../src/events.js') - mockAcceptInvite.mockResolvedValue(makeGoTrueUser()) - - const cb = vi.fn() - onAuthChange(cb) - await acceptInvite('invite-token', 'my-password') - - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) -}) - -describe('verifyEmailChange', () => { - it('calls PUT /user with email_change_token', async () => { - const { verifyEmailChange } = await import('../src/account.js') - const userData = makeGoTrueUser() - mockCurrentUser.mockReturnValue({ jwt: mockJwt }) - mockJwt.mockResolvedValue('test-jwt-token') - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(userData), - }), - ) - - const user = await verifyEmailChange('change-token') - - expect(fetch).toHaveBeenCalledWith( - expect.stringContaining('/.netlify/identity/user'), - expect.objectContaining({ - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Authorization: 'Bearer test-jwt-token', - }, - body: JSON.stringify({ email_change_token: 'change-token' }), - }), - ) - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('emits a user_updated event', async () => { - const { verifyEmailChange } = await import('../src/account.js') - const { onAuthChange } = await import('../src/events.js') - mockCurrentUser.mockReturnValue({ jwt: mockJwt }) - mockJwt.mockResolvedValue('test-jwt-token') - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const cb = vi.fn() - onAuthChange(cb) - await verifyEmailChange('change-token') - - expect(cb).toHaveBeenCalledWith( - 'user_updated', - expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - ) - }) - - it('throws AuthError when no user is logged in', async () => { - const { verifyEmailChange } = await import('../src/account.js') - const { AuthError } = await import('../src/errors.js') - mockCurrentUser.mockReturnValue(null) - - const error = await verifyEmailChange('change-token').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('No user is currently logged in') - }) -}) - -describe('updateUser', () => { - it('updates the current user', async () => { - const { updateUser } = await import('../src/account.js') - mockCurrentUser.mockReturnValue(gotrueUserWithUpdate()) - mockUpdate.mockResolvedValue(makeGoTrueUser({ user_metadata: { full_name: 'New Name' } })) - - const user = await updateUser({ data: { full_name: 'New Name' } }) - - expect(mockUpdate).toHaveBeenCalledWith({ data: { full_name: 'New Name' } }) - expect(user.name).toBe('New Name') - }) - - it('emits a user_updated event', async () => { - const { updateUser } = await import('../src/account.js') - const { onAuthChange } = await import('../src/events.js') - mockCurrentUser.mockReturnValue(gotrueUserWithUpdate()) - mockUpdate.mockResolvedValue(makeGoTrueUser()) - - const cb = vi.fn() - onAuthChange(cb) - await updateUser({ data: { full_name: 'New Name' } }) - - expect(cb).toHaveBeenCalledWith( - 'user_updated', - expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - ) - }) - - it('throws AuthError when no user is logged in', async () => { - const { updateUser } = await import('../src/account.js') - const { AuthError } = await import('../src/errors.js') - mockCurrentUser.mockReturnValue(null) - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - - const error = await updateUser({ data: { full_name: 'New Name' } }).catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('No user is currently logged in') - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - }) - - it('auto-hydrates from cookies when no session but cookies exist', async () => { - const { updateUser } = await import('../src/account.js') - - const hydratedUser = gotrueUserWithUpdate() - mockCurrentUser - .mockReturnValueOnce(null) // first check: no session - .mockReturnValueOnce(null) // hydrateSession internal check - .mockReturnValueOnce(hydratedUser) // after hydration - .mockReturnValueOnce(hydratedUser) // startTokenRefresh reads currentUser - mockCreateUser.mockResolvedValue(makeGoTrueUser()) - mockUpdate.mockResolvedValue(makeGoTrueUser({ user_metadata: { full_name: 'New Name' } })) - - Object.defineProperty(document, 'cookie', { - writable: true, - value: 'nf_jwt=test-access-token; nf_refresh=test-refresh-token', - }) - - const user = await updateUser({ data: { full_name: 'New Name' } }) - - expect(mockCreateUser).toHaveBeenCalled() - expect(mockUpdate).toHaveBeenCalledWith({ data: { full_name: 'New Name' } }) - expect(user.name).toBe('New Name') - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - }) -}) diff --git a/packages/identity/prod/test/admin.browser.test.ts b/packages/identity/prod/test/admin.browser.test.ts deleted file mode 100644 index c0d2656..0000000 --- a/packages/identity/prod/test/admin.browser.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' - -vi.mock('gotrue-js', () => ({ - // eslint-disable-next-line @typescript-eslint/no-extraneous-class - default: class MockGoTrue {}, -})) - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() -}) - -describe('admin (browser)', () => { - it('admin.listUsers throws AuthError in the browser', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.listUsers().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('server-only') - }) - - it('admin.getUser throws AuthError in the browser', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('550e8400-e29b-41d4-a716-446655440000').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('server-only') - }) - - it('admin.createUser throws AuthError in the browser', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin - .createUser({ email: 'jane@example.com', password: 'password123' }) - .catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('server-only') - }) - - it('admin.updateUser throws AuthError in the browser', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin - .updateUser('550e8400-e29b-41d4-a716-446655440000', { email: 'new@example.com' }) - .catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('server-only') - }) - - it('admin.deleteUser throws AuthError in the browser', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.deleteUser('550e8400-e29b-41d4-a716-446655440000').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('server-only') - }) -}) diff --git a/packages/identity/prod/test/admin.server.test.ts b/packages/identity/prod/test/admin.server.test.ts deleted file mode 100644 index 784e5be..0000000 --- a/packages/identity/prod/test/admin.server.test.ts +++ /dev/null @@ -1,448 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser } from './fixtures.js' - -const IDENTITY_URL = 'https://example.netlify.app/.netlify/identity' -const OPERATOR_TOKEN = 'test-operator-token' - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - - globalThis.netlifyIdentityContext = { - url: IDENTITY_URL, - token: OPERATOR_TOKEN, - } -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - vi.unstubAllGlobals() - delete globalThis.netlifyIdentityContext -}) - -describe('admin.listUsers (server)', () => { - it('GETs /admin/users with operator token and returns User[]', async () => { - const users = [ - makeGoTrueUser(), - makeGoTrueUser({ id: '661e8400-e29b-41d4-a716-446655440001', email: 'bob@example.com' }), - ] - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve({ users }), - }), - ) - - const { admin } = await import('../src/admin.js') - const result = await admin.listUsers() - - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/admin/users`, - expect.objectContaining({ - headers: expect.objectContaining({ - Authorization: `Bearer ${OPERATOR_TOKEN}`, - 'Content-Type': 'application/json', - }), - }), - ) - - expect(result).toHaveLength(2) - expect(result[0].id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(result[1].id).toBe('661e8400-e29b-41d4-a716-446655440001') - }) - - it('appends pagination query params when provided', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve({ users: [] }), - }), - ) - - const { admin } = await import('../src/admin.js') - await admin.listUsers({ page: 2, perPage: 10 }) - - expect(fetch).toHaveBeenCalledWith(`${IDENTITY_URL}/admin/users?page=2&per_page=10`, expect.any(Object)) - }) - - it('throws AuthError on HTTP failure', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 403, - json: () => Promise.resolve({ msg: 'Forbidden' }), - }), - ) - - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.listUsers().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toBe('Forbidden') - expect((error as InstanceType).status).toBe(403) - }) -}) - -describe('admin.getUser (server)', () => { - it('GETs /admin/users/:id and returns User', async () => { - const userData = makeGoTrueUser() - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(userData), - }), - ) - - const { admin } = await import('../src/admin.js') - const result = await admin.getUser('550e8400-e29b-41d4-a716-446655440000') - - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/admin/users/550e8400-e29b-41d4-a716-446655440000`, - expect.objectContaining({ - headers: expect.objectContaining({ Authorization: `Bearer ${OPERATOR_TOKEN}` }), - }), - ) - expect(result.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(result.email).toBe('jane@example.com') - }) - - it('throws AuthError on 404', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 404, - json: () => Promise.resolve({ msg: 'User not found' }), - }), - ) - - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('00000000-0000-0000-0000-000000000000').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).status).toBe(404) - }) -}) - -describe('admin.createUser (server)', () => { - it('POSTs to /admin/users with JSON body and returns User', async () => { - const userData = makeGoTrueUser() - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(userData), - }), - ) - - const { admin } = await import('../src/admin.js') - const result = await admin.createUser({ - email: 'jane@example.com', - password: 'password123', - data: { role: 'editor', user_metadata: { full_name: 'Jane Doe' } }, - }) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = JSON.parse(callArgs[1]?.body as string) - expect(body).toEqual({ - email: 'jane@example.com', - password: 'password123', - role: 'editor', - user_metadata: { full_name: 'Jane Doe' }, - confirm: true, - }) - - expect(result.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('works without optional data parameter', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const { admin } = await import('../src/admin.js') - await admin.createUser({ email: 'jane@example.com', password: 'password123' }) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = JSON.parse(callArgs[1]?.body as string) - expect(body).toEqual({ - email: 'jane@example.com', - password: 'password123', - confirm: true, - }) - }) - - it('does not allow data to override email, password, or confirm', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const { admin } = await import('../src/admin.js') - await admin.createUser({ - email: 'jane@example.com', - password: 'password123', - data: { email: 'attacker@evil.com', password: 'hacked', confirm: false }, - }) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = JSON.parse(callArgs[1]?.body as string) - expect(body.email).toBe('jane@example.com') - expect(body.password).toBe('password123') - expect(body.confirm).toBe(true) - }) - - it('silently ignores unrecognized keys in data', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const { admin } = await import('../src/admin.js') - await admin.createUser({ - email: 'jane@example.com', - password: 'password123', - data: { full_name: 'Jane Doe', arbitrary_field: 'ignored' }, - }) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = JSON.parse(callArgs[1]?.body as string) - expect(body).toEqual({ - email: 'jane@example.com', - password: 'password123', - confirm: true, - }) - }) - - it('forwards all allowed GoTrue fields from data', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const { admin } = await import('../src/admin.js') - await admin.createUser({ - email: 'jane@example.com', - password: 'password123', - data: { - role: 'editor', - app_metadata: { plan: 'pro' }, - user_metadata: { full_name: 'Jane Doe' }, - }, - }) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = JSON.parse(callArgs[1]?.body as string) - expect(body).toEqual({ - email: 'jane@example.com', - password: 'password123', - confirm: true, - role: 'editor', - app_metadata: { plan: 'pro' }, - user_metadata: { full_name: 'Jane Doe' }, - }) - }) -}) - -describe('admin.updateUser (server)', () => { - it('PUTs to /admin/users/:id with attributes and returns User', async () => { - const userData = makeGoTrueUser({ email: 'updated@example.com' }) - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(userData), - }), - ) - - const { admin } = await import('../src/admin.js') - const result = await admin.updateUser('550e8400-e29b-41d4-a716-446655440000', { email: 'updated@example.com' }) - - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/admin/users/550e8400-e29b-41d4-a716-446655440000`, - expect.objectContaining({ method: 'PUT' }), - ) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = JSON.parse(callArgs[1]?.body as string) - expect(body).toEqual({ email: 'updated@example.com' }) - - expect(result.email).toBe('updated@example.com') - }) -}) - -describe('admin.deleteUser (server)', () => { - it('DELETEs /admin/users/:id and returns void', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve({}), - }), - ) - - const { admin } = await import('../src/admin.js') - await admin.deleteUser('550e8400-e29b-41d4-a716-446655440000') - - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/admin/users/550e8400-e29b-41d4-a716-446655440000`, - expect.objectContaining({ method: 'DELETE' }), - ) - }) - - it('throws AuthError on failure', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 500, - json: () => Promise.resolve({ msg: 'Internal error' }), - }), - ) - - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.deleteUser('550e8400-e29b-41d4-a716-446655440000').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).status).toBe(500) - }) -}) - -describe('admin error handling (server)', () => { - it('throws AuthError when operator token is missing', async () => { - globalThis.netlifyIdentityContext = { url: IDENTITY_URL } - - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.listUsers().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('operator token') - }) - - it('throws AuthError when identity URL is missing', async () => { - delete globalThis.netlifyIdentityContext - - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('550e8400-e29b-41d4-a716-446655440000').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('Identity endpoint URL') - }) - - it('throws AuthError when fetch itself fails', async () => { - vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('Network error'))) - - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.listUsers().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toBe('Network error') - }) - - it('uses fallback message when error response has no msg field', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 502, - json: () => Promise.resolve({}), - }), - ) - - const { admin } = await import('../src/admin.js') - - const error = (await admin.listUsers().catch((e: unknown) => e)) as Error - expect(error.message).toBe('Admin request failed (502)') - }) -}) - -describe('userId validation (sanitizeUserId)', () => { - it('accepts a valid lowercase UUID', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const { admin } = await import('../src/admin.js') - const result = await admin.getUser('550e8400-e29b-41d4-a716-446655440000') - - expect(result.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('accepts a valid uppercase UUID', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(makeGoTrueUser()), - }), - ) - - const { admin } = await import('../src/admin.js') - const result = await admin.getUser('550E8400-E29B-41D4-A716-446655440000') - - expect(result.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('rejects path traversal strings', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('../../settings').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('not a valid UUID') - }) - - it('rejects an empty string', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect((error as InstanceType).message).toContain('not a valid UUID') - }) - - it('rejects a UUID with extra characters appended', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('550e8400-e29b-41d4-a716-446655440000-extra').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - }) - - it('rejects a non-hex string in UUID format', async () => { - const { admin } = await import('../src/admin.js') - const { AuthError } = await import('../src/errors.js') - - const error = await admin.getUser('zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - }) -}) diff --git a/packages/identity/prod/test/auth.browser.test.ts b/packages/identity/prod/test/auth.browser.test.ts deleted file mode 100644 index abec6b5..0000000 --- a/packages/identity/prod/test/auth.browser.test.ts +++ /dev/null @@ -1,594 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser, clearBrowserAuthCookies } from './fixtures.js' - -const mockLogin = vi.fn() -const mockSignup = vi.fn() -const mockLogout = vi.fn() -const mockUpdate = vi.fn() -const mockCurrentUser = vi.fn() -const mockLoginExternalUrl = vi.fn() -const mockCreateUser = vi.fn() -const mockConfirm = vi.fn() -const mockRecover = vi.fn() -const mockJwt = vi.fn() - -vi.mock('gotrue-js', () => ({ - default: class MockGoTrue { - login = mockLogin - signup = mockSignup - currentUser = mockCurrentUser - loginExternalUrl = mockLoginExternalUrl - createUser = mockCreateUser - confirm = mockConfirm - recover = mockRecover - }, -})) - -const mockTokenDetails = { - access_token: 'test-jwt-token', - refresh_token: 'test-refresh-token', - expires_in: 3600, - expires_at: Math.floor(Date.now() / 1000) + 3600, -} - -const gotrueUserWithJwt = (overrides = {}) => { - const user = makeGoTrueUser(overrides) - return { ...user, jwt: mockJwt, tokenDetails: () => mockTokenDetails } -} - -const gotrueUserWithMethods = (overrides = {}) => { - const user = makeGoTrueUser(overrides) - return { ...user, logout: mockLogout, update: mockUpdate, jwt: mockJwt, tokenDetails: () => mockTokenDetails } -} - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - mockJwt.mockResolvedValue('test-jwt-token') -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - window.location.hash = '' - clearBrowserAuthCookies() -}) - -describe('login', () => { - it('returns a normalized User', async () => { - const { login } = await import('../src/auth.js') - mockLogin.mockResolvedValue(gotrueUserWithJwt()) - - const user = await login('jane@example.com', 'password123') - - expect(mockLogin).toHaveBeenCalledWith('jane@example.com', 'password123', true) - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - expect(user.provider).toBe('github') - }) - - it('emits a login event', async () => { - const { login } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockLogin.mockResolvedValue(gotrueUserWithJwt()) - - const cb = vi.fn() - onAuthChange(cb) - await login('jane@example.com', 'password123') - - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) - - it('wraps gotrue-js errors in AuthError', async () => { - const { login } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - mockLogin.mockRejectedValue(new Error('Invalid credentials')) - - const error = await login('jane@example.com', 'wrong').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Invalid credentials') - }) -}) - -describe('signup', () => { - it('returns a normalized User', async () => { - const { signup } = await import('../src/auth.js') - mockSignup.mockResolvedValue(makeGoTrueUser()) - - const user = await signup('jane@example.com', 'password123') - - expect(mockSignup).toHaveBeenCalledWith('jane@example.com', 'password123', undefined) - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - }) - - it('passes user data to gotrue-js', async () => { - const { signup } = await import('../src/auth.js') - mockSignup.mockResolvedValue(makeGoTrueUser()) - - await signup('jane@example.com', 'password123', { full_name: 'Jane Doe' }) - - expect(mockSignup).toHaveBeenCalledWith('jane@example.com', 'password123', { - full_name: 'Jane Doe', - }) - }) - - it('emits login event when autoconfirm is on', async () => { - const { signup } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockSignup.mockResolvedValue(makeGoTrueUser({ confirmed_at: '2026-01-01T00:00:00Z' })) - - const cb = vi.fn() - onAuthChange(cb) - await signup('jane@example.com', 'password123') - - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) - - it('sets nf_jwt cookie when autoconfirm is on', async () => { - const { signup } = await import('../src/auth.js') - mockJwt.mockResolvedValue('autoconfirm-jwt-token') - mockSignup.mockResolvedValue({ - ...makeGoTrueUser({ confirmed_at: '2026-01-01T00:00:00Z' }), - jwt: mockJwt, - tokenDetails: () => ({ ...mockTokenDetails, access_token: 'autoconfirm-jwt-token' }), - }) - - await signup('jane@example.com', 'password123') - - expect(document.cookie).toContain('nf_jwt=autoconfirm-jwt-token') - }) - - it('does not set cookie when confirmation is required', async () => { - const { signup } = await import('../src/auth.js') - mockSignup.mockResolvedValue(makeGoTrueUser({ confirmed_at: null })) - - await signup('jane@example.com', 'password123') - - expect(document.cookie).not.toContain('nf_jwt') - }) - - it('does not emit login event when confirmation is required', async () => { - const { signup } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockSignup.mockResolvedValue(makeGoTrueUser({ confirmed_at: null })) - - const cb = vi.fn() - onAuthChange(cb) - await signup('jane@example.com', 'password123') - - expect(cb).not.toHaveBeenCalled() - }) -}) - -describe('logout', () => { - it('calls currentUser().logout()', async () => { - const { logout } = await import('../src/auth.js') - const mockUser = gotrueUserWithMethods() - mockCurrentUser.mockReturnValue(mockUser) - mockLogout.mockResolvedValue(undefined) - - await logout() - - expect(mockLogout).toHaveBeenCalled() - }) - - it('emits a logout event', async () => { - const { logout } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockCurrentUser.mockReturnValue(gotrueUserWithMethods()) - mockLogout.mockResolvedValue(undefined) - - const cb = vi.fn() - onAuthChange(cb) - await logout() - - expect(cb).toHaveBeenCalledWith('logout', null) - }) - - it('emits logout even when no current user', async () => { - const { logout } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockCurrentUser.mockReturnValue(null) - - const cb = vi.fn() - onAuthChange(cb) - await logout() - - expect(cb).toHaveBeenCalledWith('logout', null) - expect(mockLogout).not.toHaveBeenCalled() - }) -}) - -describe('oauthLogin', () => { - it('calls loginExternalUrl with the provider', async () => { - const { oauthLogin } = await import('../src/auth.js') - mockLoginExternalUrl.mockReturnValue('https://github.com/login/oauth/authorize?...') - - expect(() => oauthLogin('github')).toThrow('Redirecting to OAuth provider') - expect(mockLoginExternalUrl).toHaveBeenCalledWith('github') - }) -}) - -describe('onAuthChange', () => { - it('returns an unsubscribe function', async () => { - const { login } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockLogin.mockResolvedValue(gotrueUserWithJwt()) - - const cb = vi.fn() - const unsub = onAuthChange(cb) - - unsub() - await login('jane@example.com', 'password123') - - expect(cb).not.toHaveBeenCalled() - }) - - it('supports multiple subscribers', async () => { - const { login } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockLogin.mockResolvedValue(gotrueUserWithJwt()) - - const cb1 = vi.fn() - const cb2 = vi.fn() - onAuthChange(cb1) - onAuthChange(cb2) - await login('jane@example.com', 'password123') - - expect(cb1).toHaveBeenCalledOnce() - expect(cb2).toHaveBeenCalledOnce() - }) - - it('fires on cross-tab storage events', async () => { - const { onAuthChange } = await import('../src/events.js') - mockCurrentUser.mockReturnValue(makeGoTrueUser()) - - const cb = vi.fn() - onAuthChange(cb) - - window.dispatchEvent( - new StorageEvent('storage', { - key: 'gotrue.user', - newValue: '{"id":"550e8400-e29b-41d4-a716-446655440000"}', - }), - ) - - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) - - it('fires logout on cross-tab session removal', async () => { - const { onAuthChange } = await import('../src/events.js') - - const cb = vi.fn() - onAuthChange(cb) - - window.dispatchEvent( - new StorageEvent('storage', { - key: 'gotrue.user', - newValue: null, - }), - ) - - expect(cb).toHaveBeenCalledWith('logout', null) - }) - - it('ignores storage events for other keys', async () => { - const { onAuthChange } = await import('../src/events.js') - - const cb = vi.fn() - onAuthChange(cb) - - window.dispatchEvent( - new StorageEvent('storage', { - key: 'some-other-key', - newValue: 'whatever', - }), - ) - - expect(cb).not.toHaveBeenCalled() - }) - - it('continues notifying other listeners when one throws', async () => { - const { login } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockLogin.mockResolvedValue(gotrueUserWithJwt()) - - const throwingCb = vi.fn(() => { - throw new Error('subscriber error') - }) - const survivingCb = vi.fn() - onAuthChange(throwingCb) - onAuthChange(survivingCb) - await login('jane@example.com', 'password123') - - expect(throwingCb).toHaveBeenCalledOnce() - expect(survivingCb).toHaveBeenCalledWith( - 'login', - expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - ) - }) -}) - -describe('hydrateSession', () => { - it('reads cookies and calls createUser to hydrate the session', async () => { - const { hydrateSession } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockCurrentUser.mockReturnValue(null) - mockCreateUser.mockResolvedValue(makeGoTrueUser()) - - Object.defineProperty(document, 'cookie', { - writable: true, - value: 'nf_jwt=test-access-token; nf_refresh=test-refresh-token', - }) - - const cb = vi.fn() - onAuthChange(cb) - const user = await hydrateSession() - - expect(mockCreateUser).toHaveBeenCalledWith( - expect.objectContaining({ - access_token: 'test-access-token', - refresh_token: 'test-refresh-token', - token_type: 'bearer', - }), - true, - ) - expect(user).toEqual(expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - }) - - it('is a no-op when a session already exists', async () => { - const { hydrateSession } = await import('../src/auth.js') - mockCurrentUser.mockReturnValue(gotrueUserWithJwt()) - - const user = await hydrateSession() - - expect(mockCreateUser).not.toHaveBeenCalled() - expect(user).toEqual(expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) - - it('returns null when no cookies are present', async () => { - const { hydrateSession } = await import('../src/auth.js') - mockCurrentUser.mockReturnValue(null) - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - - const user = await hydrateSession() - - expect(mockCreateUser).not.toHaveBeenCalled() - expect(user).toBeNull() - }) - - it('uses fallback expiry when JWT payload is not decodable', async () => { - const { hydrateSession } = await import('../src/auth.js') - mockCurrentUser.mockReturnValue(null) - mockCreateUser.mockResolvedValue(makeGoTrueUser()) - - Object.defineProperty(document, 'cookie', { writable: true, value: 'nf_jwt=not-a-valid-jwt' }) - - await hydrateSession() - - expect(mockCreateUser).toHaveBeenCalledWith( - expect.objectContaining({ - access_token: 'not-a-valid-jwt', - token_type: 'bearer', - expires_in: expect.any(Number), - expires_at: expect.any(Number), - }), - true, - ) - const callArgs = mockCreateUser.mock.calls[0][0] - expect(callArgs.expires_in).toBeGreaterThan(0) - expect(callArgs.expires_in).toBeLessThanOrEqual(3600) - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - }) - - it('hydrates with empty refresh token when only nf_jwt is present', async () => { - const { hydrateSession } = await import('../src/auth.js') - mockCurrentUser.mockReturnValue(null) - mockCreateUser.mockResolvedValue(makeGoTrueUser()) - - Object.defineProperty(document, 'cookie', { writable: true, value: 'nf_jwt=test-access-token' }) - - await hydrateSession() - - expect(mockCreateUser).toHaveBeenCalledWith( - expect.objectContaining({ - access_token: 'test-access-token', - refresh_token: '', - }), - true, - ) - - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - }) -}) - -describe('handleAuthCallback', () => { - it('returns null when there is no hash', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - - const result = await handleAuthCallback() - expect(result).toBeNull() - }) - - it('handles OAuth access_token', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockCreateUser.mockResolvedValue(makeGoTrueUser()) - - window.location.hash = - '#access_token=test-token&token_type=bearer&expires_in=3600&expires_at=9999999999&refresh_token=refresh-123' - - const cb = vi.fn() - onAuthChange(cb) - const result = await handleAuthCallback() - - expect(result).toEqual({ - type: 'oauth', - user: expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - }) - expect(mockCreateUser).toHaveBeenCalledWith( - { - access_token: 'test-token', - token_type: 'bearer', - expires_in: 3600, - expires_at: 9999999999, - refresh_token: 'refresh-123', - }, - true, - ) - expect(cb).toHaveBeenCalledWith('login', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - expect(window.location.hash).toBe('') - }) - - it('handles confirmation_token', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - mockConfirm.mockResolvedValue(gotrueUserWithJwt()) - - window.location.hash = '#confirmation_token=confirm-abc' - - const result = await handleAuthCallback() - - expect(result).toEqual({ - type: 'confirmation', - user: expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - }) - expect(mockConfirm).toHaveBeenCalledWith('confirm-abc', true) - }) - - it('handles recovery_token', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - mockRecover.mockResolvedValue(gotrueUserWithJwt()) - - const cb = vi.fn() - onAuthChange(cb) - - window.location.hash = '#recovery_token=recover-abc' - - const result = await handleAuthCallback() - - expect(result).toEqual({ - type: 'recovery', - user: expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - }) - expect(mockRecover).toHaveBeenCalledWith('recover-abc', true) - expect(cb).toHaveBeenCalledWith('recovery', expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' })) - }) - - it('handles invite_token without completing the flow', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - - window.location.hash = '#invite_token=invite-abc' - - const result = await handleAuthCallback() - - expect(result).toEqual({ - type: 'invite', - user: null, - token: 'invite-abc', - }) - }) - - it('handles email_change_token by calling PUT /user', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - const { onAuthChange } = await import('../src/events.js') - const userData = makeGoTrueUser() - mockCurrentUser.mockReturnValue({ jwt: mockJwt }) - mockJwt.mockResolvedValue('test-jwt-token') - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(userData), - }), - ) - - window.location.hash = '#email_change_token=change-abc' - - const cb = vi.fn() - onAuthChange(cb) - const result = await handleAuthCallback() - - expect(result).toEqual({ - type: 'email_change', - user: expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - }) - expect(fetch).toHaveBeenCalledWith( - expect.stringContaining('/.netlify/identity/user'), - expect.objectContaining({ - method: 'PUT', - body: JSON.stringify({ email_change_token: 'change-abc' }), - }), - ) - expect(cb).toHaveBeenCalledWith( - 'user_updated', - expect.objectContaining({ id: '550e8400-e29b-41d4-a716-446655440000' }), - ) - }) - - it('throws AuthError when email_change API returns an error', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - mockCurrentUser.mockReturnValue({ jwt: mockJwt }) - mockJwt.mockResolvedValue('test-jwt-token') - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 422, - json: () => Promise.resolve({ msg: 'Invalid email change token' }), - }), - ) - - window.location.hash = '#email_change_token=bad-token' - - const error = await handleAuthCallback().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Invalid email change token') - expect(error.status).toBe(422) - }) - - it('throws AuthError for email_change_token when no session exists', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - mockCurrentUser.mockReturnValue(null) - - window.location.hash = '#email_change_token=change-abc' - - const error = await handleAuthCallback().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Email change verification requires an active browser session') - }) - - it('clears the URL hash after handling', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - mockConfirm.mockResolvedValue(gotrueUserWithJwt()) - - window.location.hash = '#confirmation_token=confirm-abc' - await handleAuthCallback() - - expect(window.location.hash).toBe('') - }) - - it('wraps errors in AuthError', async () => { - const { handleAuthCallback } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - mockConfirm.mockRejectedValue(new Error('Invalid token')) - - window.location.hash = '#confirmation_token=bad-token' - - const error = await handleAuthCallback().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Invalid token') - }) -}) diff --git a/packages/identity/prod/test/auth.server.test.ts b/packages/identity/prod/test/auth.server.test.ts deleted file mode 100644 index 8e5cd05..0000000 --- a/packages/identity/prod/test/auth.server.test.ts +++ /dev/null @@ -1,400 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser } from './fixtures.js' - -const mockCookies = { - get: vi.fn(), - set: vi.fn(), - delete: vi.fn(), -} - -const IDENTITY_URL = 'https://example.netlify.app/.netlify/identity' - -/** Builds a fake JWT (header.payload.signature) from claims. */ -const fakeJwt = (claims: Record): string => { - const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' })) - const payload = btoa(JSON.stringify(claims)) - return `${header}.${payload}.fake-signature` -} - -const TEST_JWT_CLAIMS = { - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - exp: Math.floor(Date.now() / 1000) + 3600, - app_metadata: { provider: 'github' }, - user_metadata: { full_name: 'Jane Doe' }, -} - -const TEST_ACCESS_TOKEN = fakeJwt(TEST_JWT_CLAIMS) - -const mockTokenResponse = () => ({ - access_token: TEST_ACCESS_TOKEN, - token_type: 'bearer', - expires_in: 3600, - refresh_token: 'test-refresh-token', -}) - -const mockGoTrueSignupResponse = (overrides: Record = {}) => { - const user = makeGoTrueUser() - return { ...user, ...overrides } -} - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - - globalThis.netlifyIdentityContext = { - url: IDENTITY_URL, - token: 'test-operator-token', - } - - globalThis.Netlify = { - context: { - cookies: mockCookies, - }, - } as unknown as typeof globalThis.Netlify -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - vi.unstubAllGlobals() - delete globalThis.netlifyIdentityContext - delete (globalThis as Record).Netlify -}) - -describe('login (server)', () => { - it('POSTs to /token then GETs /user and sets nf_jwt cookie', async () => { - const userData = makeGoTrueUser() - vi.stubGlobal( - 'fetch', - vi - .fn() - .mockResolvedValueOnce({ - ok: true, - json: () => Promise.resolve(mockTokenResponse()), - }) - .mockResolvedValueOnce({ - ok: true, - json: () => Promise.resolve(userData), - }), - ) - - const { login } = await import('../src/auth.js') - const user = await login('jane@example.com', 'password123') - - expect(fetch).toHaveBeenCalledTimes(2) - - expect(fetch).toHaveBeenNthCalledWith( - 1, - `${IDENTITY_URL}/token`, - expect.objectContaining({ - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - }), - ) - - const callArgs = vi.mocked(fetch).mock.calls[0] - const body = callArgs[1]?.body as string - expect(body).toContain('grant_type=password') - expect(body).toContain('username=jane%40example.com') - expect(body).toContain('password=password123') - - expect(fetch).toHaveBeenNthCalledWith( - 2, - `${IDENTITY_URL}/user`, - expect.objectContaining({ - headers: { Authorization: `Bearer ${TEST_ACCESS_TOKEN}` }, - }), - ) - - expect(mockCookies.set).toHaveBeenCalledWith({ - name: 'nf_jwt', - value: TEST_ACCESS_TOKEN, - httpOnly: false, - secure: true, - path: '/', - sameSite: 'Lax', - }) - - expect(mockCookies.set).toHaveBeenCalledWith({ - name: 'nf_refresh', - value: 'test-refresh-token', - httpOnly: false, - secure: true, - path: '/', - sameSite: 'Lax', - }) - - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - }) - - it('returns a User with real fields from the /user endpoint', async () => { - vi.stubGlobal( - 'fetch', - vi - .fn() - .mockResolvedValueOnce({ - ok: true, - json: () => Promise.resolve(mockTokenResponse()), - }) - .mockResolvedValueOnce({ - ok: true, - json: () => - Promise.resolve( - makeGoTrueUser({ - user_metadata: { full_name: 'Jane Doe', avatar_url: 'https://example.com/avatar.png' }, - }), - ), - }), - ) - - const { login } = await import('../src/auth.js') - const user = await login('jane@example.com', 'password123') - - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - expect(user.name).toBe('Jane Doe') - expect(user.pictureUrl).toBe('https://example.com/avatar.png') - expect(user.provider).toBe('github') - }) - - it('throws AuthError when /user fetch fails', async () => { - vi.stubGlobal( - 'fetch', - vi - .fn() - .mockResolvedValueOnce({ - ok: true, - json: () => Promise.resolve(mockTokenResponse()), - }) - .mockResolvedValueOnce({ - ok: false, - status: 401, - json: () => Promise.resolve({ msg: 'Invalid token' }), - }), - ) - - const { login } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - - const error = await login('jane@example.com', 'password123').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Invalid token') - expect(error.status).toBe(401) - }) - - it('throws AuthError with status on invalid credentials', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 401, - json: () => Promise.resolve({ msg: 'Invalid credentials' }), - }), - ) - - const { login } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - - const error = await login('jane@example.com', 'wrong').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Invalid credentials') - expect(error.status).toBe(401) - }) - - it('throws AuthError when fetch itself fails', async () => { - vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('Network error'))) - - const { login } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - - const error = await login('jane@example.com', 'password123').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Network error') - }) - - it('throws AuthError when Netlify.context.cookies is not available', async () => { - delete (globalThis as Record).Netlify - - const { login } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - - const error = await login('jane@example.com', 'password123').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Server-side auth requires Netlify Functions runtime') - }) -}) - -describe('signup (server)', () => { - it('POSTs to /signup with JSON body and returns normalized User', async () => { - const signupResponse = mockGoTrueSignupResponse({ confirmed_at: null }) - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(signupResponse), - }), - ) - - const { signup } = await import('../src/auth.js') - const user = await signup('jane@example.com', 'password123', { full_name: 'Jane Doe' }) - - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/signup`, - expect.objectContaining({ - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email: 'jane@example.com', password: 'password123', data: { full_name: 'Jane Doe' } }), - }), - ) - - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - expect(mockCookies.set).not.toHaveBeenCalled() - }) - - it('sets nf_jwt and nf_refresh cookies when autoconfirm is on', async () => { - const autoConfirmToken = fakeJwt(TEST_JWT_CLAIMS) - const signupResponse = mockGoTrueSignupResponse({ - confirmed_at: '2026-01-01T00:00:00Z', - access_token: autoConfirmToken, - refresh_token: 'auto-confirm-refresh', - }) - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(signupResponse), - }), - ) - - const { signup } = await import('../src/auth.js') - await signup('jane@example.com', 'password123') - - expect(mockCookies.set).toHaveBeenCalledWith( - expect.objectContaining({ - name: 'nf_jwt', - value: autoConfirmToken, - httpOnly: false, - }), - ) - expect(mockCookies.set).toHaveBeenCalledWith( - expect.objectContaining({ - name: 'nf_refresh', - value: 'auto-confirm-refresh', - httpOnly: false, - }), - ) - }) - - it('does not set cookie when autoconfirm is off', async () => { - const signupResponse = mockGoTrueSignupResponse({ confirmed_at: null }) - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(signupResponse), - }), - ) - - const { signup } = await import('../src/auth.js') - await signup('jane@example.com', 'password123') - - expect(mockCookies.set).not.toHaveBeenCalled() - }) - - it('does not set cookie when confirmed but no access_token', async () => { - const signupResponse = mockGoTrueSignupResponse({ - confirmed_at: '2026-01-01T00:00:00Z', - }) - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve(signupResponse), - }), - ) - - const { signup } = await import('../src/auth.js') - await signup('jane@example.com', 'password123') - - expect(mockCookies.set).not.toHaveBeenCalled() - }) - - it('throws AuthError on failure', async () => { - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValue({ - ok: false, - status: 422, - json: () => Promise.resolve({ msg: 'User already exists' }), - }), - ) - - const { signup } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - - const error = await signup('jane@example.com', 'password123').catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('User already exists') - expect(error.status).toBe(422) - }) -}) - -describe('logout (server)', () => { - it('POSTs to /logout with Bearer token and deletes both cookies', async () => { - mockCookies.get.mockReturnValue('existing-jwt-token') - vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true })) - - const { logout } = await import('../src/auth.js') - await logout() - - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/logout`, - expect.objectContaining({ - method: 'POST', - headers: { Authorization: 'Bearer existing-jwt-token' }, - }), - ) - - expect(mockCookies.delete).toHaveBeenCalledWith('nf_jwt') - expect(mockCookies.delete).toHaveBeenCalledWith('nf_refresh') - }) - - it('deletes both cookies even when no JWT exists (skip /logout call)', async () => { - mockCookies.get.mockReturnValue(undefined) - vi.stubGlobal('fetch', vi.fn()) - - const { logout } = await import('../src/auth.js') - await logout() - - expect(fetch).not.toHaveBeenCalled() - expect(mockCookies.delete).toHaveBeenCalledWith('nf_jwt') - expect(mockCookies.delete).toHaveBeenCalledWith('nf_refresh') - }) - - it('still deletes cookies when fetch fails', async () => { - mockCookies.get.mockReturnValue('existing-jwt-token') - vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('Network error'))) - - const { logout } = await import('../src/auth.js') - - await logout() - - expect(mockCookies.delete).toHaveBeenCalledWith('nf_jwt') - expect(mockCookies.delete).toHaveBeenCalledWith('nf_refresh') - }) - - it('throws AuthError when Netlify.context.cookies is not available', async () => { - delete (globalThis as Record).Netlify - - const { logout } = await import('../src/auth.js') - const { AuthError } = await import('../src/errors.js') - - const error = await logout().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Server-side auth requires Netlify Functions runtime') - }) -}) diff --git a/packages/identity/prod/test/config.browser.test.ts b/packages/identity/prod/test/config.browser.test.ts deleted file mode 100644 index 42578a4..0000000 --- a/packages/identity/prod/test/config.browser.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, afterEach } from 'vitest' -import { getIdentityConfig } from '../src/main.js' -import { resetTestGoTrueClient } from '../src/environment.js' - -describe('getIdentityConfig (browser)', () => { - afterEach(() => { - resetTestGoTrueClient() - }) - - it('returns config with URL from window origin', () => { - const config = getIdentityConfig() - if (!config) throw new Error('expected config to not be null') - expect(config.url).toContain('/.netlify/identity') - expect(config.token).toBeUndefined() - }) -}) diff --git a/packages/identity/prod/test/config.test.ts b/packages/identity/prod/test/config.test.ts deleted file mode 100644 index 9795fb0..0000000 --- a/packages/identity/prod/test/config.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' - -vi.mock('gotrue-js', () => { - const mockSettings = vi.fn() - return { - default: class MockGoTrue { - settings = mockSettings - }, - __mockSettings: mockSettings, - } -}) - -const getMockSettings = async () => { - const mod = await import('gotrue-js') - return (mod as unknown as { __mockSettings: ReturnType }).__mockSettings -} - -describe('getIdentityConfig (server)', () => { - beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - }) - - afterEach(() => { - delete globalThis.netlifyIdentityContext - delete globalThis.Netlify - resetTestGoTrueClient() - }) - - it('returns null outside Netlify environment', async () => { - const { getIdentityConfig } = await import('../src/main.js') - expect(getIdentityConfig()).toBeNull() - }) - - it('returns config from identity context', async () => { - globalThis.netlifyIdentityContext = { - url: 'https://example.com/.netlify/identity', - token: 'op-token', - } - const { getIdentityConfig } = await import('../src/main.js') - const config = getIdentityConfig() - expect(config).toEqual({ - url: 'https://example.com/.netlify/identity', - token: 'op-token', - }) - }) - - it('falls back to Netlify.context.url when netlifyIdentityContext has no url', async () => { - globalThis.netlifyIdentityContext = { - user: { - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - }, - } - globalThis.Netlify = { context: { url: 'https://example.netlify.app' } } - const { getIdentityConfig } = await import('../src/main.js') - const config = getIdentityConfig() - expect(config).toEqual({ - url: 'https://example.netlify.app/.netlify/identity', - }) - }) -}) - -describe('getSettings', () => { - beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - }) - - afterEach(() => { - delete globalThis.netlifyIdentityContext - resetTestGoTrueClient() - vi.resetAllMocks() - }) - - it('throws MissingIdentityError when no client is available', async () => { - const { getSettings, MissingIdentityError } = await import('../src/main.js') - await expect(getSettings()).rejects.toThrow(MissingIdentityError) - await expect(getSettings()).rejects.toThrow('Netlify Identity is not available') - }) - - it('maps gotrue-js settings to the Settings type', async () => { - globalThis.netlifyIdentityContext = { - url: 'https://example.com/.netlify/identity', - } - - const mockSettings = await getMockSettings() - mockSettings.mockResolvedValue({ - autoconfirm: false, - disable_signup: true, - external: { - google: true, - github: true, - gitlab: false, - bitbucket: false, - facebook: false, - email: true, - }, - }) - - const { getSettings } = await import('../src/main.js') - const settings = await getSettings() - - expect(settings.autoconfirm).toBe(false) - expect(settings.disableSignup).toBe(true) - expect(settings.providers.google).toBe(true) - expect(settings.providers.github).toBe(true) - expect(settings.providers.email).toBe(true) - expect(settings.providers.gitlab).toBe(false) - }) - - it('wraps fetch errors in AuthError with status 502', async () => { - globalThis.netlifyIdentityContext = { - url: 'https://example.com/.netlify/identity', - } - - const mockSettings = await getMockSettings() - const networkError = new Error('Network error') - mockSettings.mockRejectedValue(networkError) - - const { getSettings, AuthError } = await import('../src/main.js') - const error = await getSettings().catch((e: unknown) => e) - expect(error).toBeInstanceOf(AuthError) - expect(error.message).toBe('Network error') - expect(error.status).toBe(502) - expect(error.cause).toBe(networkError) - }) -}) diff --git a/packages/identity/prod/test/csrf.test.ts b/packages/identity/prod/test/csrf.test.ts deleted file mode 100644 index d4d7979..0000000 --- a/packages/identity/prod/test/csrf.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { verifyRequestOrigin } from '../src/csrf.js' -import { AuthError } from '../src/errors.js' - -const makeRequest = (url: string, init?: { method?: string; origin?: string }): Request => { - const headers = new Headers() - if (init?.origin !== undefined) { - headers.set('origin', init.origin) - } - return new Request(url, { method: init?.method ?? 'POST', headers }) -} - -describe('verifyRequestOrigin', () => { - describe('default (no allowedOrigins)', () => { - it('passes when Origin matches the request URL origin', () => { - const request = makeRequest('https://example.com/api/login', { - origin: 'https://example.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).not.toThrow() - }) - - it('passes when Origin matches with a non-default port', () => { - const request = makeRequest('https://example.com:8443/api/login', { - origin: 'https://example.com:8443', - }) - expect(() => { - verifyRequestOrigin(request) - }).not.toThrow() - }) - - it('throws AuthError with status 403 when Origin does not match', () => { - const request = makeRequest('https://example.com/api/login', { - origin: 'https://evil.com', - }) - - let caught: unknown - try { - verifyRequestOrigin(request) - } catch (err) { - caught = err - } - expect(caught).toBeInstanceOf(AuthError) - expect((caught as AuthError).status).toBe(403) - expect((caught as AuthError).message).toContain('https://evil.com') - }) - - it('throws when scheme differs (http vs https)', () => { - const request = makeRequest('https://example.com/api/login', { - origin: 'http://example.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).toThrow(AuthError) - }) - - it('throws when subdomains differ', () => { - const request = makeRequest('https://app.example.com/api/login', { - origin: 'https://other.example.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).toThrow(AuthError) - }) - }) - - describe('all methods are checked', () => { - it('passes on GET with same-origin', () => { - const request = makeRequest('https://example.com/api/whatever', { - method: 'GET', - origin: 'https://example.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).not.toThrow() - }) - - it('throws on GET with mismatching Origin', () => { - const request = makeRequest('https://example.com/api/whatever', { - method: 'GET', - origin: 'https://evil.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).toThrow(AuthError) - }) - - it('throws on HEAD with mismatching Origin', () => { - const request = makeRequest('https://example.com/api/whatever', { - method: 'HEAD', - origin: 'https://evil.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).toThrow(AuthError) - }) - - it('throws on DELETE with mismatching Origin', () => { - const request = makeRequest('https://example.com/api/whatever', { - method: 'DELETE', - origin: 'https://evil.com', - }) - expect(() => { - verifyRequestOrigin(request) - }).toThrow(AuthError) - }) - }) - - describe('missing Origin header', () => { - it('throws AuthError with status 403 when Origin header is absent', () => { - const request = makeRequest('https://example.com/api/login') - - let caught: unknown - try { - verifyRequestOrigin(request) - } catch (err) { - caught = err - } - expect(caught).toBeInstanceOf(AuthError) - expect((caught as AuthError).status).toBe(403) - expect((caught as AuthError).message).toContain('missing Origin header') - }) - - it('throws when Origin header is empty string', () => { - const request = makeRequest('https://example.com/api/login', { origin: '' }) - expect(() => { - verifyRequestOrigin(request) - }).toThrow(AuthError) - }) - }) - - describe('allowedOrigins override', () => { - it('accepts an Origin listed in allowedOrigins', () => { - const request = makeRequest('https://app.example.com/api/login', { - origin: 'https://www.example.com', - }) - expect(() => { - verifyRequestOrigin(request, { - allowedOrigins: ['https://www.example.com', 'https://app.example.com'], - }) - }).not.toThrow() - }) - - it('rejects the request URL origin when allowedOrigins is provided and does not include it', () => { - const request = makeRequest('https://app.example.com/api/login', { - origin: 'https://app.example.com', - }) - expect(() => { - verifyRequestOrigin(request, { allowedOrigins: ['https://www.example.com'] }) - }).toThrow(AuthError) - }) - - it('rejects every Origin when allowedOrigins is an empty array', () => { - const request = makeRequest('https://example.com/api/login', { - origin: 'https://example.com', - }) - expect(() => { - verifyRequestOrigin(request, { allowedOrigins: [] }) - }).toThrow(AuthError) - }) - - it('still throws on missing Origin when allowedOrigins is set', () => { - const request = makeRequest('https://example.com/api/login') - expect(() => { - verifyRequestOrigin(request, { allowedOrigins: ['https://example.com'] }) - }).toThrow(AuthError) - }) - }) -}) diff --git a/packages/identity/prod/test/errors.test.ts b/packages/identity/prod/test/errors.test.ts deleted file mode 100644 index 794838e..0000000 --- a/packages/identity/prod/test/errors.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { AuthError, MissingIdentityError } from '../src/main.js' - -describe('AuthError', () => { - it('has correct name and status', () => { - const err = new AuthError('fail', 401) - expect(err.name).toBe('AuthError') - expect(err.message).toBe('fail') - expect(err.status).toBe(401) - expect(err).toBeInstanceOf(Error) - }) - - it('works without status', () => { - const err = new AuthError('oops') - expect(err.status).toBeUndefined() - }) -}) - -describe('MissingIdentityError', () => { - it('has correct name and default message', () => { - const err = new MissingIdentityError() - expect(err.name).toBe('MissingIdentityError') - expect(err.message).toBe('Netlify Identity is not available.') - }) -}) diff --git a/packages/identity/prod/test/fetch.test.ts b/packages/identity/prod/test/fetch.test.ts deleted file mode 100644 index d767fb6..0000000 --- a/packages/identity/prod/test/fetch.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { describe, it, expect, afterEach, vi } from 'vitest' -import { fetchWithTimeout } from '../src/fetch.js' -import { AuthError } from '../src/errors.js' - -describe('fetchWithTimeout', () => { - afterEach(() => { - vi.restoreAllMocks() - }) - - it('returns the response when fetch completes within the timeout', async () => { - const mockResponse = new Response(JSON.stringify({ ok: true }), { status: 200 }) - vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockResponse) - - const res = await fetchWithTimeout('https://example.com/.netlify/identity/user', { - headers: { Authorization: 'Bearer test-token' }, - }) - - expect(res).toBe(mockResponse) - expect(globalThis.fetch).toHaveBeenCalledWith( - 'https://example.com/.netlify/identity/user', - expect.objectContaining({ - headers: { Authorization: 'Bearer test-token' }, - signal: expect.any(AbortSignal), - }), - ) - }) - - it('forwards request options to fetch', async () => { - vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response('', { status: 200 })) - - await fetchWithTimeout('https://example.com/.netlify/identity/token', { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: 'grant_type=password', - }) - - expect(globalThis.fetch).toHaveBeenCalledWith( - 'https://example.com/.netlify/identity/token', - expect.objectContaining({ - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: 'grant_type=password', - }), - ) - }) - - it('throws AuthError with pathname and timeout when request times out', async () => { - vi.useFakeTimers() - vi.spyOn(globalThis, 'fetch').mockImplementation( - (_url, options) => - new Promise((_resolve, reject) => { - options?.signal?.addEventListener('abort', () => { - const err = new Error('The operation was aborted') - err.name = 'AbortError' - reject(err) - }) - }), - ) - - const promise = fetchWithTimeout('https://example.com/.netlify/identity/user', {}, 100) - - vi.advanceTimersByTime(100) - - await expect(promise).rejects.toThrow(AuthError) - await expect(promise).rejects.toThrow(/\/\.netlify\/identity\/user/) - await expect(promise).rejects.toThrow(/100ms/) - - vi.useRealTimers() - }) - - it('re-throws non-timeout errors without wrapping', async () => { - const networkError = new Error('getaddrinfo ENOTFOUND example.com') - vi.spyOn(globalThis, 'fetch').mockRejectedValue(networkError) - - await expect(fetchWithTimeout('https://example.com/.netlify/identity/user')).rejects.toBe(networkError) - expect(networkError).not.toBeInstanceOf(AuthError) - }) - - it('does not leak query params in timeout error messages', async () => { - vi.useFakeTimers() - vi.spyOn(globalThis, 'fetch').mockImplementation( - (_url, options) => - new Promise((_resolve, reject) => { - options?.signal?.addEventListener('abort', () => { - const err = new Error('The operation was aborted') - err.name = 'AbortError' - reject(err) - }) - }), - ) - - const promise = fetchWithTimeout( - 'https://example.com/.netlify/identity/token?secret=sensitive&refresh_token=abc', - {}, - 100, - ) - - vi.advanceTimersByTime(100) - - await expect(promise).rejects.toBeInstanceOf(AuthError) - await expect(promise).rejects.toThrow(/\/\.netlify\/identity\/token/) - await expect(promise).rejects.not.toThrow(/secret=sensitive/) - await expect(promise).rejects.not.toThrow(/refresh_token=abc/) - await expect(promise).rejects.not.toThrow(/example\.com/) - - vi.useRealTimers() - }) -}) diff --git a/packages/identity/prod/test/fixtures.ts b/packages/identity/prod/test/fixtures.ts deleted file mode 100644 index 8be8b15..0000000 --- a/packages/identity/prod/test/fixtures.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { UserData } from 'gotrue-js' - -/** Clears nf_jwt and nf_refresh cookies via expiry. Use in afterEach for browser test files. */ -export const clearBrowserAuthCookies = (): void => { - document.cookie = 'nf_jwt=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT' - document.cookie = 'nf_refresh=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT' -} - -export const makeGoTrueUser = (overrides: Partial = {}): UserData => ({ - id: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - aud: '', - role: '', - confirmed_at: '2026-01-01T00:00:00Z', - created_at: '2026-01-01T00:00:00Z', - updated_at: '2026-02-25T00:00:00Z', - app_metadata: { provider: 'github' }, - user_metadata: { full_name: 'Jane Doe', avatar_url: 'https://example.com/avatar.png' }, - ...overrides, -}) diff --git a/packages/identity/prod/test/nextjs.test.ts b/packages/identity/prod/test/nextjs.test.ts deleted file mode 100644 index 0ccc5fd..0000000 --- a/packages/identity/prod/test/nextjs.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { describe, it, expect, vi, afterEach } from 'vitest' -import { triggerNextjsDynamic, resetNextjsState } from '../src/nextjs.js' - -describe('triggerNextjsDynamic', () => { - afterEach(() => { - resetNextjsState() - }) - - it('is a no-op when next/headers is not available', () => { - // next/headers is not installed, so require() will fail and cache null - expect(() => { - triggerNextjsDynamic() - }).not.toThrow() - }) - - it('caches the "not available" result and skips on subsequent calls', () => { - triggerNextjsDynamic() - // Second call should return immediately - expect(() => { - triggerNextjsDynamic() - }).not.toThrow() - }) - - it('calls the headers function when available', () => { - const mockHeaders = vi.fn() - resetNextjsState(mockHeaders) - - triggerNextjsDynamic() - - expect(mockHeaders).toHaveBeenCalledOnce() - }) - - it('calls headers on every invocation (not just the first)', () => { - const mockHeaders = vi.fn() - resetNextjsState(mockHeaders) - - triggerNextjsDynamic() - triggerNextjsDynamic() - triggerNextjsDynamic() - - expect(mockHeaders).toHaveBeenCalledTimes(3) - }) - - it('re-throws DynamicServerError (error with digest property)', () => { - const dynamicError = new Error('DYNAMIC_SERVER_USAGE') - ;(dynamicError as unknown as Record).digest = 'DYNAMIC_SERVER_USAGE' - resetNextjsState(() => { - throw dynamicError - }) - - expect(() => { - triggerNextjsDynamic() - }).toThrow(dynamicError) - }) - - it('re-throws prerendering bailout errors', () => { - const bailoutError = new Error('Bail out of prerendering') - resetNextjsState(() => { - throw bailoutError - }) - - expect(() => { - triggerNextjsDynamic() - }).toThrow(bailoutError) - }) - - it('swallows non-Dynamic errors from headers()', () => { - resetNextjsState(() => { - throw new Error('some other error') - }) - - expect(() => { - triggerNextjsDynamic() - }).not.toThrow() - }) - - it('swallows non-Error throws from headers()', () => { - resetNextjsState(() => { - // eslint-disable-next-line @typescript-eslint/only-throw-error -- intentionally throwing a non-Error to test the handler - throw 'string error' - }) - - expect(() => { - triggerNextjsDynamic() - }).not.toThrow() - }) - - it('skips entirely when state is set to null (not Next.js)', () => { - const mockHeaders = vi.fn() - resetNextjsState(null) - - triggerNextjsDynamic() - - expect(mockHeaders).not.toHaveBeenCalled() - }) -}) diff --git a/packages/identity/prod/test/refresh.browser.test.ts b/packages/identity/prod/test/refresh.browser.test.ts deleted file mode 100644 index d9c08bb..0000000 --- a/packages/identity/prod/test/refresh.browser.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser, clearBrowserAuthCookies } from './fixtures.js' - -const mockCurrentUser = vi.fn() -const mockJwt = vi.fn() - -const futureExpiry = Math.floor(Date.now() / 1000) + 3600 - -const mockTokenDetails = vi.fn().mockReturnValue({ - access_token: 'test-jwt-token', - refresh_token: 'test-refresh-token', - expires_in: 3600, - expires_at: futureExpiry, -}) - -vi.mock('gotrue-js', () => ({ - default: class MockGoTrue { - currentUser = mockCurrentUser - }, -})) - -const gotrueUserWithJwt = (overrides = {}) => { - const user = makeGoTrueUser(overrides) - return { ...user, jwt: mockJwt, tokenDetails: mockTokenDetails } -} - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - vi.useFakeTimers() - mockJwt.mockResolvedValue('refreshed-jwt-token') -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - vi.useRealTimers() - clearBrowserAuthCookies() -}) - -describe('startTokenRefresh (browser)', () => { - it('schedules a refresh before token expiry', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - - const { startTokenRefresh, stopTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - - // Token expires in 3600s, refresh margin is 60s, so timer fires at 3540s - // Advance to just before the refresh should fire - vi.advanceTimersByTime(3539 * 1000) - expect(mockJwt).not.toHaveBeenCalled() - - // Advance past the refresh point - vi.advanceTimersByTime(2 * 1000) - await vi.runOnlyPendingTimersAsync() - - expect(mockJwt).toHaveBeenCalledWith(true) - stopTokenRefresh() - }) - - it('refreshes token and syncs cookies when timer fires', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - mockTokenDetails.mockReturnValue({ - access_token: 'refreshed-jwt-token', - refresh_token: 'new-refresh-token', - expires_in: 3600, - expires_at: futureExpiry, - }) - - const { startTokenRefresh, stopTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - - await vi.advanceTimersByTimeAsync(3541 * 1000) - await Promise.resolve() - - // Verify the refresh happened and tokenDetails were read for cookie sync - expect(mockJwt).toHaveBeenCalledWith(true) - expect(mockTokenDetails).toHaveBeenCalled() - stopTokenRefresh() - }) - - it('is a no-op when no user is logged in', async () => { - mockCurrentUser.mockReturnValue(null) - - const { startTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - - vi.advanceTimersByTime(4000 * 1000) - expect(mockJwt).not.toHaveBeenCalled() - }) - - it('is a no-op when user has no tokenDetails', async () => { - const user = makeGoTrueUser() - mockCurrentUser.mockReturnValue({ ...user, tokenDetails: () => null }) - - const { startTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - - vi.advanceTimersByTime(4000 * 1000) - expect(mockJwt).not.toHaveBeenCalled() - }) - - it('stops retrying when refresh fails', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - // Token expires in 10s (under 60s margin), so timer fires immediately - mockTokenDetails.mockReturnValue({ - access_token: 'old-token', - refresh_token: 'test-refresh', - expires_in: 10, - expires_at: Math.floor(Date.now() / 1000) + 10, - }) - mockJwt.mockRejectedValue(new Error('Refresh token revoked')) - - const { startTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - - await vi.advanceTimersByTimeAsync(1) - - expect(mockJwt).toHaveBeenCalledWith(true) - - // Should not schedule another refresh after failure - mockJwt.mockClear() - await vi.advanceTimersByTimeAsync(7200 * 1000) - expect(mockJwt).not.toHaveBeenCalled() - }) - - it('restarts timer when called multiple times', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - - const { startTokenRefresh, stopTokenRefresh } = await import('../src/refresh.js') - - // First start with a far-future expiry - startTokenRefresh() - - // Now restart with a near-expiry token (fires immediately) - mockTokenDetails.mockReturnValue({ - access_token: 'old-token', - refresh_token: 'test-refresh', - expires_in: 5, - expires_at: Math.floor(Date.now() / 1000) + 5, - }) - startTokenRefresh() - - await vi.advanceTimersByTimeAsync(1) - expect(mockJwt).toHaveBeenCalledWith(true) - - stopTokenRefresh() - }) - - it('fires immediately when token is already near expiry', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - mockTokenDetails.mockReturnValue({ - access_token: 'old-token', - refresh_token: 'test-refresh', - expires_in: 30, - expires_at: Math.floor(Date.now() / 1000) + 30, // 30s left, under 60s margin - }) - - const { startTokenRefresh, stopTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - - // delay should be max(0, ...) = 0, so fires on next tick - vi.advanceTimersByTime(1) - await vi.runOnlyPendingTimersAsync() - - expect(mockJwt).toHaveBeenCalledWith(true) - stopTokenRefresh() - }) -}) - -describe('stopTokenRefresh', () => { - it('cancels a pending refresh', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - - const { startTokenRefresh, stopTokenRefresh } = await import('../src/refresh.js') - startTokenRefresh() - stopTokenRefresh() - - vi.advanceTimersByTime(4000 * 1000) - await vi.runOnlyPendingTimersAsync() - expect(mockJwt).not.toHaveBeenCalled() - }) - - it('is safe to call when no timer is running', async () => { - const { stopTokenRefresh } = await import('../src/refresh.js') - expect(() => { - stopTokenRefresh() - }).not.toThrow() - }) -}) - -describe('refreshSession (browser)', () => { - it('calls user.jwt() and updates cookie', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBe('refreshed-jwt-token') - expect(mockJwt).toHaveBeenCalled() - expect(document.cookie).toContain('nf_jwt=refreshed-jwt-token') - }) - - it('returns null when no user is logged in', async () => { - mockCurrentUser.mockReturnValue(null) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - }) - - it('returns null when jwt() throws', async () => { - const user = gotrueUserWithJwt() - mockCurrentUser.mockReturnValue(user) - mockJwt.mockRejectedValue(new Error('Token expired')) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - }) -}) diff --git a/packages/identity/prod/test/refresh.server.test.ts b/packages/identity/prod/test/refresh.server.test.ts deleted file mode 100644 index 1b8cf4e..0000000 --- a/packages/identity/prod/test/refresh.server.test.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' - -const mockCookies = { - get: vi.fn(), - set: vi.fn(), - delete: vi.fn(), -} - -const IDENTITY_URL = 'https://example.netlify.app/.netlify/identity' - -/** Builds a fake JWT (header.payload.signature) from claims. */ -const fakeJwt = (claims: Record): string => { - const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' })) - const payload = btoa(JSON.stringify(claims)) - return `${header}.${payload}.fake-signature` -} - -const expiredJwt = fakeJwt({ - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - exp: Math.floor(Date.now() / 1000) - 300, // expired 5 minutes ago -}) - -const nearExpiryJwt = fakeJwt({ - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - exp: Math.floor(Date.now() / 1000) + 30, // expires in 30s (under 60s margin) -}) - -const validJwt = fakeJwt({ - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - exp: Math.floor(Date.now() / 1000) + 3600, // expires in 1 hour -}) - -const freshAccessToken = fakeJwt({ - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - exp: Math.floor(Date.now() / 1000) + 3600, -}) - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - - globalThis.netlifyIdentityContext = { - url: IDENTITY_URL, - token: 'test-operator-token', - } - - globalThis.Netlify = { - context: { - cookies: mockCookies, - }, - } as unknown as typeof globalThis.Netlify -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - vi.unstubAllGlobals() - delete globalThis.netlifyIdentityContext - delete (globalThis as Record).Netlify -}) - -describe('refreshSession (server)', () => { - it('refreshes an expired token and updates cookies', async () => { - mockCookies.get - .mockReturnValueOnce(expiredJwt) // nf_jwt - .mockReturnValueOnce('old-refresh-token') // nf_refresh - - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValueOnce({ - ok: true, - json: () => - Promise.resolve({ - access_token: freshAccessToken, - token_type: 'bearer', - expires_in: 3600, - refresh_token: 'new-refresh-token', - }), - }), - ) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBe(freshAccessToken) - - // Verify GoTrue /token endpoint was called with refresh_token grant - expect(fetch).toHaveBeenCalledWith( - `${IDENTITY_URL}/token`, - expect.objectContaining({ - method: 'POST', - body: 'grant_type=refresh_token&refresh_token=old-refresh-token', - }), - ) - - // Verify cookies were updated - expect(mockCookies.set).toHaveBeenCalledWith(expect.objectContaining({ name: 'nf_jwt', value: freshAccessToken })) - expect(mockCookies.set).toHaveBeenCalledWith( - expect.objectContaining({ name: 'nf_refresh', value: 'new-refresh-token' }), - ) - }) - - it('refreshes a near-expiry token (within 60s margin)', async () => { - mockCookies.get.mockReturnValueOnce(nearExpiryJwt).mockReturnValueOnce('test-refresh-token') - - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValueOnce({ - ok: true, - json: () => - Promise.resolve({ - access_token: freshAccessToken, - refresh_token: 'new-refresh-token', - }), - }), - ) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBe(freshAccessToken) - expect(fetch).toHaveBeenCalled() - }) - - it('returns null when token is still valid', async () => { - mockCookies.get.mockReturnValueOnce(validJwt).mockReturnValueOnce('test-refresh-token') - - vi.stubGlobal('fetch', vi.fn()) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - expect(fetch).not.toHaveBeenCalled() - }) - - it('returns null when no nf_jwt cookie exists', async () => { - mockCookies.get.mockReturnValue(null) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - }) - - it('returns null when no nf_refresh cookie exists', async () => { - mockCookies.get - .mockReturnValueOnce(expiredJwt) // nf_jwt present - .mockReturnValueOnce(null) // nf_refresh missing - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - }) - - it('returns null when refresh token is invalid (401)', async () => { - mockCookies.get.mockReturnValueOnce(expiredJwt).mockReturnValueOnce('invalid-refresh-token') - - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValueOnce({ - ok: false, - status: 401, - json: () => Promise.resolve({ msg: 'Invalid Refresh Token' }), - }), - ) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - }) - - it('returns null when refresh token is invalid (400)', async () => { - mockCookies.get.mockReturnValueOnce(expiredJwt).mockReturnValueOnce('invalid-refresh-token') - - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValueOnce({ - ok: false, - status: 400, - json: () => Promise.resolve({ error_description: 'Invalid Refresh Token' }), - }), - ) - - const { refreshSession } = await import('../src/refresh.js') - const result = await refreshSession() - - expect(result).toBeNull() - }) - - it('throws AuthError on server error (500)', async () => { - mockCookies.get.mockReturnValueOnce(expiredJwt).mockReturnValueOnce('test-refresh-token') - - vi.stubGlobal( - 'fetch', - vi.fn().mockResolvedValueOnce({ - ok: false, - status: 500, - json: () => Promise.resolve({ msg: 'Internal Server Error' }), - }), - ) - - const { refreshSession } = await import('../src/refresh.js') - const { AuthError } = await import('../src/errors.js') - - await expect(refreshSession()).rejects.toThrow(AuthError) - }) - - it('throws AuthError on network failure', async () => { - mockCookies.get.mockReturnValueOnce(expiredJwt).mockReturnValueOnce('test-refresh-token') - - vi.stubGlobal('fetch', vi.fn().mockRejectedValueOnce(new TypeError('fetch failed'))) - - const { refreshSession } = await import('../src/refresh.js') - const { AuthError } = await import('../src/errors.js') - - await expect(refreshSession()).rejects.toThrow(AuthError) - }) - - it('throws AuthError when identity URL cannot be determined', async () => { - mockCookies.get.mockReturnValueOnce(expiredJwt).mockReturnValueOnce('test-refresh-token') - - // Remove identity URL sources but keep cookies available - delete globalThis.netlifyIdentityContext - globalThis.Netlify = { - context: { - cookies: mockCookies, - // no url property - }, - } as unknown as typeof globalThis.Netlify - - const { refreshSession } = await import('../src/refresh.js') - const { AuthError } = await import('../src/errors.js') - - await expect(refreshSession()).rejects.toThrow(AuthError) - }) -}) diff --git a/packages/identity/prod/test/stale-session.browser.test.ts b/packages/identity/prod/test/stale-session.browser.test.ts deleted file mode 100644 index 3a6dc9f..0000000 --- a/packages/identity/prod/test/stale-session.browser.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser } from './fixtures.js' - -const mockClearSession = vi.fn() -const mockCurrentUser = vi.fn() - -vi.mock('gotrue-js', () => ({ - default: class MockGoTrue { - currentUser = mockCurrentUser - }, -})) - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) -}) - -afterEach(() => { - resetTestGoTrueClient() - vi.resetAllMocks() - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) -}) - -describe('stale session detection (browser)', () => { - it('clears stale session and returns null when localStorage has user but nf_jwt cookie is gone', async () => { - const gotrueUser = { ...makeGoTrueUser(), clearSession: mockClearSession } - mockCurrentUser.mockReturnValue(gotrueUser) - - // No nf_jwt cookie (server logged us out) - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - - const { getUser } = await import('../src/user.js') - const user = await getUser() - - expect(user).toBeNull() - expect(mockClearSession).toHaveBeenCalledOnce() - }) - - it('returns user normally when localStorage has user and nf_jwt cookie exists', async () => { - const gotrueUser = { ...makeGoTrueUser(), clearSession: mockClearSession, tokenDetails: vi.fn() } - mockCurrentUser.mockReturnValue(gotrueUser) - - const header = btoa(JSON.stringify({ alg: 'HS256' })) - const payload = btoa(JSON.stringify({ sub: '550e8400-e29b-41d4-a716-446655440000' })) - Object.defineProperty(document, 'cookie', { writable: true, value: `nf_jwt=${header}.${payload}.sig` }) - - const { getUser } = await import('../src/user.js') - const user = await getUser() - - if (!user) throw new Error('expected user to not be null') - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(mockClearSession).not.toHaveBeenCalled() - }) - - it('returns null on subsequent calls after stale session is cleared', async () => { - const gotrueUser = { ...makeGoTrueUser(), clearSession: mockClearSession } - - // First call: gotrue has a user, no cookie - mockCurrentUser.mockReturnValue(gotrueUser) - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) - - const { getUser } = await import('../src/user.js') - expect(await getUser()).toBeNull() - expect(mockClearSession).toHaveBeenCalledOnce() - - // Second call: clearSession worked, gotrue returns null - mockCurrentUser.mockReturnValue(null) - expect(await getUser()).toBeNull() - }) -}) diff --git a/packages/identity/prod/test/user.browser.test.ts b/packages/identity/prod/test/user.browser.test.ts deleted file mode 100644 index 3b5b560..0000000 --- a/packages/identity/prod/test/user.browser.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @vitest-environment jsdom - * @vitest-environment-options { "url": "https://localhost" } - */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { resetTestGoTrueClient } from '../src/environment.js' - -const mockCurrentUser = vi.fn().mockReturnValue(null) -const mockCreateUser = vi.fn() - -vi.mock('gotrue-js', () => ({ - default: class MockGoTrue { - currentUser = mockCurrentUser - createUser = mockCreateUser - }, -})) - -/** Builds a fake JWT (header.payload.signature) from a claims object. */ -const fakeJwt = (claims: Record): string => { - const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' })) - const payload = btoa(JSON.stringify(claims)) - return `${header}.${payload}.fake-signature` -} - -beforeEach(() => { - vi.resetModules() - resetTestGoTrueClient() - vi.resetAllMocks() - mockCurrentUser.mockReturnValue(null) - localStorage.clear() - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) -}) - -afterEach(() => { - resetTestGoTrueClient() - localStorage.clear() - Object.defineProperty(document, 'cookie', { writable: true, value: '' }) -}) - -describe('getUser (browser)', () => { - it('returns null when no session exists in localStorage', async () => { - const { getUser } = await import('../src/user.js') - expect(await getUser()).toBeNull() - }) - - it('returns user from nf_jwt cookie when no localStorage session', async () => { - const jwt = fakeJwt({ - sub: 'cookie-user-123', - email: 'cookie@example.com', - exp: Math.floor(Date.now() / 1000) + 3600, - app_metadata: { provider: 'email' }, - user_metadata: { full_name: 'Cookie User' }, - }) - - Object.defineProperty(document, 'cookie', { writable: true, value: `nf_jwt=${jwt}` }) - - // hydrateSession calls client.createUser then toUser - const mockGoTrueUser = { - id: 'cookie-user-123', - email: 'cookie@example.com', - app_metadata: { provider: 'email' }, - user_metadata: { full_name: 'Cookie User' }, - } - mockCreateUser.mockResolvedValue(mockGoTrueUser) - - const { getUser } = await import('../src/user.js') - const user = await getUser() - if (!user) throw new Error('expected user to not be null') - expect(user.id).toBe('cookie-user-123') - expect(user.email).toBe('cookie@example.com') - expect(user.provider).toBe('email') - expect(user.name).toBe('Cookie User') - }) - - it('returns null when nf_jwt cookie contains invalid JWT', async () => { - Object.defineProperty(document, 'cookie', { writable: true, value: 'nf_jwt=not-a-jwt' }) - - const { getUser } = await import('../src/user.js') - expect(await getUser()).toBeNull() - }) -}) - -describe('isAuthenticated (browser)', () => { - it('returns false when no session exists', async () => { - const { isAuthenticated } = await import('../src/user.js') - expect(await isAuthenticated()).toBe(false) - }) - - it('returns true when nf_jwt cookie is present', async () => { - const jwt = fakeJwt({ - sub: 'cookie-user-123', - email: 'cookie@example.com', - exp: Math.floor(Date.now() / 1000) + 3600, - app_metadata: { provider: 'email' }, - user_metadata: {}, - }) - - Object.defineProperty(document, 'cookie', { writable: true, value: `nf_jwt=${jwt}` }) - - const mockGoTrueUser = { - id: 'cookie-user-123', - email: 'cookie@example.com', - app_metadata: { provider: 'email' }, - user_metadata: {}, - } - mockCreateUser.mockResolvedValue(mockGoTrueUser) - - const { isAuthenticated } = await import('../src/user.js') - expect(await isAuthenticated()).toBe(true) - }) -}) diff --git a/packages/identity/prod/test/user.test.ts b/packages/identity/prod/test/user.test.ts deleted file mode 100644 index 46cb5bd..0000000 --- a/packages/identity/prod/test/user.test.ts +++ /dev/null @@ -1,311 +0,0 @@ -import { describe, it, expect, afterEach, vi } from 'vitest' -import { toUser, getUser, isAuthenticated, decodeJwtPayload } from '../src/user.js' -import { resetTestGoTrueClient } from '../src/environment.js' -import { makeGoTrueUser } from './fixtures.js' - -/** Builds a fake JWT (header.payload.signature) from a claims object. */ -const fakeJwt = (claims: Record): string => { - const header = btoa(JSON.stringify({ alg: 'HS256' })) - const payload = btoa(JSON.stringify(claims)) - return `${header}.${payload}.fake-sig` -} - -describe('toUser', () => { - it('normalizes a UserData to User', () => { - const goTrueUser = makeGoTrueUser() - const user = toUser(goTrueUser) - - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - expect(user.confirmedAt).toBe('2026-01-01T00:00:00Z') - expect(user.provider).toBe('github') - expect(user.name).toBe('Jane Doe') - expect(user.pictureUrl).toBe('https://example.com/avatar.png') - expect(user.createdAt).toBe('2026-01-01T00:00:00Z') - expect(user.updatedAt).toBe('2026-02-25T00:00:00Z') - expect(user.userMetadata).toEqual(goTrueUser.user_metadata) - }) - - it('maps GoTrue-level fields', () => { - const goTrueUser = makeGoTrueUser({ - aud: 'app-audience', - role: 'editor', - invited_at: '2026-01-15T00:00:00Z', - confirmation_sent_at: '2026-01-01T00:00:00Z', - recovery_sent_at: '2026-02-01T00:00:00Z', - new_email: 'new@example.com', - email_change_sent_at: '2026-02-20T00:00:00Z', - last_sign_in_at: '2026-02-25T00:00:00Z', - }) - const user = toUser(goTrueUser) - expect(user.role).toBe('editor') - expect(user.invitedAt).toBe('2026-01-15T00:00:00Z') - expect(user.confirmationSentAt).toBe('2026-01-01T00:00:00Z') - expect(user.recoverySentAt).toBe('2026-02-01T00:00:00Z') - expect(user.pendingEmail).toBe('new@example.com') - expect(user.emailChangeSentAt).toBe('2026-02-20T00:00:00Z') - expect(user.lastSignInAt).toBe('2026-02-25T00:00:00Z') - }) - - it('omits GoTrue-level fields when empty or absent', () => { - const goTrueUser = makeGoTrueUser() - const user = toUser(goTrueUser) - expect(user.role).toBeUndefined() - expect(user.invitedAt).toBeUndefined() - expect(user.confirmationSentAt).toBeUndefined() - expect(user.recoverySentAt).toBeUndefined() - expect(user.pendingEmail).toBeUndefined() - expect(user.emailChangeSentAt).toBeUndefined() - expect(user.lastSignInAt).toBeUndefined() - }) - - it('extracts roles from app_metadata', () => { - const goTrueUser = makeGoTrueUser({ - app_metadata: { provider: 'email', roles: ['admin', 'editor'] }, - }) - const user = toUser(goTrueUser) - expect(user.roles).toEqual(['admin', 'editor']) - }) - - it('handles missing roles', () => { - const goTrueUser = makeGoTrueUser() - const user = toUser(goTrueUser) - expect(user.roles).toBeUndefined() - }) - - it('handles missing optional fields', () => { - const goTrueUser = makeGoTrueUser({ - confirmed_at: null, - user_metadata: {}, - }) - const user = toUser(goTrueUser) - - expect(user.confirmedAt).toBeUndefined() - expect(user.name).toBeUndefined() - expect(user.pictureUrl).toBeUndefined() - }) - - it('handles undefined user_metadata and app_metadata', () => { - const goTrueUser = makeGoTrueUser({ - user_metadata: undefined as unknown as Record, - app_metadata: undefined as unknown as Record, - }) - const user = toUser(goTrueUser) - - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.provider).toBeUndefined() - expect(user.name).toBeUndefined() - expect(user.pictureUrl).toBeUndefined() - expect(user.userMetadata).toEqual({}) - }) -}) - -describe('getUser (server)', () => { - afterEach(() => { - delete globalThis.netlifyIdentityContext - resetTestGoTrueClient() - vi.restoreAllMocks() - }) - - it('returns null when no identity context exists', async () => { - expect(await getUser()).toBeNull() - }) - - it('returns User from identity context (claims fallback)', async () => { - // No identity URL available, so fetch can't happen; falls back to claims - globalThis.netlifyIdentityContext = { - user: { - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - exp: 9999999999, - app_metadata: { provider: 'github' }, - user_metadata: { full_name: 'Jane Doe' }, - }, - } - - const user = await getUser() - if (!user) throw new Error('expected user to not be null') - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - expect(user.provider).toBe('github') - expect(user.name).toBe('Jane Doe') - }) - - it('fetches full user from GoTrue when identity URL is available', async () => { - const token = fakeJwt({ sub: '550e8400-e29b-41d4-a716-446655440000', email: 'jane@example.com' }) - globalThis.netlifyIdentityContext = { - url: 'https://example.com/.netlify/identity', - token, - user: { sub: '550e8400-e29b-41d4-a716-446655440000', email: 'jane@example.com' }, - } - - vi.spyOn(globalThis, 'fetch').mockResolvedValue( - new Response( - JSON.stringify({ - id: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - confirmed_at: '2026-01-01T00:00:00Z', - created_at: '2026-01-01T00:00:00Z', - updated_at: '2026-02-25T00:00:00Z', - app_metadata: { provider: 'github', roles: ['admin'] }, - user_metadata: { full_name: 'Jane Doe', avatar_url: 'https://example.com/avatar.png' }, - }), - { status: 200 }, - ), - ) - - const user = await getUser() - if (!user) throw new Error('expected user to not be null') - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.confirmedAt).toBe('2026-01-01T00:00:00Z') - expect(user.createdAt).toBe('2026-01-01T00:00:00Z') - expect(user.pictureUrl).toBe('https://example.com/avatar.png') - expect(user.roles).toEqual(['admin']) - }) - - it('falls back to claims when GoTrue fetch fails', async () => { - const token = fakeJwt({ sub: '550e8400-e29b-41d4-a716-446655440000', email: 'jane@example.com' }) - globalThis.netlifyIdentityContext = { - url: 'https://example.com/.netlify/identity', - token, - user: { - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - app_metadata: { provider: 'email', roles: ['editor'] }, - user_metadata: { full_name: 'Jane Doe' }, - }, - } - - vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('network error')) - - const user = await getUser() - if (!user) throw new Error('expected user to not be null') - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.roles).toEqual(['editor']) - // Falls back to claims, so no GoTrue-level fields - expect(user.role).toBeUndefined() - expect(user.createdAt).toBeUndefined() - expect(user.lastSignInAt).toBeUndefined() - }) - - it('handles user with missing metadata fields', async () => { - globalThis.netlifyIdentityContext = { - user: { - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - }, - } - - const user = await getUser() - if (!user) throw new Error('expected user to not be null') - expect(user.id).toBe('550e8400-e29b-41d4-a716-446655440000') - expect(user.email).toBe('jane@example.com') - expect(user.provider).toBeUndefined() - expect(user.name).toBeUndefined() - expect(user.userMetadata).toEqual({}) - }) -}) - -describe('getUser (server, cookie fallback)', () => { - const savedUrl = process.env.URL - - afterEach(() => { - if (savedUrl !== undefined) { - process.env.URL = savedUrl - } else { - delete process.env.URL - } - delete globalThis.netlifyIdentityContext - delete (globalThis as Record).Netlify - resetTestGoTrueClient() - vi.restoreAllMocks() - vi.unstubAllGlobals() - }) - - it('falls back to nf_jwt cookie when identityContext has no token', async () => { - delete process.env.URL - const claims = { - sub: 'cookie-user-456', - email: 'cookie@example.com', - app_metadata: { provider: 'email' }, - user_metadata: { full_name: 'Cookie User' }, - } - const jwt = fakeJwt(claims) - - globalThis.Netlify = { - context: { - cookies: { - get: (name: string) => (name === 'nf_jwt' ? jwt : undefined), - set: () => {}, - delete: () => {}, - }, - }, - } as unknown as typeof globalThis.Netlify - - const user = await getUser() - // Fail-closed: without server-validated identityContext, unverified cookies are not trusted - expect(user).toBeNull() - }) - - it('returns null when no identityContext and no cookies', async () => { - expect(await getUser()).toBeNull() - }) -}) - -describe('decodeJwtPayload', () => { - it('decodes a valid JWT payload', () => { - const claims = { sub: 'user-1', email: 'test@example.com' } - const jwt = `${btoa(JSON.stringify({ alg: 'HS256' }))}.${btoa(JSON.stringify(claims))}.sig` - - const result = decodeJwtPayload(jwt) - expect(result).toEqual(expect.objectContaining({ sub: 'user-1', email: 'test@example.com' })) - }) - - it('returns null for token with wrong number of segments', () => { - expect(decodeJwtPayload('only-one-part')).toBeNull() - expect(decodeJwtPayload('two.parts')).toBeNull() - expect(decodeJwtPayload('a.b.c.d')).toBeNull() - }) - - it('returns null for token with invalid base64 payload', () => { - expect(decodeJwtPayload('header.!!!invalid!!!.sig')).toBeNull() - }) - - it('returns null for token with non-JSON payload', () => { - const notJson = btoa('this is not json') - expect(decodeJwtPayload(`header.${notJson}.sig`)).toBeNull() - }) - - it('handles base64url-encoded payloads (- and _ characters)', () => { - const claims = { sub: 'user-1' } - const standard = btoa(JSON.stringify(claims)) - const urlSafe = standard.replace(/\+/g, '-').replace(/\//g, '_') - const jwt = `header.${urlSafe}.sig` - - const result = decodeJwtPayload(jwt) - expect(result).toEqual(expect.objectContaining({ sub: 'user-1' })) - }) -}) - -describe('isAuthenticated (server)', () => { - afterEach(() => { - delete globalThis.netlifyIdentityContext - resetTestGoTrueClient() - }) - - it('returns false when no session exists', async () => { - expect(await isAuthenticated()).toBe(false) - }) - - it('returns true when user is present', async () => { - globalThis.netlifyIdentityContext = { - user: { - sub: '550e8400-e29b-41d4-a716-446655440000', - email: 'jane@example.com', - app_metadata: { provider: 'github' }, - user_metadata: {}, - }, - } - expect(await isAuthenticated()).toBe(true) - }) -}) diff --git a/packages/identity/prod/tsconfig.json b/packages/identity/prod/tsconfig.json deleted file mode 100644 index 83e9a4b..0000000 --- a/packages/identity/prod/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "allowImportingTsExtensions": true, - "emitDeclarationOnly": true, - "target": "ES2020", - "module": "nodenext", - "allowJs": true, - "declaration": true, - "declarationMap": false, - "sourceMap": false, - "outDir": "./dist", - "removeComments": false, - "strict": true, - "moduleResolution": "nodenext", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src"] -} diff --git a/packages/identity/prod/tsup.config.ts b/packages/identity/prod/tsup.config.ts deleted file mode 100644 index 689ec35..0000000 --- a/packages/identity/prod/tsup.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/main.ts'], - tsconfig: 'tsconfig.json', - bundle: true, - format: ['cjs', 'esm'], - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/identity/prod/vitest.config.ts b/packages/identity/prod/vitest.config.ts deleted file mode 100644 index 6e8f57e..0000000 --- a/packages/identity/prod/vitest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['test/**/*.test.ts'], - testTimeout: 30_000, - }, -}) diff --git a/packages/images/.gitignore b/packages/images/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/images/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/images/CHANGELOG.md b/packages/images/CHANGELOG.md deleted file mode 100644 index f284169..0000000 --- a/packages/images/CHANGELOG.md +++ /dev/null @@ -1,223 +0,0 @@ -# Changelog - -## [1.3.10](https://github.com/netlify/primitives/compare/images-v1.3.9...images-v1.3.10) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.5 to ^4.4.6 - -## [1.3.9](https://github.com/netlify/primitives/compare/images-v1.3.8...images-v1.3.9) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.4 to ^4.4.5 - -## [1.3.8](https://github.com/netlify/primitives/compare/images-v1.3.7...images-v1.3.8) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.3 to ^4.4.4 - -## [1.3.7](https://github.com/netlify/primitives/compare/images-v1.3.6...images-v1.3.7) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.2 to ^4.4.3 - -## [1.3.6](https://github.com/netlify/primitives/compare/images-v1.3.5...images-v1.3.6) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.1 to ^4.4.2 - -## [1.3.5](https://github.com/netlify/primitives/compare/images-v1.3.4...images-v1.3.5) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.0 to ^4.4.1 - -## [1.3.4](https://github.com/netlify/primitives/compare/images-v1.3.3...images-v1.3.4) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.3 to ^4.4.0 - -## [1.3.3](https://github.com/netlify/primitives/compare/images-v1.3.2...images-v1.3.3) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.2 to ^4.3.3 - -## [1.3.2](https://github.com/netlify/primitives/compare/images-v1.3.1...images-v1.3.2) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.1 to ^4.3.2 - -## [1.3.1](https://github.com/netlify/primitives/compare/images-v1.3.0...images-v1.3.1) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.0 to ^4.3.1 - -## [1.3.0](https://github.com/netlify/primitives/compare/images-v1.2.8...images-v1.3.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.2.0 to ^4.3.0 - -## [1.2.8](https://github.com/netlify/primitives/compare/images-v1.2.7...images-v1.2.8) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.3 to ^4.2.0 - -## [1.2.7](https://github.com/netlify/primitives/compare/images-v1.2.6...images-v1.2.7) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.2 to ^4.1.3 - -## [1.2.6](https://github.com/netlify/primitives/compare/images-v1.2.5...images-v1.2.6) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.1 to ^4.1.2 - -## [1.2.5](https://github.com/netlify/primitives/compare/images-v1.2.4...images-v1.2.5) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.0 to ^4.1.1 - -## [1.2.4](https://github.com/netlify/primitives/compare/images-v1.2.3...images-v1.2.4) (2025-07-24) - - -### Bug Fixes - -* **deps:** update dependency ipx to v3.1.1 ([#391](https://github.com/netlify/primitives/issues/391)) ([e186aac](https://github.com/netlify/primitives/commit/e186aac06ed142757f8a081b55c9dcc417d06657)) - -## [1.2.3](https://github.com/netlify/primitives/compare/images-v1.2.2...images-v1.2.3) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.0.0 to ^4.1.0 - -## [1.2.2](https://github.com/netlify/primitives/compare/images-v1.2.1...images-v1.2.2) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.3.0 to ^4.0.0 - -## [1.2.1](https://github.com/netlify/primitives/compare/images-v1.2.0...images-v1.2.1) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.2 to ^3.3.0 - -## [1.2.0](https://github.com/netlify/primitives/compare/images-v1.1.2...images-v1.2.0) (2025-07-15) - - -### Features - -* add `images.remoteURLPatterns` option to `NetlifyDev` ([#348](https://github.com/netlify/primitives/issues/348)) ([606e264](https://github.com/netlify/primitives/commit/606e26475c88a47f41929c5548820f2886094b3a)) - -## [1.1.2](https://github.com/netlify/primitives/compare/images-v1.1.1...images-v1.1.2) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.1 to ^3.2.2 - -## [1.1.1](https://github.com/netlify/primitives/compare/images-v1.1.0...images-v1.1.1) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.0 to ^3.2.1 - -## [1.1.0](https://github.com/netlify/primitives/compare/images-v1.0.0...images-v1.1.0) (2025-06-17) - - -### Features - -* add `serverAddress` to request handler ([#308](https://github.com/netlify/primitives/issues/308)) ([fa811f2](https://github.com/netlify/primitives/commit/fa811f24d473d471108f560abc484d17ea11bd70)) - -## 1.0.0 (2025-06-06) - - -### Features - -* image cdn support ([#232](https://github.com/netlify/primitives/issues/232)) ([01c844d](https://github.com/netlify/primitives/commit/01c844d82a27a9812be7634219d9bdc69a128985)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.1.1 to ^3.2.0 - -## Changelog diff --git a/packages/images/package.json b/packages/images/package.json deleted file mode 100644 index 8e345b5..0000000 --- a/packages/images/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "@netlify/images", - "version": "1.3.10", - "description": "TypeScript implementation of Netlify's Image CDN", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.js", - "exports": "./dist/main.js", - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/images" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "directories": { - "test": "test" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "tsup": "^8.5.0", - "vitest": "^3.1.4" - }, - "dependencies": { - "ipx": "^3.1.1" - } -} diff --git a/packages/images/src/main.test.ts b/packages/images/src/main.test.ts deleted file mode 100644 index 8411f8c..0000000 --- a/packages/images/src/main.test.ts +++ /dev/null @@ -1,369 +0,0 @@ -import { createImageServerHandler, createMockLogger, getImageResponseSize, HTTPServer } from '@netlify/dev-utils' -import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest' -import { createIPXWebServer } from 'ipx' - -import { ImageHandler } from './main.js' - -const mockedIpxResponse = new Response('Mocked response from IPX') - -vi.mock('ipx', async () => { - return { - ...(await vi.importActual('ipx')), - createIPXWebServer: vi.fn(() => () => Promise.resolve(mockedIpxResponse.clone())), - } -}) - -const mockCreateIPXWebServer = vi.mocked(createIPXWebServer) - -beforeEach(() => { - mockCreateIPXWebServer.mockReset() -}) - -describe('`ImageHandler`', () => { - describe('constructor', () => { - test('warns about malformed remote image patterns', () => { - const logger = { ...createMockLogger(), warn: vi.fn() } - - new ImageHandler({ - logger, - imagesConfig: { - remote_images: ['https://example.com/images/.*', 'invalid-regex['], - }, - }) - - expect(logger.warn).toHaveBeenCalledWith( - 'Malformed remote image pattern: "invalid-regex[": Invalid regular expression: /invalid-regex[/: Unterminated character class. Skipping it.', - ) - }) - }) - - describe('match', () => { - describe('image endpoints', () => { - test('matches on `/.netlify/images', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const url = new URL('/.netlify/images', 'https://netlify.com') - url.searchParams.set('url', 'image.png') - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle('http://localhost:5173') - - expect(response.ok).toBe(true) - expect(response).toMatchObject(mockedIpxResponse) - }) - - test('matches on `/.netlify/images/', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const url = new URL('/.netlify/images/', 'https://netlify.com') - url.searchParams.set('url', 'image.png') - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle('http://localhost:5173') - - expect(response.ok).toBe(true) - expect(response).toMatchObject(mockedIpxResponse) - }) - - test('does not match on `/.netlify/foo', () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const url = new URL('/.netlify/foo', 'https://netlify.com') - url.searchParams.set('url', 'image.png') - - const match = imageHandler.match(new Request(url)) - - expect(match).not.toBeDefined() - }) - }) - - describe('request methods', () => { - test('allows GET requests', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const url = new URL('/.netlify/images', 'https://netlify.com') - url.searchParams.set('url', 'image.png') - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle('http://localhost:5173') - - expect(response.ok).toBe(true) - expect(response).toMatchObject(mockedIpxResponse) - }) - - test('does not allow POST requests', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const url = new URL('/.netlify/images', 'https://netlify.com') - url.searchParams.set('url', 'image.png') - - const match = imageHandler.match(new Request(url, { method: 'POST' })) - - expect(match).toBeDefined() - - const response = await match!.handle('http://localhost:5173') - - expect(response.ok).toBe(false) - expect(await response.text()).toBe('Method Not Allowed') - }) - }) - - describe('local images', () => { - let originServerAddress: string - let originServer: HTTPServer - - const LOCAL_IMAGE_PATH = '/local/image.jpg' - const LOCAL_IMAGE_WIDTH = 800 - const LOCAL_IMAGE_HEIGHT = 400 - - beforeAll(async () => { - originServer = new HTTPServer( - createImageServerHandler((url: URL) => { - if (url.pathname === LOCAL_IMAGE_PATH) { - return { width: LOCAL_IMAGE_WIDTH, height: LOCAL_IMAGE_HEIGHT } - } - return null - }), - ) - - originServerAddress = await originServer.start() - }) - - afterAll(async () => { - await originServer.stop() - }) - - beforeEach(async () => { - mockCreateIPXWebServer.mockImplementation( - (await vi.importActual('ipx')).createIPXWebServer, - ) - }) - - test('preserves original width if width param is not used', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const url = new URL('/.netlify/images', originServerAddress) - url.searchParams.set('url', LOCAL_IMAGE_PATH) - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle(originServerAddress) - - expect(response.ok).toBe(true) - - const { width } = await getImageResponseSize(response) - - expect(width).toBe(LOCAL_IMAGE_WIDTH) - }) - - test('resizes image to specified width preserving aspect ratio', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const requestedWidth = 200 - - const url = new URL('/.netlify/images', originServerAddress) - url.searchParams.set('url', LOCAL_IMAGE_PATH) - url.searchParams.set('w', requestedWidth.toString()) - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle(originServerAddress) - - expect(response.ok).toBe(true) - - const { width, height } = await getImageResponseSize(response) - - expect(width).toBe(requestedWidth) - expect(width / height).toBe(LOCAL_IMAGE_WIDTH / LOCAL_IMAGE_HEIGHT) - }) - - test('resizes image to specified height preserving aspect ratio', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const requestedHeight = 200 - - const url = new URL('/.netlify/images', originServerAddress) - url.searchParams.set('url', LOCAL_IMAGE_PATH) - url.searchParams.set('h', requestedHeight.toString()) - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle(originServerAddress) - - expect(response.ok).toBe(true) - - const { width, height } = await getImageResponseSize(response) - - expect(height).toBe(requestedHeight) - expect(width / height).toBe(LOCAL_IMAGE_WIDTH / LOCAL_IMAGE_HEIGHT) - }) - - test('resizes image to specified width and height ignoring original aspect ratio', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - }) - - const requestedWidth = 200 - const requestedHeight = 200 - - const url = new URL('/.netlify/images', originServerAddress) - url.searchParams.set('url', LOCAL_IMAGE_PATH) - url.searchParams.set('w', requestedWidth.toString()) - url.searchParams.set('h', requestedHeight.toString()) - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle(originServerAddress) - - expect(response.ok).toBe(true) - - const { width, height } = await getImageResponseSize(response) - - expect(width).toBe(requestedWidth) - expect(height).toBe(requestedHeight) - expect(width / height).not.toBe(LOCAL_IMAGE_WIDTH / LOCAL_IMAGE_HEIGHT) - }) - }) - - describe('remote images', () => { - let remoteServerAddress: string - let remoteServer: HTTPServer - - const IMAGE_WIDTH = 800 - const IMAGE_HEIGHT = 400 - - beforeAll(async () => { - remoteServer = new HTTPServer( - createImageServerHandler(() => { - return { width: IMAGE_WIDTH, height: IMAGE_HEIGHT } - }), - ) - - remoteServerAddress = await remoteServer.start() - }) - - afterAll(async () => { - await remoteServer.stop() - }) - - test('allow remote images matching configured patterns', async () => { - mockCreateIPXWebServer.mockImplementation( - (await vi.importActual('ipx')).createIPXWebServer, - ) - - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - imagesConfig: { - remote_images: [`^${remoteServerAddress}/.*`], - }, - }) - - const requestedWidth = 100 - - const url = new URL('/.netlify/images', 'https://netlify.com') - url.searchParams.set('url', remoteServerAddress) - url.searchParams.set('w', requestedWidth.toString()) - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle('https://example.netlify') - - expect(response.ok).toBe(true) - - const { width, height } = await getImageResponseSize(response) - - expect(width).toBe(requestedWidth) - expect(width / height).toBe(IMAGE_WIDTH / IMAGE_HEIGHT) - }, 30_000) - - test('allow matching any remote image when using a wildcard pattern', async () => { - mockCreateIPXWebServer.mockImplementation( - (await vi.importActual('ipx')).createIPXWebServer, - ) - - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - imagesConfig: { - remote_images: [`(.*)`], - }, - }) - - const requestedWidth = 100 - - const url = new URL('/.netlify/images', 'https://netlify.com') - url.searchParams.set('url', remoteServerAddress) - url.searchParams.set('w', requestedWidth.toString()) - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle('https://example.netlify') - - expect(response.ok).toBe(true) - - const { width, height } = await getImageResponseSize(response) - - expect(width).toBe(requestedWidth) - expect(width / height).toBe(IMAGE_WIDTH / IMAGE_HEIGHT) - }, 30_000) - - test('does not allow remote images not matching configured patterns', async () => { - const imageHandler = new ImageHandler({ - logger: createMockLogger(), - imagesConfig: { - remote_images: [], - }, - }) - - const url = new URL('/.netlify/images', 'https://netlify.com') - url.searchParams.set('url', remoteServerAddress) - url.searchParams.set('w', '100') - - const match = imageHandler.match(new Request(url)) - - expect(match).toBeDefined() - - const response = await match!.handle('https://example.netlify') - - expect(response.status).toBe(403) - expect(await response.text()).toBe('Forbidden: Remote image URL not allowed') - }) - }) - }) -}) diff --git a/packages/images/src/main.ts b/packages/images/src/main.ts deleted file mode 100644 index 995de52..0000000 --- a/packages/images/src/main.ts +++ /dev/null @@ -1,133 +0,0 @@ -import type { Logger } from '@netlify/dev-utils' -import { createIPX, createIPXWebServer, ipxFSStorage, ipxHttpStorage } from 'ipx' - -interface ImagesConfig { - remote_images: string[] -} - -interface ImageHandlerOptions { - imagesConfig?: ImagesConfig - logger: Logger - originServerAddress?: string -} - -export interface ImageMatch { - handle: (originServerAddress: string) => Promise -} - -const IMAGE_CDN_ENDPOINTS = ['/.netlify/images', '/.netlify/images/'] - -export class ImageHandler { - #allowedRemoteUrlPatterns: RegExp[] - #logger: Logger - - constructor({ logger, imagesConfig }: ImageHandlerOptions) { - this.#logger = logger - this.#allowedRemoteUrlPatterns = (imagesConfig?.remote_images ?? []).reduce((acc, stringPattern) => { - try { - acc.push(new RegExp(stringPattern)) - } catch (maybeError) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)) - this.#logger.warn(`Malformed remote image pattern: "${stringPattern}": ${error.message}. Skipping it.`) - } - return acc - }, []) - } - - private generateIPXRequestURL(imageURL: URL, netlifyImageCdnParams: URLSearchParams): URL { - const ipxParams: string[] = [] - - const width = netlifyImageCdnParams.get('w') ?? netlifyImageCdnParams.get('width') - const height = netlifyImageCdnParams.get('h') ?? netlifyImageCdnParams.get('height') - - if (width && height) { - ipxParams.push(`resize_${width}x${height}`) - } else if (width) { - ipxParams.push(`width_${width}`) - } else if (height) { - ipxParams.push(`height_${height}`) - } - - const quality = netlifyImageCdnParams.get('q') ?? netlifyImageCdnParams.get('quality') - if (quality) { - ipxParams.push(`quality_${quality}`) - } - const format = netlifyImageCdnParams.get('fm') - if (format) { - ipxParams.push(`format_${format}`) - } - - const fit = netlifyImageCdnParams.get('fit') - if (fit) { - ipxParams.push(`fit_${fit === 'contain' ? 'inside' : fit}`) - } - - const position = netlifyImageCdnParams.get('position') - if (position) { - ipxParams.push(`position_${position}`) - } - - const ipxModifiers = ipxParams.join(',') - - return new URL(`/${ipxModifiers || `_`}/${encodeURIComponent(imageURL.href)}`, imageURL.origin) - } - - match(request: Request): ImageMatch | undefined { - const url = new URL(request.url) - - if (!IMAGE_CDN_ENDPOINTS.includes(url.pathname)) { - return - } - - return { - handle: async (originServerAddress: string) => { - if (request.method !== 'GET') { - return new Response('Method Not Allowed', { status: 405 }) - } - - const sourceImageUrlParam = url.searchParams.get('url') - if (!sourceImageUrlParam) { - return new Response('Bad Request: Missing "url" query parameter', { status: 400 }) - } - - const originServerURL = originServerAddress ? new URL(originServerAddress) : null - - let sourceImageUrl: URL - try { - sourceImageUrl = new URL(sourceImageUrlParam, String(originServerURL)) - } catch (error) { - throw new Error( - `Failed to construct source image URL from "${sourceImageUrlParam}".` + - (!originServerURL && !sourceImageUrlParam.startsWith('http') - ? '\nLooks like source image is local and `originServerAddress` was not provided.' - : ''), - { cause: error }, - ) - } - - // if it's not local image, check if it's allowed - if ( - sourceImageUrl.origin !== originServerURL?.origin && - !this.#allowedRemoteUrlPatterns.some((allowedRemoteUrlPattern) => - allowedRemoteUrlPattern.test(sourceImageUrl.href), - ) - ) { - return new Response('Forbidden: Remote image URL not allowed', { status: 403 }) - } - - const ipx = createIPX({ - storage: ipxFSStorage(), - httpStorage: ipxHttpStorage({ - // checking if url is allowed is done above, so we disable IPX checking - allowAllDomains: true, - }), - }) - - const ipxHandler = createIPXWebServer(ipx) - - const ipxRequest = new Request(this.generateIPXRequestURL(sourceImageUrl, url.searchParams), request) - return ipxHandler(ipxRequest) - }, - } - } -} diff --git a/packages/images/tsconfig.json b/packages/images/tsconfig.json deleted file mode 100644 index 7b592ea..0000000 --- a/packages/images/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/images/tsup.config.ts b/packages/images/tsup.config.ts deleted file mode 100644 index 9a08857..0000000 --- a/packages/images/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['esm'], - entry: ['src/main.ts'], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/nuxt-module/.nuxtrc b/packages/nuxt-module/.nuxtrc new file mode 100644 index 0000000..1e78080 --- /dev/null +++ b/packages/nuxt-module/.nuxtrc @@ -0,0 +1 @@ +setups.@nuxt/test-utils="3.23.0" \ No newline at end of file diff --git a/packages/otel/.gitattributes b/packages/otel/.gitattributes deleted file mode 100644 index 6313b56..0000000 --- a/packages/otel/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto eol=lf diff --git a/packages/otel/.gitignore b/packages/otel/.gitignore deleted file mode 100644 index 6a5f751..0000000 --- a/packages/otel/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -*~ -*.swp -npm-debug.log -node_modules -/core -.eslintcache -.npmrc -.yarn-error.log -/coverage -/build -.vscode -/dist diff --git a/packages/otel/CHANGELOG.md b/packages/otel/CHANGELOG.md deleted file mode 100644 index 2a9e591..0000000 --- a/packages/otel/CHANGELOG.md +++ /dev/null @@ -1,251 +0,0 @@ -# Changelog - -## [6.0.3](https://github.com/netlify/primitives/compare/otel-v6.0.2...otel-v6.0.3) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.5 to ^4.4.6 - -## [6.0.2](https://github.com/netlify/primitives/compare/otel-v6.0.1...otel-v6.0.2) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.4 to ^4.4.5 - -## [6.0.1](https://github.com/netlify/primitives/compare/otel-v6.0.0...otel-v6.0.1) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.3 to ^4.4.4 - -## [6.0.0](https://github.com/netlify/primitives/compare/otel-v5.1.5...otel-v6.0.0) (2026-05-11) - - -### ⚠ BREAKING CHANGES - -* **otel:** Consumers implementing their own SpanExporter that read ReadableSpan.parentSpanId or ReadableSpan.instrumentationLibrary must update to the 2.x field names. - -### Features - -* **otel:** upgrade to OpenTelemetry JS 2.x ([#682](https://github.com/netlify/primitives/issues/682)) ([2d14e46](https://github.com/netlify/primitives/commit/2d14e46e5ae042210b6db91a8b96588b89e8b767)) - -## [5.1.5](https://github.com/netlify/primitives/compare/otel-v5.1.4...otel-v5.1.5) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.2 to ^4.4.3 - -## [5.1.4](https://github.com/netlify/primitives/compare/otel-v5.1.3...otel-v5.1.4) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.1 to ^4.4.2 - -## [5.1.3](https://github.com/netlify/primitives/compare/otel-v5.1.2...otel-v5.1.3) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.0 to ^4.4.1 - -## [5.1.2](https://github.com/netlify/primitives/compare/otel-v5.1.1...otel-v5.1.2) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.3 to ^4.4.0 - -## [5.1.1](https://github.com/netlify/primitives/compare/otel-v5.1.0...otel-v5.1.1) (2025-12-16) - - -### Bug Fixes - -* instrumentation headers type safety ([#560](https://github.com/netlify/primitives/issues/560)) ([0352005](https://github.com/netlify/primitives/commit/0352005c2613fdb9683ba41e43af7f54018eb719)) - -## [5.1.0](https://github.com/netlify/primitives/compare/otel-v5.0.1...otel-v5.1.0) (2025-12-08) - - -### Features - -* HttpInstrumentation ([#555](https://github.com/netlify/primitives/issues/555)) ([a666b89](https://github.com/netlify/primitives/commit/a666b89259be76fb8d88b5a4b87f7895ca8f6480)) -* non-conflicting fetch instrumentation ([#554](https://github.com/netlify/primitives/issues/554)) ([412986e](https://github.com/netlify/primitives/commit/412986e35e65da8b31ad5048d4e2a7eae1b2f6f0)) - - -### Bug Fixes - -* support skipURLs property in http instrumentation ([#559](https://github.com/netlify/primitives/issues/559)) ([d0cfcd3](https://github.com/netlify/primitives/commit/d0cfcd389b66aad18ddbcc852c9ac0db933566ae)) - -## [5.0.1](https://github.com/netlify/primitives/compare/otel-v5.0.0...otel-v5.0.1) (2025-12-03) - - -### Bug Fixes - -* prevent multiple instances of the tracer provider ([#545](https://github.com/netlify/primitives/issues/545)) ([0225010](https://github.com/netlify/primitives/commit/0225010a8d2caf553a4313d43889f9409a7fba94)) - -## [5.0.0](https://github.com/netlify/primitives/compare/otel-v4.3.2...otel-v5.0.0) (2025-11-17) - - -### ⚠ BREAKING CHANGES - -* use static imports ([#530](https://github.com/netlify/primitives/issues/530)) - -### Features - -* use static imports ([#530](https://github.com/netlify/primitives/issues/530)) ([c78f7ad](https://github.com/netlify/primitives/commit/c78f7ad0189ec52eb6eebbf59da0eefd795e979b)) - - -### Bug Fixes - -* replace otlp exporter with local implementation ([#531](https://github.com/netlify/primitives/issues/531)) ([2d6b30a](https://github.com/netlify/primitives/commit/2d6b30a260064e4de56a681e398bf06778a2978c)) - -## [4.3.2](https://github.com/netlify/primitives/compare/otel-v4.3.1...otel-v4.3.2) (2025-10-27) - - -### Bug Fixes - -* set span error states when fetch operations fail ([#501](https://github.com/netlify/primitives/issues/501)) ([63938b0](https://github.com/netlify/primitives/commit/63938b089d7f060f6d0ecde69afc0f716a36bbf8)) - -## [4.3.1](https://github.com/netlify/primitives/compare/otel-v4.3.0...otel-v4.3.1) (2025-10-22) - - -### Bug Fixes - -* export enums by reference instead of as types ([#497](https://github.com/netlify/primitives/issues/497)) ([292304a](https://github.com/netlify/primitives/commit/292304a5536791a8d186f2cbebf8f5f854fbf7db)) - -## [4.3.0](https://github.com/netlify/primitives/compare/otel-v4.2.0...otel-v4.3.0) (2025-10-10) - - -### Features - -* add trace to otel exports ([#473](https://github.com/netlify/primitives/issues/473)) ([ecc4ec5](https://github.com/netlify/primitives/commit/ecc4ec53e91aef20d1c2009e08582c07f5e01470)) - -## [4.2.0](https://github.com/netlify/primitives/compare/otel-v4.1.0...otel-v4.2.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - -## [4.1.0](https://github.com/netlify/primitives/compare/otel-v4.0.0...otel-v4.1.0) (2025-10-09) - - -### Features - -* extend list of exported otel classes ([#467](https://github.com/netlify/primitives/issues/467)) ([a9b059f](https://github.com/netlify/primitives/commit/a9b059f7ea6ddf8683f520f267a3216c3ab7d9a4)) - -## [4.0.0](https://github.com/netlify/primitives/compare/otel-v3.4.1...otel-v4.0.0) (2025-09-23) - - -### ⚠ BREAKING CHANGES - -* add `spanProcessors` property ([#460](https://github.com/netlify/primitives/issues/460)) - -### Features - -* add `spanProcessors` property ([#460](https://github.com/netlify/primitives/issues/460)) ([039f955](https://github.com/netlify/primitives/commit/039f955d5de232f7cc1ee57e36a04233b14a2adb)) - -## [3.4.1](https://github.com/netlify/primitives/compare/otel-v3.4.0...otel-v3.4.1) (2025-08-26) - - -### Bug Fixes - -* don't reüse used request in otel fetch ([#435](https://github.com/netlify/primitives/issues/435)) ([6d755f6](https://github.com/netlify/primitives/commit/6d755f6a081169f5b59b132c03e65bf955debc91)) - -## [3.4.0](https://github.com/netlify/primitives/compare/otel-v3.3.1...otel-v3.4.0) (2025-08-05) - - -### Features - -* Add skipping and redacting of headers ([#404](https://github.com/netlify/primitives/issues/404)) ([7bcfe6d](https://github.com/netlify/primitives/commit/7bcfe6d636869edbf035da8a815d00a5979044c8)) - -## [3.3.1](https://github.com/netlify/primitives/compare/otel-v3.3.0...otel-v3.3.1) (2025-07-29) - - -### Bug Fixes - -* Add exporter-netlify and instrumentation-fetch to exports ([#400](https://github.com/netlify/primitives/issues/400)) ([5a6c6f6](https://github.com/netlify/primitives/commit/5a6c6f616f165debe1fe6cff5dbc4a4224327220)) - -## [3.3.0](https://github.com/netlify/primitives/compare/otel-v3.2.0...otel-v3.3.0) (2025-07-28) - - -### Features - -* a minimal fetch instrumentation ([#383](https://github.com/netlify/primitives/issues/383)) ([744a3a3](https://github.com/netlify/primitives/commit/744a3a39851800fd7220080e7322b8ed38b84391)) - -## [3.2.0](https://github.com/netlify/primitives/compare/otel-v3.1.0...otel-v3.2.0) (2025-07-24) - - -### Features - -* Add @netlify/otel affordances ([#363](https://github.com/netlify/primitives/issues/363)) ([50fae00](https://github.com/netlify/primitives/commit/50fae00cfae69fcfeed18f24e39f51066cdbcee0)) - -## [3.1.0](https://github.com/netlify/primitives/compare/otel-v3.0.2...otel-v3.1.0) (2025-07-10) - - -### Features - -* make getTracer a sync function so it can be used in sync and async contexts ([#339](https://github.com/netlify/primitives/issues/339)) ([62e7ede](https://github.com/netlify/primitives/commit/62e7ede177212baaf1939220eba1dc91ac3460b4)) - -## [3.0.2](https://github.com/netlify/primitives/compare/otel-v3.0.1...otel-v3.0.2) (2025-06-03) - - -### Bug Fixes - -* bring back node 18.14 support by using older version of the @opentelemetry/otlp-transformer package ([#276](https://github.com/netlify/primitives/issues/276)) ([78d156c](https://github.com/netlify/primitives/commit/78d156cdc520a2b53a5d1830b95a4a58cae445f2)) - -## [3.0.1](https://github.com/netlify/primitives/compare/otel-v3.0.0...otel-v3.0.1) (2025-06-03) - - -### Bug Fixes - -* bring back node18 support by using older versions of the otel packages ([#271](https://github.com/netlify/primitives/issues/271)) ([e8ddc2e](https://github.com/netlify/primitives/commit/e8ddc2e8ed8378d5ca162ed3f681aa9b409db6d1)) - -## [3.0.0](https://github.com/netlify/primitives/compare/otel-v2.0.0...otel-v3.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Bug Fixes - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) - -## [2.0.0](https://github.com/netlify/primitives/compare/otel-v1.1.0...otel-v2.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - -## [1.1.0](https://github.com/netlify/primitives/compare/otel-v1.0.0...otel-v1.1.0) (2025-05-12) - - -### Features - -* **otel:** initialize OpenTelemetry package with tracer provider and span exporter ([#188](https://github.com/netlify/primitives/issues/188)) ([4056cc4](https://github.com/netlify/primitives/commit/4056cc4d1631ac0b7f94b7aac578a0e7b48defb6)) - -## Changelog diff --git a/packages/otel/CODE_OF_CONDUCT.md b/packages/otel/CODE_OF_CONDUCT.md deleted file mode 100644 index fad7632..0000000 --- a/packages/otel/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,60 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making -participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, -disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take -appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, -issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any -contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the -project or its community. Examples of representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed representative at an online or offline -event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at -david@netlify.com. All complaints will be reviewed and investigated and will result in a response that is deemed -necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to -the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent -repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at -[http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/packages/otel/CONTRIBUTING.md b/packages/otel/CONTRIBUTING.md deleted file mode 100644 index 5dfd0c0..0000000 --- a/packages/otel/CONTRIBUTING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributions - -🎉 Thanks for considering contributing to this project! 🎉 - -These guidelines will help you send a pull request. - -Please note that this project is not intended to be used outside my own projects so new features are unlikely to be -accepted. - -If you're submitting an issue instead, please skip this document. - -If your pull request is related to a typo or the documentation being unclear, please click on the relevant page's `Edit` -button (pencil icon) and directly suggest a correction instead. - -This project was made with ❤️. The simplest way to give back is by starring and sharing it online. - -Everyone is welcome regardless of personal background. We enforce a [Code of conduct](CODE_OF_CONDUCT.md) in order to -promote a positive and inclusive environment. - -# Development process - -First fork and clone the repository. If you're not sure how to do this, please watch -[these videos](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). - -Run: - -```bash -npm install -``` - -Make sure everything is correctly setup with: - -```bash -npm test -``` - -After submitting the pull request, please make sure the Continuous Integration checks are passing. - -## Releasing - -1. Merge the release PR -2. Switch to the default branch `git checkout main` -3. Pull latest changes `git pull` -4. Publish the package `npm publish` diff --git a/packages/otel/LICENSE b/packages/otel/LICENSE deleted file mode 100644 index 182fc3f..0000000 --- a/packages/otel/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2022 Netlify - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/otel/README.md b/packages/otel/README.md deleted file mode 100644 index c4949cd..0000000 --- a/packages/otel/README.md +++ /dev/null @@ -1,14 +0,0 @@ -[![Build](https://github.com/netlify/primitives/workflows/Build/badge.svg)](https://github.com/netlify/primitives/actions) -[![Node](https://img.shields.io/node/v/@netlify/otel.svg?logo=node.js)](https://www.npmjs.com/package/@netlify/otel) - -# @netlify/otel - -TypeScript utilities to interact with Netlify's OpenTelemetry - -## Installation - -You can install `@netlify/otel` via npm: - -```shell -npm install @netlify/otel -``` diff --git a/packages/otel/package.json b/packages/otel/package.json deleted file mode 100644 index c870e97..0000000 --- a/packages/otel/package.json +++ /dev/null @@ -1,141 +0,0 @@ -{ - "name": "@netlify/otel", - "version": "6.0.3", - "type": "module", - "engines": { - "node": "^18.14.0 || >=20.6.1" - }, - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - }, - "./package.json": "./package.json", - "./bootstrap": { - "require": { - "types": "./dist/bootstrap/main.d.cts", - "default": "./dist/bootstrap/main.cjs" - }, - "import": { - "types": "./dist/bootstrap/main.d.ts", - "default": "./dist/bootstrap/main.js" - }, - "default": { - "types": "./dist/bootstrap/main.d.ts", - "default": "./dist/bootstrap/main.js" - } - }, - "./exporter-netlify": { - "require": { - "types": "./dist/exporters/netlify.d.cts", - "default": "./dist/exporters/netlify.cjs" - }, - "import": { - "types": "./dist/exporters/netlify.d.ts", - "default": "./dist/exporters/netlify.js" - }, - "default": { - "types": "./dist/exporters/netlify.d.ts", - "default": "./dist/exporters/netlify.js" - } - }, - "./instrumentation-fetch": { - "require": { - "types": "./dist/instrumentations/fetch.d.cts", - "default": "./dist/instrumentations/fetch.cjs" - }, - "import": { - "types": "./dist/instrumentations/fetch.d.ts", - "default": "./dist/instrumentations/fetch.js" - }, - "default": { - "types": "./dist/instrumentations/fetch.d.ts", - "default": "./dist/instrumentations/fetch.js" - } - }, - "./instrumentation-http": { - "require": { - "types": "./dist/instrumentations/http.d.cts", - "default": "./dist/instrumentations/http.cjs" - }, - "import": { - "types": "./dist/instrumentations/http.d.ts", - "default": "./dist/instrumentations/http.js" - }, - "default": { - "types": "./dist/instrumentations/http.d.ts", - "default": "./dist/instrumentations/http.js" - } - }, - "./opentelemetry": { - "require": { - "types": "./dist/opentelemetry.d.cts", - "default": "./dist/opentelemetry.cjs" - }, - "import": { - "types": "./dist/opentelemetry.d.ts", - "default": "./dist/opentelemetry.js" - }, - "default": { - "types": "./dist/opentelemetry.d.ts", - "default": "./dist/opentelemetry.js" - } - } - }, - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "dev": "tsup-node --watch", - "prepack": "npm run build", - "test": "run-s build test:ci", - "test:dev": "run-s build test:dev:*", - "test:ci": "run-s build test:ci:*", - "test:dev:vitest": "vitest", - "test:dev:vitest:watch": "vitest watch", - "test:ci:vitest": "vitest run", - "publint": "npx -y publint --strict" - }, - "keywords": [ - "netlify", - "cdn" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/otel" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "msw": "^2.10.5", - "npm-run-all2": "^7.0.2", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - }, - "dependencies": { - "@opentelemetry/api": "1.9.0", - "@opentelemetry/core": "2.7.1", - "@opentelemetry/instrumentation": "^0.217.0", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/sdk-trace-node": "2.7.1" - } -} diff --git a/packages/otel/src/bootstrap/main.ts b/packages/otel/src/bootstrap/main.ts deleted file mode 100644 index 8b3b4c0..0000000 --- a/packages/otel/src/bootstrap/main.ts +++ /dev/null @@ -1,86 +0,0 @@ -import process from 'node:process' - -import { trace } from '@opentelemetry/api' -import { SugaredTracer } from '@opentelemetry/api/experimental' -import { resourceFromAttributes } from '@opentelemetry/resources' -import { type Instrumentation, registerInstrumentations } from '@opentelemetry/instrumentation' -import { W3CTraceContextPropagator } from '@opentelemetry/core' -import { NodeTracerProvider, SimpleSpanProcessor, type SpanProcessor } from '@opentelemetry/sdk-trace-node' - -import { GET_TRACER, SHUTDOWN_TRACERS } from '../constants.js' -import { NetlifySpanExporter } from '../exporters/netlify.js' -import packageJson from '../../package.json' with { type: 'json' } - -export interface TracerProviderOptions { - serviceName: string - serviceVersion: string - deploymentEnvironment: string - siteUrl: string - siteId: string - siteName: string - instrumentations?: Instrumentation[] - spanProcessors?: SpanProcessor[] -} - -export const createTracerProvider = (options: TracerProviderOptions) => { - // Prevent multiple tracers from being created - if (Object.prototype.hasOwnProperty.call(globalThis, GET_TRACER)) return - - // remove the v prefix from the version to match the spec - const runtimeVersion = process.version.slice(1) - - const resource = resourceFromAttributes({ - 'service.name': options.serviceName, - 'service.version': options.serviceVersion, - 'process.runtime.name': 'nodejs', - 'process.runtime.version': runtimeVersion, - 'deployment.environment': options.deploymentEnvironment, - 'http.url': options.siteUrl, - 'netlify.site.id': options.siteId, - 'netlify.site.name': options.siteName, - }) - - const spanProcessors = options.spanProcessors ?? [getBaseSpanProcessor()] - - const nodeTracerProvider = new NodeTracerProvider({ - resource, - spanProcessors, - }) - - nodeTracerProvider.register({ - propagator: new W3CTraceContextPropagator(), - }) - - const instrumentations = options.instrumentations ?? [] - - registerInstrumentations({ - instrumentations, - tracerProvider: nodeTracerProvider, - }) - - Object.defineProperty(globalThis, GET_TRACER, { - enumerable: false, - configurable: true, - writable: false, - value: function getTracer(name?: string, version?: string) { - if (name) { - return new SugaredTracer(trace.getTracer(name, version)) - } - - return new SugaredTracer(trace.getTracer(packageJson.name, packageJson.version)) - }, - }) - - Object.defineProperty(globalThis, SHUTDOWN_TRACERS, { - enumerable: false, - configurable: true, - writable: false, - value: async () => { - return await nodeTracerProvider.shutdown() - }, - }) -} - -export const getBaseSpanProcessor = (): SpanProcessor => { - return new SimpleSpanProcessor(new NetlifySpanExporter()) -} diff --git a/packages/otel/src/constants.ts b/packages/otel/src/constants.ts deleted file mode 100644 index 3262a66..0000000 --- a/packages/otel/src/constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const GET_TRACER = '__netlify__getTracer' -export const SHUTDOWN_TRACERS = '__netlify__shutdownTracers' -export const TRACE_PREFIX = '__nfOTLPTrace' diff --git a/packages/otel/src/exporters/netlify.test.ts b/packages/otel/src/exporters/netlify.test.ts deleted file mode 100644 index 11d4692..0000000 --- a/packages/otel/src/exporters/netlify.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { serializeSpans } from './netlify.ts' -import { SpanKind, SpanStatusCode, TraceFlags } from '@opentelemetry/api' -import { TraceState } from '@opentelemetry/core' -import { resourceFromAttributes } from '@opentelemetry/resources' -import { ReadableSpan } from '@opentelemetry/sdk-trace-node' -import { describe, test, expect } from 'vitest' - -function createSpan(): ReadableSpan { - return { - name: 'span-name', - kind: SpanKind.INTERNAL, - spanContext: () => ({ - spanId: '0000000000000002', - traceFlags: TraceFlags.SAMPLED, - traceId: '00000000000000000000000000000001', - isRemote: false, - traceState: new TraceState('span=bar'), - }), - startTime: [1640715557, 342725388], - endTime: [1640715558, 642725388], - status: { - code: SpanStatusCode.OK, - }, - attributes: { 'string-attribute': 'some attribute value' }, - links: [ - { - context: { - spanId: '0000000000000003', - traceId: '00000000000000000000000000000002', - traceFlags: TraceFlags.SAMPLED, - isRemote: false, - traceState: new TraceState('link=foo'), - }, - attributes: { - 'link-attribute': 'string value', - }, - }, - ], - events: [ - { - name: 'event', - time: [1640715558, 542725388], - attributes: { - 'event-attribute': 'string value', - }, - }, - ], - duration: [1, 300000000], - ended: true, - resource: resourceFromAttributes({ - 'service.name': 'serviceName', - 'service.version': 'serviceVersion', - 'process.runtime.name': 'nodejs', - 'process.runtime.version': 'runtimeVersion', - 'deployment.environment': 'deploymentEnvironment', - 'http.url': 'siteUrl', - 'netlify.site.id': 'siteId', - 'netlify.site.name': 'siteName', - }), - instrumentationScope: { - name: '@netlify/otel', - version: '1.0.0', - }, - droppedAttributesCount: 0, - droppedEventsCount: 0, - droppedLinksCount: 0, - } -} - -describe('`serializeSpans`', () => { - test('Returns expected results', () => { - const sampleSpans = [createSpan()] - const result = serializeSpans(sampleSpans) - - const expectedResult = { - resourceSpans: [ - { - resource: { - attributes: [ - { key: 'service.name', value: { stringValue: 'serviceName' } }, - { key: 'service.version', value: { stringValue: 'serviceVersion' } }, - { key: 'process.runtime.name', value: { stringValue: 'nodejs' } }, - { key: 'process.runtime.version', value: { stringValue: 'runtimeVersion' } }, - { key: 'deployment.environment', value: { stringValue: 'deploymentEnvironment' } }, - { key: 'http.url', value: { stringValue: 'siteUrl' } }, - { key: 'netlify.site.id', value: { stringValue: 'siteId' } }, - { key: 'netlify.site.name', value: { stringValue: 'siteName' } }, - ], - droppedAttributesCount: 0, - }, - scopeSpans: [ - { - scope: { name: '@netlify/otel', version: '1.0.0' }, - spans: [ - { - traceId: '00000000000000000000000000000001', - spanId: '0000000000000002', - name: 'span-name', - kind: 1, - startTimeUnixNano: '1640715557342725388', - endTimeUnixNano: '1640715558642725388', - attributes: [{ key: 'string-attribute', value: { stringValue: 'some attribute value' } }], - droppedAttributesCount: 0, - events: [ - { - name: 'event', - timeUnixNano: '1640715558542725388', - attributes: [{ key: 'event-attribute', value: { stringValue: 'string value' } }], - droppedAttributesCount: 0, - }, - ], - droppedEventsCount: 0, - status: { code: 1 }, - links: [ - { - spanId: '0000000000000003', - traceId: '00000000000000000000000000000002', - attributes: [{ key: 'link-attribute', value: { stringValue: 'string value' } }], - droppedAttributesCount: 0, - }, - ], - droppedLinksCount: 0, - }, - ], - }, - ], - }, - ], - } - - expect(result).toEqual(expectedResult) - }) -}) diff --git a/packages/otel/src/exporters/netlify.ts b/packages/otel/src/exporters/netlify.ts deleted file mode 100644 index 5a04254..0000000 --- a/packages/otel/src/exporters/netlify.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { diag, SpanKind, type DiagLogger } from '@opentelemetry/api' -import { BindOnceFuture, ExportResult, ExportResultCode } from '@opentelemetry/core' -import type { SpanExporter, ReadableSpan } from '@opentelemetry/sdk-trace-node' -import { TRACE_PREFIX } from '../constants.ts' - -export class NetlifySpanExporter implements SpanExporter { - #shutdownOnce: BindOnceFuture - #logger: DiagLogger - - constructor() { - this.#shutdownOnce = new BindOnceFuture(this.#shutdown, this) - this.#logger = diag.createComponentLogger({ - namespace: 'netlify-span-exporter', - }) - } - - /** Export spans. */ - export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void { - this.#logger.debug(`export ${spans.length.toString()} spans`) - if (this.#shutdownOnce.isCalled) { - resultCallback({ - code: ExportResultCode.FAILED, - error: new Error('Exporter has been shutdown'), - }) - return - } - - console.log(TRACE_PREFIX, JSON.stringify(serializeSpans(spans))) - resultCallback({ code: ExportResultCode.SUCCESS }) - } - - /** - * Shutdown the exporter. - */ - shutdown(): Promise { - return this.#shutdownOnce.call() - } - - /** - * Called by #shutdownOnce with BindOnceFuture - */ - #shutdown(): Promise { - this.#logger.debug('Shutting down') - return Promise.resolve() - } -} - -// Replaces JsonTraceSerializer.serializeRequest(spans) -export function serializeSpans(spans: ReadableSpan[]): Record { - return { - resourceSpans: spans.map((span) => { - const spanContext = span.spanContext() - return { - resource: { - attributes: toAttributes(span.resource.attributes), - droppedAttributesCount: span.droppedAttributesCount, - }, - scopeSpans: [ - { - scope: { - name: span.instrumentationScope.name, - version: span.instrumentationScope.version, - }, - spans: [ - { - traceId: spanContext.traceId, - spanId: spanContext.spanId, - parentSpanId: span.parentSpanContext?.spanId, - - name: span.name, - kind: span.kind || SpanKind.SERVER, - - startTimeUnixNano: hrTimeToNanos(span.startTime), - endTimeUnixNano: hrTimeToNanos(span.endTime), - - attributes: toAttributes(span.attributes), - droppedAttributesCount: span.droppedAttributesCount, - - events: span.events.map((event) => ({ - name: event.name, - timeUnixNano: hrTimeToNanos(event.time), - attributes: toAttributes(event.attributes ?? {}), - droppedAttributesCount: event.droppedAttributesCount ?? 0, - })), - droppedEventsCount: span.droppedEventsCount, - - status: { - code: span.status.code, - message: span.status.message, - }, - - links: span.links.map((link) => ({ - spanId: link.context.spanId, - traceId: link.context.traceId, - attributes: toAttributes(link.attributes ?? {}), - droppedAttributesCount: link.droppedAttributesCount ?? 0, - })), - droppedLinksCount: span.droppedLinksCount, - }, - ], - }, - ], - } - }), - } -} - -// Reference: opentelemetry-js/experimental/packages/otlp-transformer/src/common/internal.ts - -type IAnyValue = Record - -export function toAttributes(attributes: Record): IAnyValue[] { - return Object.keys(attributes).map((key) => toKeyValue(key, attributes[key])) -} - -function toKeyValue(key: string, value: unknown): IAnyValue { - return { - key: key, - value: toAnyValue(value), - } -} - -function toAnyValue(value: unknown): IAnyValue { - const t = typeof value - if (t === 'string') return { stringValue: value as string } - if (t === 'number') { - if (!Number.isInteger(value)) return { doubleValue: value as number } - return { intValue: value as number } - } - if (t === 'boolean') return { boolValue: value as boolean } - if (value instanceof Uint8Array) return { bytesValue: value } - if (Array.isArray(value)) return { arrayValue: { values: value.map(toAnyValue) } } - if (t === 'object' && value != null) - return { - kvlistValue: { - values: Object.entries(value as object).map(([k, v]) => toKeyValue(k, v)), - }, - } - - return {} -} - -function hrTimeToNanos(hrTime: [number, number]) { - const NANOSECONDS = BigInt(1_000_000_000) - const nanos = BigInt(Math.trunc(hrTime[0])) * NANOSECONDS + BigInt(Math.trunc(hrTime[1])) - return nanos.toString() -} diff --git a/packages/otel/src/instrumentations/fetch.test.ts b/packages/otel/src/instrumentations/fetch.test.ts deleted file mode 100644 index 22738ec..0000000 --- a/packages/otel/src/instrumentations/fetch.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { afterAll, beforeAll, beforeEach, describe, expect, it, test } from 'vitest' -import { FetchInstrumentation } from './fetch.ts' -import { ReadableSpan, SimpleSpanProcessor, SpanExporter } from '@opentelemetry/sdk-trace-node' -import { createTracerProvider } from '../bootstrap/main.ts' -import { HTTPServer } from '@netlify/dev-utils' - -describe('header exclusion', () => { - test('skips configured headers', () => { - const instrumentation = new FetchInstrumentation({ - skipHeaders: ['authorization'], - }) - - // eslint-disable-next-line @typescript-eslint/dot-notation - const attributes = instrumentation['prepareHeaders']( - 'request', - ['a', 'a', 'b', 'b', 'authorization', 'secret'].map((value) => Buffer.from(value)), - ) - expect(attributes).toEqual({ - 'http.request.header.a': 'a', - 'http.request.header.b': 'b', - }) - }) - - test('it skips all headers if so configured', () => { - const everything = new FetchInstrumentation({ - skipHeaders: true, - }) - // eslint-disable-next-line @typescript-eslint/dot-notation - const empty = everything['prepareHeaders']( - 'request', - ['a', 'a', 'b', 'b', 'authorization', 'secret'].map((value) => Buffer.from(value)), - ) - expect(empty).toEqual({}) - }) - - test('redacts configured headers', () => { - const instrumentation = new FetchInstrumentation({ - redactHeaders: ['authorization'], - }) - - // eslint-disable-next-line @typescript-eslint/dot-notation - const attributes = instrumentation['prepareHeaders']( - 'request', - ['a', 'a', 'b', 'b', 'authorization', 'secret'].map((value) => Buffer.from(value)), - ) - expect(attributes['http.request.header.authorization']).not.toBe('secret') - expect(attributes['http.request.header.authorization']).toBeTypeOf('string') - expect(attributes['http.request.header.a']).toBe('a') - expect(attributes['http.request.header.b']).toBe('b') - }) - - test('redacts everything if so requested', () => { - const instrumentation = new FetchInstrumentation({ - redactHeaders: true, - }) - - // eslint-disable-next-line @typescript-eslint/dot-notation - const attributes = instrumentation['prepareHeaders']( - 'request', - ['a', 'a', 'b', 'b', 'authorization', 'secret'].map((value) => Buffer.from(value)), - ) - expect(attributes['http.request.header.authorization']).not.toBe('secret') - expect(attributes['http.request.header.a']).not.toBe('a') - expect(attributes['http.request.header.b']).not.toBe('b') - expect(attributes['http.request.header.authorization']).toBeTypeOf('string') - expect(attributes['http.request.header.a']).toBeTypeOf('string') - expect(attributes['http.request.header.b']).toBeTypeOf('string') - }) -}) - -describe('fetch instrumentation (integration)', () => { - let serverAddress: string - let server: HTTPServer - - class DummySpanExporter implements SpanExporter { - readonly exported: ReadableSpan[][] = [] - - export(spans: ReadableSpan[]) { - this.exported.push(spans) - } - - shutdown() { - return Promise.resolve() - } - - forceFlush(): Promise { - return Promise.resolve() - } - } - - const exporter = new DummySpanExporter() - - beforeAll(async () => { - server = new HTTPServer(() => Promise.resolve(new Response('OK'))) - serverAddress = await server.start() - }) - - beforeEach(() => { - createTracerProvider({ - serviceName: 'test-service', - serviceVersion: '1.0.0', - deploymentEnvironment: 'test', - siteUrl: 'https://example.com', - siteId: '12345', - siteName: 'example', - instrumentations: [new FetchInstrumentation()], - spanProcessors: [new SimpleSpanProcessor(exporter)], - }) - }) - - afterAll(async () => { - await server.stop() - }) - - it('GET', async () => { - const headers = new Headers({ a: 'a' }) - headers.append('b', 'b') - headers.set('c', 'c') - - await expect(fetch(serverAddress, { headers }).then((r) => r.text())).resolves.toEqual('OK') - - const resultSpan = exporter.exported[0][0] - - expect(resultSpan.name).toEqual('GET') - - expect(resultSpan.attributes).toEqual( - expect.objectContaining({ - 'http.request.method': 'GET', - 'http.response.header.connection': 'keep-alive', - 'http.response.header.content-type': 'text/plain;charset=UTF-8', - 'http.response.header.keep-alive': 'timeout=5', - 'http.response.header.transfer-encoding': 'chunked', - 'http.response.status_code': 200, - 'url.scheme': 'http', - }), - ) - - // Skip request headers when values are a single string instead of a string array in v18 and v20.6.1 - const shouldCheckRequestHeaders = !process.version.startsWith('v18') && process.version !== 'v20.6.1' - const requestHeaderExpectation = shouldCheckRequestHeaders - ? { - 'http.request.header.a': 'a', - 'http.request.header.b': 'b', - 'http.request.header.c': 'c', - - 'http.request.header.accept': '*/*', - 'http.request.header.accept-encoding': 'gzip, deflate', - 'http.request.header.accept-language': '*', - 'http.request.header.sec-fetch-mode': 'cors', - 'http.request.header.user-agent': 'node', - } - : {} - - expect(resultSpan.attributes).toEqual(expect.objectContaining(requestHeaderExpectation)) - }) -}) diff --git a/packages/otel/src/instrumentations/fetch.ts b/packages/otel/src/instrumentations/fetch.ts deleted file mode 100644 index f94366c..0000000 --- a/packages/otel/src/instrumentations/fetch.ts +++ /dev/null @@ -1,255 +0,0 @@ -import * as diagnosticsChannel from 'diagnostics_channel' - -import * as api from '@opentelemetry/api' -import { SugaredTracer } from '@opentelemetry/api/experimental' -import { _globalThis } from '@opentelemetry/core' -import { InstrumentationConfig, type Instrumentation } from '@opentelemetry/instrumentation' - -export interface FetchInstrumentationConfig extends InstrumentationConfig { - getRequestAttributes?(request: FetchRequest): api.Attributes - getResponseAttributes?(response: FetchResponse): api.Attributes - skipURLs?: (string | RegExp)[] - skipHeaders?: (string | RegExp)[] | true - redactHeaders?: (string | RegExp)[] | true -} - -export class FetchInstrumentation implements Instrumentation { - instrumentationName = '@netlify/otel/instrumentation-fetch' - instrumentationVersion = '1.0.0' - private config: FetchInstrumentationConfig - private provider?: api.TracerProvider - - declare private _channelSubs: ListenerRecord[] - private _recordFromReq = new WeakMap() - - constructor(config: FetchInstrumentationConfig = {}) { - this.config = config - this._channelSubs = [] - } - - getConfig(): FetchInstrumentationConfig { - return this.config - } - - setConfig(): void {} - - setMeterProvider(): void {} - setTracerProvider(provider: api.TracerProvider): void { - this.provider = provider - } - getTracerProvider(): api.TracerProvider | undefined { - return this.provider - } - - private annotateFromRequest(span: api.Span, request: FetchRequest): void { - const extras = this.config.getRequestAttributes?.(request) ?? {} - const url = new URL(request.path, request.origin) - - // these are based on @opentelemetry/semantic-convention 1.36 - span.setAttributes({ - ...extras, - 'http.request.method': request.method, - 'url.full': url.href, - 'url.host': url.host, - 'url.scheme': url.protocol.slice(0, -1), - 'server.address': url.hostname, - 'server.port': url.port, - ...this.prepareHeaders('request', request.headers), - }) - } - - private annotateFromResponse(span: api.Span, response: FetchResponse): void { - const extras = this.config.getResponseAttributes?.(response) ?? {} - - // these are based on @opentelemetry/semantic-convention 1.36 - span.setAttributes({ - ...extras, - 'http.response.status_code': response.statusCode, - ...this.prepareHeaders('response', response.headers), - }) - - span.setStatus({ - code: response.statusCode >= 400 ? api.SpanStatusCode.ERROR : api.SpanStatusCode.UNSET, - }) - } - - private prepareHeaders(type: 'request' | 'response', headers: unknown): api.Attributes { - // Low enough versions of Undici return a single string for response headers instead of an array of strings - if (!Array.isArray(headers)) return {} - - if (this.config.skipHeaders === true) return {} - const everything = ['*', '/.*/'] - const skips = this.config.skipHeaders ?? [] - const redacts = this.config.redactHeaders ?? [] - const everythingSkipped = skips.some((skip) => everything.includes(skip.toString())) - const attributes: api.Attributes = {} - if (everythingSkipped) return attributes - for (let idx = 0; idx + 1 < headers.length; idx = idx + 2) { - const key: unknown = headers[idx] - const value: unknown = headers[idx + 1] - - // Type safety - ensure we are handling only known request/response header shapes - if (typeof key !== 'string' && !Buffer.isBuffer(key)) continue - if (typeof value !== 'string' && !Buffer.isBuffer(value)) continue - - const headerKey = key.toString().toLowerCase() - if (skips.some((skip) => (typeof skip == 'string' ? skip == headerKey : skip.test(headerKey)))) { - continue - } - const attributeKey = `http.${type}.header.${headerKey}` - if ( - redacts === true || - redacts.some((redact) => (typeof redact == 'string' ? redact == headerKey : redact.test(headerKey))) - ) { - attributes[attributeKey] = 'REDACTED' - } else { - attributes[attributeKey] = value.toString() - } - } - return attributes - } - - private getRequestMethod(original: string): string { - const acceptedMethods = ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'] - - if (acceptedMethods.includes(original.toUpperCase())) { - return original.toUpperCase() - } - - return '_OTHER' - } - - private getTracer(): SugaredTracer | undefined { - if (!this.provider) { - return undefined - } - - const tracer = this.provider.getTracer(this.instrumentationName, this.instrumentationVersion) - if (tracer instanceof SugaredTracer) { - return tracer - } - - return new SugaredTracer(tracer) - } - - enable(): void { - // Avoid to duplicate subscriptions - if (this._channelSubs.length > 0) return - - // https://undici.nodejs.org/#/docs/api/DiagnosticsChannel?id=diagnostics-channel-support - this.subscribe('undici:request:create', this.onRequestCreate.bind(this)) - this.subscribe('undici:request:headers', this.onRequestHeaders.bind(this)) - this.subscribe('undici:request:trailers', this.onRequestEnd.bind(this)) - this.subscribe('undici:request:error', this.onRequestError.bind(this)) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private subscribe(channelName: string, onMessage: (message: any, name: string | symbol) => void) { - diagnosticsChannel.subscribe(channelName, onMessage) - - const unsubscribe = () => diagnosticsChannel.unsubscribe(channelName, onMessage) - this._channelSubs.push({ name: channelName, unsubscribe }) - } - - disable() { - this._channelSubs.forEach((sub) => { - sub.unsubscribe() - }) - this._channelSubs.length = 0 - } - - private onRequestCreate({ request }: { request: FetchRequest }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const tracer = this.getTracer() - const url = new URL(request.path, request.origin) - - if ( - !tracer || - request.method === 'CONNECT' || - this.config.skipURLs?.some((skip) => - typeof skip == 'string' ? url.href.startsWith(skip) : skip.test(url.href), - ) - ) { - return - } - - const span = tracer.startSpan( - this.getRequestMethod(request.method), - { - kind: api.SpanKind.CLIENT, - }, - api.context.active(), - ) - - this.annotateFromRequest(span, request) - - this._recordFromReq.set(request, span) - } catch {} - } - - private onRequestHeaders({ request, response }: { request: FetchRequest; response: FetchResponse }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const span = this._recordFromReq.get(request) - if (!span) return - - this.annotateFromResponse(span, response) - } catch {} - } - - private onRequestError({ request, error }: { request: FetchRequest; error: Error }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const span = this._recordFromReq.get(request) - if (!span) return - - span.recordException(error) - span.setStatus({ - code: api.SpanStatusCode.ERROR, - message: error.message, - }) - - span.end() - this._recordFromReq.delete(request) - } catch {} - } - - private onRequestEnd({ request }: { request: FetchRequest; response: FetchResponse }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const span = this._recordFromReq.get(request) - if (!span) return - - span.end() - this._recordFromReq.delete(request) - } catch {} - } -} - -interface ListenerRecord { - name: string - unsubscribe: () => void -} - -// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/packages/instrumentation-undici/src/types.ts -interface FetchRequest { - origin: string - method: string - path: string - headers: unknown - addHeader: (name: string, value: string) => void - throwOnError: boolean - completed: boolean - aborted: boolean - idempotent: boolean - contentLength: number | null - contentType: string | null - body: unknown -} - -interface FetchResponse { - headers: unknown - statusCode: number - statusText: string -} diff --git a/packages/otel/src/instrumentations/http.test.ts b/packages/otel/src/instrumentations/http.test.ts deleted file mode 100644 index e71d481..0000000 --- a/packages/otel/src/instrumentations/http.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import * as http from 'http' -import { afterAll, beforeAll, beforeEach, describe, expect, it, test } from 'vitest' -import { HttpInstrumentation } from './http.ts' -import { HTTPServer } from '@netlify/dev-utils' -import { SpanExporter, ReadableSpan, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node' -import { createTracerProvider } from '../bootstrap/main.ts' - -describe('header exclusion', () => { - test('skips configured headers', () => { - const instrumentation = new HttpInstrumentation({ - skipHeaders: ['authorization'], - }) - - // eslint-disable-next-line @typescript-eslint/dot-notation - const attributes = instrumentation['prepareHeaders']('request', { - a: 'a', - b: 'b', - authorization: 'secret', - }) - expect(attributes).toEqual({ - 'http.request.header.a': 'a', - 'http.request.header.b': 'b', - }) - }) - - test('it skips all headers if so configured', () => { - const everything = new HttpInstrumentation({ - skipHeaders: true, - }) - // eslint-disable-next-line @typescript-eslint/dot-notation - const empty = everything['prepareHeaders']('request', { - a: 'a', - b: 'b', - authorization: 'secret', - }) - expect(empty).toEqual({}) - }) - - test('redacts configured headers', () => { - const instrumentation = new HttpInstrumentation({ - redactHeaders: ['authorization'], - }) - - // eslint-disable-next-line @typescript-eslint/dot-notation - const attributes = instrumentation['prepareHeaders']('request', { - a: 'a', - b: 'b', - authorization: 'secret', - }) - expect(attributes['http.request.header.authorization']).not.toBe('secret') - expect(attributes['http.request.header.authorization']).toBeTypeOf('string') - expect(attributes['http.request.header.a']).toBe('a') - expect(attributes['http.request.header.b']).toBe('b') - }) - - test('redacts everything if so requested', () => { - const instrumentation = new HttpInstrumentation({ - redactHeaders: true, - }) - - // eslint-disable-next-line @typescript-eslint/dot-notation - const attributes = instrumentation['prepareHeaders']('request', { - a: 'a', - b: 'b', - authorization: 'secret', - }) - expect(attributes['http.request.header.authorization']).not.toBe('secret') - expect(attributes['http.request.header.a']).not.toBe('a') - expect(attributes['http.request.header.b']).not.toBe('b') - expect(attributes['http.request.header.authorization']).toBeTypeOf('string') - expect(attributes['http.request.header.a']).toBeTypeOf('string') - expect(attributes['http.request.header.b']).toBeTypeOf('string') - }) -}) - -describe('http instrumentation (integration)', () => { - let serverAddress: string - let server: HTTPServer - - class DummySpanExporter implements SpanExporter { - readonly exported: ReadableSpan[][] = [] - - export(spans: ReadableSpan[]) { - this.exported.push(spans) - } - - shutdown() { - return Promise.resolve() - } - - forceFlush(): Promise { - return Promise.resolve() - } - } - - const exporter = new DummySpanExporter() - - beforeAll(async () => { - server = new HTTPServer(() => Promise.resolve(new Response('OK'))) - serverAddress = await server.start() - }) - - beforeEach(() => { - createTracerProvider({ - serviceName: 'test-service', - serviceVersion: '1.0.0', - deploymentEnvironment: 'test', - siteUrl: 'https://example.com', - siteId: '12345', - siteName: 'example', - instrumentations: [new HttpInstrumentation()], - spanProcessors: [new SimpleSpanProcessor(exporter)], - }) - }) - - afterAll(async () => { - await server.stop() - }) - - it.skipIf(process.version.startsWith('v18'))('GET', async () => { - const request = (options: object): Promise<{ statusCode?: number; body?: string }> => - new Promise((resolve, reject) => { - // Inspired from https://gist.github.com/ktheory/df3440b01d4b9d3197180d5254d7fb65 - const req = http.request(options, (res) => { - const chunks: string[] = [] - - res.on('data', (chunk: string) => chunks.push(chunk)) - res.on('error', reject) - res.on('end', () => { - const { statusCode } = res - const body = chunks.join('') - resolve({ statusCode, body }) - }) - }) - - req.on('error', reject) - req.end() - }) - - const options = { - hostname: 'localhost', - port: serverAddress.split(':')[2], - headers: { - a: 'a', - b: 'b', - c: 'c', - }, - } - - await expect(request(options).then((r) => r.body)).resolves.toEqual('OK') - - const resultSpan = exporter.exported[0][0] - - expect(resultSpan.name).toEqual('GET') - - expect(resultSpan.attributes).toEqual( - expect.objectContaining({ - 'http.request.header.a': 'a', - 'http.request.header.b': 'b', - 'http.request.header.c': 'c', - 'http.request.method': 'GET', - 'http.response.header.connection': 'keep-alive', - 'http.response.header.content-type': 'text/plain;charset=UTF-8', - 'http.response.header.keep-alive': 'timeout=5', - 'http.response.header.transfer-encoding': 'chunked', - 'http.response.status_code': 200, - 'server.address': 'localhost', - 'url.full': 'http://localhost/', - 'url.host': 'localhost', - 'url.scheme': 'http', - }), - ) - }) -}) diff --git a/packages/otel/src/instrumentations/http.ts b/packages/otel/src/instrumentations/http.ts deleted file mode 100644 index f949a37..0000000 --- a/packages/otel/src/instrumentations/http.ts +++ /dev/null @@ -1,222 +0,0 @@ -import * as diagnosticsChannel from 'diagnostics_channel' -import type { ClientRequest, IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders } from 'http' - -import * as api from '@opentelemetry/api' -import { SugaredTracer } from '@opentelemetry/api/experimental' -import { _globalThis } from '@opentelemetry/core' -import { Instrumentation, InstrumentationConfig } from '@opentelemetry/instrumentation' - -export interface HttpInstrumentationConfig extends InstrumentationConfig { - getRequestAttributes?(request: ClientRequest): api.Attributes - getResponseAttributes?(response: IncomingMessage): api.Attributes - skipURLs?: (string | RegExp)[] - skipHeaders?: (string | RegExp)[] | true - redactHeaders?: (string | RegExp)[] | true -} - -export class HttpInstrumentation implements Instrumentation { - instrumentationName = '@netlify/otel/instrumentation-http' - instrumentationVersion = '1.0.0' - private config: HttpInstrumentationConfig - private provider?: api.TracerProvider - - declare private _channelSubs: ListenerRecord[] - private _recordFromReq = new WeakMap() - - constructor(config = {}) { - this.config = config - this._channelSubs = [] - } - - getConfig() { - return this.config - } - - setConfig() {} - - setMeterProvider() {} - setTracerProvider(provider: api.TracerProvider): void { - this.provider = provider - } - getTracerProvider(): api.TracerProvider | undefined { - return this.provider - } - - private annotateFromRequest(span: api.Span, request: ClientRequest): void { - const extras = this.config.getRequestAttributes?.(request) ?? {} - const url = new URL(request.path, `${request.protocol}//${request.host}`) - - // these are based on @opentelemetry/semantic-convention 1.36 - span.setAttributes({ - ...extras, - 'http.request.method': request.method, - 'url.full': url.href, - 'url.host': url.host, - 'url.scheme': url.protocol.slice(0, -1), - 'server.address': url.hostname, - ...this.prepareHeaders('request', request.getHeaders()), - }) - } - - private annotateFromResponse(span: api.Span, response: IncomingMessage): void { - const extras = this.config.getResponseAttributes?.(response) ?? {} - - // these are based on @opentelemetry/semantic-convention 1.36 - span.setAttributes({ - ...extras, - 'http.response.status_code': response.statusCode, - ...this.prepareHeaders('response', response.headers), - }) - - span.setStatus({ - code: response.statusCode && response.statusCode >= 400 ? api.SpanStatusCode.ERROR : api.SpanStatusCode.UNSET, - }) - } - - private prepareHeaders( - type: 'request' | 'response', - headers: IncomingHttpHeaders | OutgoingHttpHeaders, - ): api.Attributes { - if (this.config.skipHeaders === true) { - return {} - } - const everything = ['*', '/.*/'] - const skips = this.config.skipHeaders ?? [] - const redacts = this.config.redactHeaders ?? [] - const everythingSkipped = skips.some((skip) => everything.includes(skip.toString())) - const attributes: api.Attributes = {} - if (everythingSkipped) return attributes - const entries = Object.entries(headers) - for (const [key, value] of entries) { - if (skips.some((skip) => (typeof skip == 'string' ? skip == key : skip.test(key)))) { - continue - } - const attributeKey = `http.${type}.header.${key}` - if ( - redacts === true || - redacts.some((redact) => (typeof redact == 'string' ? redact == key : redact.test(key))) - ) { - attributes[attributeKey] = 'REDACTED' - } else { - attributes[attributeKey] = value - } - } - return attributes - } - - private getRequestMethod(original: string): string { - const acceptedMethods = ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'] - - if (acceptedMethods.includes(original.toUpperCase())) { - return original.toUpperCase() - } - - return '_OTHER' - } - - getTracer() { - if (!this.provider) { - return undefined - } - - const tracer = this.provider.getTracer(this.instrumentationName, this.instrumentationVersion) - - if (tracer instanceof SugaredTracer) { - return tracer - } - - return new SugaredTracer(tracer) - } - - enable() { - // Avoid to duplicate subscriptions - if (this._channelSubs.length > 0) return - - // https://nodejs.org/docs/latest-v20.x/api/diagnostics_channel.html#http - this.subscribe('http.client.request.start', this.onRequest.bind(this)) - this.subscribe('http.client.response.finish', this.onResponse.bind(this)) - this.subscribe('http.client.request.error', this.onError.bind(this)) - } - - disable() { - this._channelSubs.forEach((sub) => { - sub.unsubscribe() - }) - this._channelSubs.length = 0 - } - - private onRequest({ request }: { request: ClientRequest }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const tracer = this.getTracer() - const url = new URL(request.path, `${request.protocol}//${request.host}`) - - if ( - !tracer || - this.config.skipURLs?.some((skip) => - typeof skip == 'string' ? url.href.startsWith(skip) : skip.test(url.href), - ) - ) { - return - } - - const span = tracer.startSpan( - this.getRequestMethod(request.method), - { - kind: api.SpanKind.CLIENT, - }, - api.context.active(), - ) - - this.annotateFromRequest(span, request) - - this._recordFromReq.set(request, span) - } catch {} - } - - private onResponse({ request, response }: { request: ClientRequest; response: IncomingMessage }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const span = this._recordFromReq.get(request) - - if (!span) return - - this.annotateFromResponse(span, response) - - span.end() - - this._recordFromReq.delete(request) - } catch {} - } - - private onError({ request, error }: { request: ClientRequest; error: Error }): void { - // If our code raises an exception, we don't want this to affect user code - try { - const span = this._recordFromReq.get(request) - - if (!span) return - - span.recordException(error) - span.setStatus({ - code: api.SpanStatusCode.ERROR, - message: error.name, - }) - - span.end() - - this._recordFromReq.delete(request) - } catch {} - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private subscribe(channelName: string, onMessage: (message: any, name: string | symbol) => void) { - diagnosticsChannel.subscribe(channelName, onMessage) - const unsubscribe = () => diagnosticsChannel.unsubscribe(channelName, onMessage) - this._channelSubs.push({ name: channelName, unsubscribe }) - } -} - -interface ListenerRecord { - name: string - unsubscribe: () => void -} diff --git a/packages/otel/src/main.test.ts b/packages/otel/src/main.test.ts deleted file mode 100644 index 31b6af3..0000000 --- a/packages/otel/src/main.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { describe, test, expect } from 'vitest' -import { getTracer, shutdownTracers } from './main.ts' -import { SugaredTracer } from '@opentelemetry/api/experimental' -import { createTracerProvider } from './bootstrap/main.ts' - -describe('`getTracer` export', () => { - test('Returns undefined if tracing has not been previously activated', () => { - expect(getTracer()).toBeUndefined() - }) - test('Returns tracer if tracing has been previously activated', () => { - createTracerProvider({ - serviceName: 'test-service', - serviceVersion: '1.0.0', - deploymentEnvironment: 'test', - siteUrl: 'https://example.com', - siteId: '12345', - siteName: 'example', - }) - expect(getTracer()).toBeInstanceOf(SugaredTracer) - }) -}) - -describe('`shutdownTracers` export', () => { - test('Returns undefined', async () => { - await expect(shutdownTracers()).resolves.toBeUndefined() - }) - test('Returns undefined if tracing has been previously activated', async () => { - createTracerProvider({ - serviceName: 'test-service', - serviceVersion: '1.0.0', - deploymentEnvironment: 'test', - siteUrl: 'https://example.com', - siteId: '12345', - siteName: 'example', - }) - await expect(shutdownTracers()).resolves.toBeUndefined() - await expect(shutdownTracers()).resolves.toBeUndefined() - }) -}) diff --git a/packages/otel/src/main.ts b/packages/otel/src/main.ts deleted file mode 100644 index cb20d3a..0000000 --- a/packages/otel/src/main.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { Context, Span } from '@opentelemetry/api' -import type { SugaredSpanOptions, SugaredTracer } from '@opentelemetry/api/experimental' - -import { GET_TRACER, SHUTDOWN_TRACERS } from './constants.js' - -type GlobalThisExtended = typeof globalThis & { - [GET_TRACER]?: (name?: string, version?: string) => SugaredTracer | undefined - [SHUTDOWN_TRACERS]?: () => void -} - -export const getTracer = (name?: string, version?: string): SugaredTracer | undefined => { - return (globalThis as GlobalThisExtended)[GET_TRACER]?.(name, version) -} - -export const shutdownTracers = async (): Promise => { - return (globalThis as GlobalThisExtended)[SHUTDOWN_TRACERS]?.() -} - -export function withActiveSpan ReturnType>( - tracer: SugaredTracer | undefined, - name: string, - fn: F, -): ReturnType -export function withActiveSpan ReturnType>( - tracer: SugaredTracer | undefined, - name: string, - options: SugaredSpanOptions, - fn: F, -): ReturnType -export function withActiveSpan ReturnType>( - tracer: SugaredTracer | undefined, - name: string, - options: SugaredSpanOptions, - context: Context, - fn: F, -): ReturnType -export function withActiveSpan ReturnType>( - tracer: SugaredTracer | undefined, - name: string, - optionsOrFn: SugaredSpanOptions | F, - contextOrFn?: Context | F, - fn?: F, -): ReturnType { - const func = typeof contextOrFn === 'function' ? contextOrFn : typeof optionsOrFn === 'function' ? optionsOrFn : fn - if (!func) { - throw new Error('function to execute with active span is missing') - } - if (!tracer) { - return func() - } - return tracer.withActiveSpan(name, optionsOrFn as SugaredSpanOptions, contextOrFn as Context, func) -} diff --git a/packages/otel/src/opentelemetry.test.ts b/packages/otel/src/opentelemetry.test.ts deleted file mode 100644 index b29dcd8..0000000 --- a/packages/otel/src/opentelemetry.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { describe, test, expect } from 'vitest' -import { SimpleSpanProcessor, BatchSpanProcessor } from './opentelemetry.js' - -describe('OpenTelemetry exports', () => { - test('exports SimpleSpanProcessor', () => { - expect(SimpleSpanProcessor).toBeDefined() - expect(typeof SimpleSpanProcessor).toBe('function') - }) - - test('exports BatchSpanProcessor', () => { - expect(BatchSpanProcessor).toBeDefined() - expect(typeof BatchSpanProcessor).toBe('function') - }) -}) diff --git a/packages/otel/src/opentelemetry.ts b/packages/otel/src/opentelemetry.ts deleted file mode 100644 index 1181192..0000000 --- a/packages/otel/src/opentelemetry.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Re-exports of commonly used OpenTelemetry primitives - * This ensures version compatibility when building custom exporters and processors - */ -export { context, propagation, trace, SpanKind, SpanStatusCode } from '@opentelemetry/api' -export { W3CTraceContextPropagator } from '@opentelemetry/core' -export { BatchSpanProcessor, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node' - -export type { Attributes, Context, Span, SpanContext, SpanStatus, TimeInput } from '@opentelemetry/api' -export type { ExportResult, ExportResultCode } from '@opentelemetry/core' -export type { SpanExporter, ReadableSpan } from '@opentelemetry/sdk-trace-node' diff --git a/packages/otel/tsconfig.json b/packages/otel/tsconfig.json deleted file mode 100644 index 7ca5f57..0000000 --- a/packages/otel/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "allowImportingTsExtensions": true, - "emitDeclarationOnly": true, - "target": "ES2020", - "module": "NodeNext", - "allowJs": true, - "declaration": true, - "declarationMap": false, - "sourceMap": false, - "outDir": "./dist", - "removeComments": false, - "strict": true, - "moduleResolution": "nodenext", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true - }, - "include": ["src"] -} diff --git a/packages/otel/tsup.config.ts b/packages/otel/tsup.config.ts deleted file mode 100644 index f1bf5ab..0000000 --- a/packages/otel/tsup.config.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['cjs', 'esm'], - entry: [ - 'src/bootstrap/main.ts', - 'src/main.ts', - 'src/exporters/netlify.ts', - 'src/instrumentations/fetch.ts', - 'src/instrumentations/http.ts', - 'src/opentelemetry.ts', - ], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/otel/vitest.config.ts b/packages/otel/vitest.config.ts deleted file mode 100644 index eff32b2..0000000 --- a/packages/otel/vitest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - esbuild: { - target: 'esnext', - }, - test: { - include: ['src/**/*.test.ts'], - testTimeout: 30_000, - }, -}) diff --git a/packages/redirects/.gitignore b/packages/redirects/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/redirects/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/redirects/CHANGELOG.md b/packages/redirects/CHANGELOG.md deleted file mode 100644 index d502c3e..0000000 --- a/packages/redirects/CHANGELOG.md +++ /dev/null @@ -1,336 +0,0 @@ -# Changelog - -## [3.1.13](https://github.com/netlify/primitives/compare/redirects-v3.1.12...redirects-v3.1.13) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.5 to 4.4.6 - -## [3.1.12](https://github.com/netlify/primitives/compare/redirects-v3.1.11...redirects-v3.1.12) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.4 to 4.4.5 - -## [3.1.11](https://github.com/netlify/primitives/compare/redirects-v3.1.10...redirects-v3.1.11) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.3 to 4.4.4 - -## [3.1.10](https://github.com/netlify/primitives/compare/redirects-v3.1.9...redirects-v3.1.10) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.2 to 4.4.3 - -## [3.1.9](https://github.com/netlify/primitives/compare/redirects-v3.1.8...redirects-v3.1.9) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.1 to 4.4.2 - -## [3.1.8](https://github.com/netlify/primitives/compare/redirects-v3.1.7...redirects-v3.1.8) (2026-03-13) - - -### Bug Fixes - -* **deps:** update netlify packages ([#626](https://github.com/netlify/primitives/issues/626)) ([a87ba84](https://github.com/netlify/primitives/commit/a87ba84fa23c3a4ff506cd9c3d5f3b5cd78d9f3c)) - -## [3.1.7](https://github.com/netlify/primitives/compare/redirects-v3.1.6...redirects-v3.1.7) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.4.0 to 4.4.1 - -## [3.1.6](https://github.com/netlify/primitives/compare/redirects-v3.1.5...redirects-v3.1.6) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.3 to 4.4.0 - -## [3.1.5](https://github.com/netlify/primitives/compare/redirects-v3.1.4...redirects-v3.1.5) (2026-02-16) - - -### Bug Fixes - -* **deps:** update dependency jsonwebtoken to v9.0.3 ([#575](https://github.com/netlify/primitives/issues/575)) ([144a930](https://github.com/netlify/primitives/commit/144a9305da67c1683267d3a1f68597ca8a6f0860)) - -## [3.1.4](https://github.com/netlify/primitives/compare/redirects-v3.1.3...redirects-v3.1.4) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.2 to 4.3.3 - -## [3.1.3](https://github.com/netlify/primitives/compare/redirects-v3.1.2...redirects-v3.1.3) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.1 to 4.3.2 - -## [3.1.2](https://github.com/netlify/primitives/compare/redirects-v3.1.1...redirects-v3.1.2) (2025-11-06) - - -### Bug Fixes - -* ignore SPA redirect in dev mode to allow Vite to take over ([#514](https://github.com/netlify/primitives/issues/514)) ([510642b](https://github.com/netlify/primitives/commit/510642b575b10e1595f19bbeab475ffcaa35b1f2)) - -## [3.1.1](https://github.com/netlify/primitives/compare/redirects-v3.1.0...redirects-v3.1.1) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.3.0 to 4.3.1 - -## [3.1.0](https://github.com/netlify/primitives/compare/redirects-v3.0.13...redirects-v3.1.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.2.0 to 4.3.0 - -## [3.0.13](https://github.com/netlify/primitives/compare/redirects-v3.0.12...redirects-v3.0.13) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.3 to 4.2.0 - -## [3.0.12](https://github.com/netlify/primitives/compare/redirects-v3.0.11...redirects-v3.0.12) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.2 to 4.1.3 - -## [3.0.11](https://github.com/netlify/primitives/compare/redirects-v3.0.10...redirects-v3.0.11) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/dev-utils bumped from 4.1.1 to 4.1.2 - -## [3.0.10](https://github.com/netlify/primitives/compare/redirects-v3.0.9...redirects-v3.0.10) (2025-08-14) - - -### Bug Fixes - -* **deps:** update netlify packages ([#411](https://github.com/netlify/primitives/issues/411)) ([bad2dce](https://github.com/netlify/primitives/commit/bad2dceae8b5e5f56d947ce2332372d148819ccc)) - -## [3.0.9](https://github.com/netlify/primitives/compare/redirects-v3.0.8...redirects-v3.0.9) (2025-08-01) - - -### Bug Fixes - -* add `@netlify/dev-utils` dependency ([#403](https://github.com/netlify/primitives/issues/403)) ([3ecf352](https://github.com/netlify/primitives/commit/3ecf352a38dd7d337067b382286c49ea041b0464)) - -## [3.0.8](https://github.com/netlify/primitives/compare/redirects-v3.0.7...redirects-v3.0.8) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.1.0 to 4.1.1 - -## [3.0.7](https://github.com/netlify/primitives/compare/redirects-v3.0.6...redirects-v3.0.7) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 4.0.0 to 4.1.0 - -## [3.0.6](https://github.com/netlify/primitives/compare/redirects-v3.0.5...redirects-v3.0.6) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.3.0 to 4.0.0 - -## [3.0.5](https://github.com/netlify/primitives/compare/redirects-v3.0.4...redirects-v3.0.5) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.2.2 to 3.3.0 - -## [3.0.4](https://github.com/netlify/primitives/compare/redirects-v3.0.3...redirects-v3.0.4) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.2.1 to 3.2.2 - -## [3.0.3](https://github.com/netlify/primitives/compare/redirects-v3.0.2...redirects-v3.0.3) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.2.0 to 3.2.1 - -## [3.0.2](https://github.com/netlify/primitives/compare/redirects-v3.0.1...redirects-v3.0.2) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.1.1 to 3.2.0 - -## [3.0.1](https://github.com/netlify/primitives/compare/redirects-v3.0.0...redirects-v3.0.1) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.1.0 to 3.1.1 - -## [3.0.0](https://github.com/netlify/primitives/compare/redirects-v2.0.0...redirects-v3.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Bug Fixes - -* **deps:** update netlify packages ([#236](https://github.com/netlify/primitives/issues/236)) ([630e675](https://github.com/netlify/primitives/commit/630e675822ece3d4bca58673b0a899f5a6c06bd9)) -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 3.0.0 to 3.1.0 - -## [2.0.0](https://github.com/netlify/primitives/compare/redirects-v1.1.4...redirects-v2.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Bug Fixes - -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.2.0 to 3.0.0 - -## [1.1.4](https://github.com/netlify/primitives/compare/redirects-v1.1.3...redirects-v1.1.4) (2025-05-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.1.1 to 2.2.0 - -## [1.1.3](https://github.com/netlify/primitives/compare/redirects-v1.1.2...redirects-v1.1.3) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.1.0 to 2.1.1 - -## [1.1.2](https://github.com/netlify/primitives/compare/redirects-v1.1.1...redirects-v1.1.2) (2025-05-06) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.0.0 to 2.1.0 - -## [1.1.1](https://github.com/netlify/primitives/compare/redirects-v1.1.0...redirects-v1.1.1) (2025-05-02) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 1.1.0 to 2.0.0 - -## [1.1.0](https://github.com/netlify/primitives/compare/redirects-v1.0.0...redirects-v1.1.0) (2025-04-16) - - -### Features - -* move primitives into monorepo ([#101](https://github.com/netlify/primitives/issues/101)) ([93b72b1](https://github.com/netlify/primitives/commit/93b72b1364022e45cbd87814dc6aa235f1e1c83e)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 1.0.0 to 1.1.0 diff --git a/packages/redirects/package.json b/packages/redirects/package.json deleted file mode 100644 index 6f79763..0000000 --- a/packages/redirects/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@netlify/redirects", - "version": "3.1.13", - "description": "TypeScript implementation of Netlify's rewrites and redirects engine", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.js", - "exports": "./dist/main.js", - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/redirects" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "directories": { - "test": "test" - }, - "devDependencies": { - "@types/jsonwebtoken": "9.0.10", - "tsup": "^8.5.0", - "vitest": "^3.1.4" - }, - "dependencies": { - "@netlify/dev-utils": "4.4.6", - "@netlify/redirect-parser": "^15.0.4", - "cookie": "^1.0.2", - "jsonwebtoken": "9.0.3", - "netlify-redirector": "^0.5.0" - } -} diff --git a/packages/redirects/src/lib/parser.ts b/packages/redirects/src/lib/parser.ts deleted file mode 100644 index 2da070f..0000000 --- a/packages/redirects/src/lib/parser.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { parseAllRedirects } from '@netlify/redirect-parser' - -import type { Redirect } from './redirect.js' - -// TODO: Type in `@netlify/redirect-parser`. -interface ParsedRedirects { - errors: { message: string }[] - redirects: Redirect[] -} - -// Parse, normalize and validate all redirects from `_redirects` files -// and `netlify.toml` -export const parseRedirects = async function ({ - configRedirects = [], - configPath, - redirectsFiles, -}: { - configRedirects?: Redirect[] - configPath?: string - redirectsFiles: string[] -}) { - const parsed = (await parseAllRedirects({ - redirectsFiles, - netlifyConfigPath: configPath, - minimal: false, - - // @ts-expect-error TODO: Fix this type in `@netlify/redirect-parser`. - configRedirects, - })) as ParsedRedirects - - handleRedirectParsingErrors(parsed.errors) - - return parsed.redirects.map(normalizeRedirect) -} - -const handleRedirectParsingErrors = (errors: ParsedRedirects['errors']) => { - if (errors.length === 0) { - return - } - - const errorMessage = errors.map(({ message }: { message: string }) => message).join('\n\n') - - console.log(`Redirects syntax errors:\n${errorMessage}`) -} - -// `netlify-redirector` does not handle the same shape as the backend: -// - `from` is called `origin` -// - `query` is called `params` -// - `conditions.role|country|language` are capitalized -const normalizeRedirect = function (input: Redirect) { - const { conditions, from, query, signed, ...redirect } = input - - return { - ...redirect, - origin: from, - params: query, - conditions, - ...(signed && { - sign: { - jwt_secret: signed, - }, - }), - } -} diff --git a/packages/redirects/src/lib/redirect.ts b/packages/redirects/src/lib/redirect.ts deleted file mode 100644 index dfc98d2..0000000 --- a/packages/redirects/src/lib/redirect.ts +++ /dev/null @@ -1,12 +0,0 @@ -type HttpStatusCode = number - -export interface Redirect { - from: string - to?: string - status?: HttpStatusCode - force?: boolean - signed?: string - query?: Partial> - headers?: Partial> - conditions?: Partial> -} diff --git a/packages/redirects/src/lib/rewriter.ts b/packages/redirects/src/lib/rewriter.ts deleted file mode 100644 index 42f0d1c..0000000 --- a/packages/redirects/src/lib/rewriter.ts +++ /dev/null @@ -1,107 +0,0 @@ -import path from 'node:path' - -import { toMultiValueHeaders } from '@netlify/dev-utils' -import cookie from 'cookie' -import redirector, { type Match, type RedirectMatcher } from 'netlify-redirector' - -import { parseRedirects } from './parser.js' -import { Redirect } from './redirect.js' - -export type Rewriter = (req: Request) => Promise - -const REDIRECTS_FILE_NAME = '_redirects' - -const getLanguage = (acceptLanguage: string | null) => { - if (acceptLanguage) { - return acceptLanguage.split(',')[0].slice(0, 2) - } - - return 'en' -} - -export const createRewriter = async function ({ - configPath, - configRedirects, - geoCountry, - ignoreSPARedirect = false, - jwtRoleClaim, - jwtSecret, - projectDir, - publicDir, -}: { - configPath?: string | undefined - configRedirects: Redirect[] - geoCountry?: string | undefined - ignoreSPARedirect?: boolean - jwtRoleClaim: string - jwtSecret: string - projectDir: string - publicDir?: string | undefined -}): Promise { - let matcher: RedirectMatcher | null = null - const redirectsFiles = [ - ...new Set([path.resolve(publicDir ?? '', REDIRECTS_FILE_NAME), path.resolve(projectDir, REDIRECTS_FILE_NAME)]), - ] - let redirects = await parseRedirects({ configRedirects, redirectsFiles, configPath }) - - // Hacky solution: Filter out the SPA redirect pattern when requested. - // This prevents the redirect from interfering with local dev servers like Vite, - // while still allowing it to work in production. - // See: https://github.com/netlify/primitives/issues/325 - if (ignoreSPARedirect) { - redirects = redirects.filter((redirect) => { - // Filter out redirects that match the SPA pattern: from "/*" to "/index.html" with status 200 - // See https://docs.netlify.com/manage/routing/redirects/rewrites-proxies/#history-pushstate-and-single-page-apps, - const isSPARedirect = redirect.origin === '/*' && redirect.to === '/index.html' && redirect.status === 200 - - return !isSPARedirect - }) - } - - const getMatcher = async (): Promise => { - if (matcher) return matcher - - if (redirects.length !== 0) { - return (matcher = await redirector.parseJSON(JSON.stringify(redirects), { - jwtSecret, - jwtRoleClaim, - })) - } - return { - match() { - return null - }, - } - } - - return async function rewriter(req: Request): Promise { - const matcherFunc = await getMatcher() - const reqUrl = new URL(req.url) - const cookieValues = cookie.parse(req.headers.get('cookie') || '') - const headers: Record = { - 'x-language': cookieValues.nf_lang || getLanguage(req.headers.get('accept-language')), - 'x-country': cookieValues.nf_country || geoCountry || 'us', - ...toMultiValueHeaders(req.headers), - } - - // Definition: https://github.com/netlify/libredirect/blob/e81bbeeff9f7c260a5fb74cad296ccc67a92325b/node/src/redirects.cpp#L28-L60 - const matchReq = { - scheme: reqUrl.protocol.replace(/:.*$/, ''), - host: reqUrl.hostname, - path: decodeURIComponent(reqUrl.pathname), - query: reqUrl.search.slice(1), - headers, - cookieValues, - getHeader: (name: string) => { - const val = headers[name.toLowerCase()] - if (Array.isArray(val)) { - return val[0] - } - return val || '' - }, - getCookie: (key: string) => cookieValues[key] || '', - } - - return matcherFunc.match(matchReq) - } -} diff --git a/packages/redirects/src/lib/signer.ts b/packages/redirects/src/lib/signer.ts deleted file mode 100644 index c526b7d..0000000 --- a/packages/redirects/src/lib/signer.ts +++ /dev/null @@ -1,23 +0,0 @@ -import jwt from 'jsonwebtoken' - -interface SignRedirectOptions { - deployContext: string - secret: string - siteID: string - siteURL: string -} - -// https://docs.netlify.com/routing/redirects/rewrites-proxies/#signed-proxy-redirects -export const signRedirect = ({ deployContext, secret, siteID, siteURL }: SignRedirectOptions) => { - const claims = { - deploy_context: deployContext, - netlify_id: siteID, - site_url: siteURL, - } - const options = { - expiresIn: '5 minutes' as const, - issuer: 'netlify', - } - - return jwt.sign(claims, secret, options) -} diff --git a/packages/redirects/src/main.test.ts b/packages/redirects/src/main.test.ts deleted file mode 100644 index b989b83..0000000 --- a/packages/redirects/src/main.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { join } from 'node:path' - -import { Fixture, MockFetch } from '@netlify/dev-utils' -import { describe, expect, test } from 'vitest' - -import { RedirectsHandler } from './main.js' - -describe('Matching rules', () => { - test('Same-site rewrite', async () => { - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: '/to', - status: 200, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req1 = new Request('https://site.netlify/foo') - const match1 = await redirects.match(req1) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify/from') - const match2 = await redirects.match(req2) - expect(match2).not.toBeUndefined() - expect(match2!.external).toBe(false) - expect(match2!.redirect).toBe(false) - expect(match2!.target).toStrictEqual(new URL('https://site.netlify/to')) - expect(match2!.targetRelative).toBe('/to') - - await fixture.destroy() - }) - - test('Same-site redirect', async () => { - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: '/to', - status: 301, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req1 = new Request('https://site.netlify/foo') - const match1 = await redirects.match(req1) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify/from') - const match2 = await redirects.match(req2) - expect(match2).not.toBeUndefined() - expect(match2!.external).toBe(false) - expect(match2!.redirect).toBe(true) - expect(match2!.target).toStrictEqual(new URL('https://site.netlify/to')) - expect(match2!.targetRelative).toBe('/to') - - await fixture.destroy() - }) - - test('External rewrite', async () => { - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: 'https://example.com/to', - status: 200, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req1 = new Request('https://site.netlify/foo') - const match1 = await redirects.match(req1) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify/from') - const match2 = await redirects.match(req2) - expect(match2).not.toBeUndefined() - expect(match2!.external).toBe(true) - expect(match2!.redirect).toBe(false) - expect(match2!.target).toStrictEqual(new URL('https://example.com/to')) - expect(match2!.targetRelative).toBe('https://example.com/to') - - await fixture.destroy() - }) - - test('External redirect', async () => { - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: 'https://example.com/to', - status: 302, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req1 = new Request('https://site.netlify/foo') - const match1 = await redirects.match(req1) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify/from') - const match2 = await redirects.match(req2) - expect(match2).not.toBeUndefined() - expect(match2!.external).toBe(true) - expect(match2!.redirect).toBe(true) - expect(match2!.target).toStrictEqual(new URL('https://example.com/to')) - expect(match2!.targetRelative).toBe('https://example.com/to') - - await fixture.destroy() - }) -}) - -describe('Handling rules', () => { - test('Non-forced rewrite to static file', async () => { - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: '/to', - status: 200, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req = new Request('https://site.netlify/from') - const match = await redirects.match(req) - expect(match).not.toBeUndefined() - - const res = await redirects.handle(req, match!, async (lookup: Request) => { - expect(lookup.url).toBe('https://site.netlify/from') - - return async () => new Response('Static file') - }) - expect(await res?.text()).toBe('Static file') - - await fixture.destroy() - }) - - test('External rewrite', async () => { - const mockFetch = new MockFetch().get({ - response: new Response('Hello from example.com'), - url: 'https://example.com/', - }) - - globalThis.fetch = mockFetch.fetch - - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: 'https://example.com', - status: 200, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req = new Request('https://site.netlify/from') - const match = await redirects.match(req) - expect(match).not.toBeUndefined() - - const res = await redirects.handle(req, match!, async () => undefined) - expect(res?.status).toBe(200) - expect(await res?.text()).toBe('Hello from example.com') - - await fixture.destroy() - mockFetch.restore() - - expect(mockFetch.fulfilled).toBeTruthy() - }) - - test('Internal rewrite', async () => { - const fixture = new Fixture() - const directory = await fixture.create() - const redirects = new RedirectsHandler({ - configRedirects: [ - { - from: '/from', - to: '/to', - status: 200, - }, - ], - configPath: join(directory, 'netlify.toml'), - jwtRoleClaim: '', - jwtSecret: '', - projectDir: directory, - }) - - const req = new Request('https://site.netlify/from') - const match = await redirects.match(req) - expect(match).not.toBeUndefined() - - const res = await redirects.handle(req, match!, async () => undefined) - expect(res).toBeUndefined() - - await fixture.destroy() - }) -}) diff --git a/packages/redirects/src/main.ts b/packages/redirects/src/main.ts deleted file mode 100644 index 709cf21..0000000 --- a/packages/redirects/src/main.ts +++ /dev/null @@ -1,158 +0,0 @@ -import process from 'node:process' - -import type { Handler } from '@netlify/dev-utils' - -import type { Redirect } from './lib/redirect.js' -import { type Rewriter, createRewriter } from './lib/rewriter.js' -import { signRedirect } from './lib/signer.js' - -interface RedirectsMatch { - error?: Error - external: boolean - force: boolean - headers: Record - hiddenProxy: boolean - redirect: boolean - statusCode: number - target: URL - targetRelative: string -} - -interface RedirectsHandlerOptions { - configPath?: string | undefined - configRedirects: Redirect[] - geoCountry?: string | undefined - jwtRoleClaim: string - jwtSecret: string - notFoundHandler?: Handler - projectDir: string - publicDir?: string | undefined - siteID?: string - siteURL?: string -} - -type GetStaticFile = (request: Request) => Promise<(() => Promise) | undefined> - -export class RedirectsHandler { - private notFoundHandler: Handler - private rewriter: Promise - private siteID: string - private siteURL: string - - constructor({ - configPath, - configRedirects, - geoCountry, - jwtRoleClaim, - jwtSecret, - notFoundHandler, - projectDir, - publicDir, - siteID, - siteURL, - }: RedirectsHandlerOptions) { - this.notFoundHandler = notFoundHandler ?? (() => Promise.resolve(new Response('Not found', { status: 404 }))) - this.rewriter = createRewriter({ - configPath, - configRedirects, - geoCountry, - ignoreSPARedirect: true, - jwtRoleClaim, - jwtSecret, - projectDir, - publicDir, - }) - this.siteID = siteID ?? '0' - this.siteURL = siteURL ?? 'http://localhost' - } - - async match(request: Request): Promise { - const rewriter = await this.rewriter - const rule = await rewriter(request) - - if (!rule) { - return - } - - if (rule.force404) { - return { - external: false, - force: true, - headers: {}, - hiddenProxy: false, - redirect: false, - statusCode: 404, - target: new URL(''), - targetRelative: '', - } - } - - const requestURL = new URL(request.url) - const headers = { - ...(rule.force404 ? {} : rule.proxyHeaders), - } - const hiddenProxy = Object.entries(headers).some( - ([key, val]) => key.toLowerCase() === 'x-nf-hidden-proxy' && val === 'true', - ) - const target = new URL(rule.to, request.url) - const match: RedirectsMatch = { - external: 'to' in rule && /^https?:\/\//.exec(rule.to) != null, - force: rule.force, - headers, - hiddenProxy, - redirect: 'status' in rule && rule.status != null && rule.status >= 300 && rule.status <= 400, - statusCode: rule.status, - target, - targetRelative: `${rule.to}${requestURL.search}${requestURL.hash}`, - } - - if (target.searchParams.size === 0) { - requestURL.searchParams.forEach((val, key) => { - target.searchParams.append(key, val) - }) - } - - if (rule.signingSecret) { - const signingSecretVar = process.env[rule.signingSecret] - - if (signingSecretVar) { - match.headers['x-nf-sign'] = signRedirect({ - deployContext: 'dev', - secret: signingSecretVar, - siteID: this.siteID, - siteURL: this.siteURL, - }) - } else { - match.error = new Error(`Could not sign redirect because environment variable ${rule.signingSecret} is not set`) - } - } - - return match - } - - async handle(request: Request, match: RedirectsMatch, getStaticFile: GetStaticFile) { - if (match.force && match.statusCode === 404) { - return this.notFoundHandler(request) - } - - const sourceStaticFile = await getStaticFile(request) - if (sourceStaticFile && !match.force) { - return sourceStaticFile() - } - - if (match.redirect) { - return Response.redirect(match.target, match.statusCode) - } - - if (match.external) { - const req = new Request(match.target, request) - - return fetch(req) - } - - const targetStaticFile = await getStaticFile(new Request(match.target, request)) - if (targetStaticFile) { - return targetStaticFile() - } - } -} diff --git a/packages/redirects/tsconfig.json b/packages/redirects/tsconfig.json deleted file mode 100644 index 88d0ead..0000000 --- a/packages/redirects/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "typeRoots": ["node_modules/@types", "types"] - }, - "include": ["src"] -} diff --git a/packages/redirects/tsup.config.ts b/packages/redirects/tsup.config.ts deleted file mode 100644 index 9a08857..0000000 --- a/packages/redirects/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['esm'], - entry: ['src/main.ts'], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/redirects/types/netlify-redirector.d.ts b/packages/redirects/types/netlify-redirector.d.ts deleted file mode 100644 index f09c231..0000000 --- a/packages/redirects/types/netlify-redirector.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -declare module 'netlify-redirector' { - export interface Options { - jwtSecret?: string - jwtRoleClaim?: string - } - export interface Request { - scheme: string - host: string - path: string - query: string - getHeader: (name: string) => string - getCookie: (name: string) => string - } - export type Match = ( - | { - from: string - to: string - host: string - scheme: string - status: number - force: boolean - negative: boolean - proxyHeaders?: Record - signingSecret?: string - } - | { - force404: true - } - ) & { - force404?: boolean - conditions: Record - exceptions: Record - } - export interface RedirectMatcher { - match(req: Request): Match | null - } - export function parsePlain(rules: string, options: Options): Promise - export function parseJSON(rules: string, options: Options): Promise -} diff --git a/packages/runtime-utils/.gitignore b/packages/runtime-utils/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/runtime-utils/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/runtime-utils/CHANGELOG.md b/packages/runtime-utils/CHANGELOG.md deleted file mode 100644 index 9c3a714..0000000 --- a/packages/runtime-utils/CHANGELOG.md +++ /dev/null @@ -1,75 +0,0 @@ -# Changelog - -## [2.3.0](https://github.com/netlify/primitives/compare/runtime-utils-v2.2.1...runtime-utils-v2.3.0) (2026-02-06) - - -### Features - -* move `getEnvironment` to `runtime-utils` ([#579](https://github.com/netlify/primitives/issues/579)) ([639ba5f](https://github.com/netlify/primitives/commit/639ba5f5d5659bcf96894dc627a87af42c8fc19f)) - -## [2.2.1](https://github.com/netlify/primitives/compare/runtime-utils-v2.2.0...runtime-utils-v2.2.1) (2025-11-04) - - -### Bug Fixes - -* add CJS support to @netlify/runtime-utils to fix ERR_REQUIRE_ESM ([#510](https://github.com/netlify/primitives/issues/510)) ([a6c3a26](https://github.com/netlify/primitives/commit/a6c3a268d13fc60849f16b5cba6064710366c096)), closes [#437](https://github.com/netlify/primitives/issues/437) - -## [2.2.0](https://github.com/netlify/primitives/compare/runtime-utils-v2.1.0...runtime-utils-v2.2.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - -## [2.1.0](https://github.com/netlify/primitives/compare/runtime-utils-v2.0.0...runtime-utils-v2.1.0) (2025-06-02) - - -### Features - -* add support for edge functions ([#233](https://github.com/netlify/primitives/issues/233)) ([c80d77d](https://github.com/netlify/primitives/commit/c80d77ddf59e394f9d8a84a96275c25c1b9aefc0)) - - -### Bug Fixes - -* ensure valid 18.14.0+ dependencies ([#254](https://github.com/netlify/primitives/issues/254)) ([09dd0d8](https://github.com/netlify/primitives/commit/09dd0d8e1ab0c028eee8715b05307d8961b28463)) - -## [2.0.0](https://github.com/netlify/primitives/compare/runtime-utils-v1.3.1...runtime-utils-v2.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - -## [1.3.1](https://github.com/netlify/primitives/compare/runtime-utils-v1.3.0...runtime-utils-v1.3.1) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - -## [1.3.0](https://github.com/netlify/primitives/compare/runtime-utils-v1.2.0...runtime-utils-v1.3.0) (2025-05-07) - - -### Features - -* add separate package for types ([#175](https://github.com/netlify/primitives/issues/175)) ([bb70188](https://github.com/netlify/primitives/commit/bb7018856ebda7a52ccff291cb306478e2853468)) - -## [1.2.0](https://github.com/netlify/primitives/compare/runtime-utils-v1.1.0...runtime-utils-v1.2.0) (2025-05-06) - - -### Features - -* make `fetchWithCache` use `waitUntil` if available ([#161](https://github.com/netlify/primitives/issues/161)) ([dd9b7fd](https://github.com/netlify/primitives/commit/dd9b7fd5d0bd8b236d446d3211bfe880fedf4887)) - -## [1.1.0](https://github.com/netlify/primitives/compare/runtime-utils-v1.0.0...runtime-utils-v1.1.0) (2025-05-02) - - -### Features - -* add `runtime` and `runtime-utils` packages ([#150](https://github.com/netlify/primitives/issues/150)) ([be2cbf0](https://github.com/netlify/primitives/commit/be2cbf05cd3b73a795b54f94b7f51dacbcf6ef34)) - -## Changelog diff --git a/packages/runtime-utils/package.json b/packages/runtime-utils/package.json deleted file mode 100644 index d369e7e..0000000 --- a/packages/runtime-utils/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@netlify/runtime-utils", - "version": "2.3.0", - "description": "Cross-environment utilities for the Netlify runtime", - "type": "module", - "engines": { - "node": "^18.14.0 || >=20" - }, - "main": "./dist/main.cjs", - "module": "./dist/main.js", - "types": "./dist/main.d.ts", - "exports": { - ".": { - "require": { - "types": "./dist/main.d.cts", - "default": "./dist/main.cjs" - }, - "import": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - }, - "default": { - "types": "./dist/main.d.ts", - "default": "./dist/main.js" - } - } - }, - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/runtime-utils" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@types/node": "^18.19.110", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - } -} diff --git a/packages/runtime-utils/src/lib/base64.ts b/packages/runtime-utils/src/lib/base64.ts deleted file mode 100644 index 1bc1a95..0000000 --- a/packages/runtime-utils/src/lib/base64.ts +++ /dev/null @@ -1,9 +0,0 @@ -const getString = (input: string | object) => (typeof input === 'string' ? input : JSON.stringify(input)) - -export const base64Decode = globalThis.Buffer - ? (input: string) => Buffer.from(input, 'base64').toString() - : (input: string) => atob(input) - -export const base64Encode = globalThis.Buffer - ? (input: string | object) => Buffer.from(getString(input)).toString('base64') - : (input: string | object) => btoa(getString(input)) diff --git a/packages/runtime-utils/src/lib/environment.ts b/packages/runtime-utils/src/lib/environment.ts deleted file mode 100644 index a447edb..0000000 --- a/packages/runtime-utils/src/lib/environment.ts +++ /dev/null @@ -1,43 +0,0 @@ -export interface EnvironmentVariables { - delete: (key: string) => void - get: (key: string) => string | undefined - has: (key: string) => boolean - set: (key: string, value: string) => void - toObject: () => Record -} - -interface Globals { - Deno?: { - env: EnvironmentVariables - } - Netlify?: { - env: EnvironmentVariables - } - process?: { - env: Record - } -} - -/** - * Returns a cross-runtime interface for handling environment variables. It - * uses the `Netlify.env` global if available, otherwise looks for `Deno.env` - * and `process.env`. - */ -export const getEnvironment = (): EnvironmentVariables => { - const { Deno, Netlify, process } = globalThis as Globals - - return ( - Netlify?.env ?? - Deno?.env ?? { - delete: (key: string) => delete process?.env[key], - get: (key: string) => process?.env[key], - has: (key: string) => Boolean(process?.env[key]), - set: (key: string, value: string) => { - if (process?.env) { - process.env[key] = value - } - }, - toObject: () => process?.env ?? {}, - } - ) -} diff --git a/packages/runtime-utils/src/main.test.ts b/packages/runtime-utils/src/main.test.ts deleted file mode 100644 index e7a276b..0000000 --- a/packages/runtime-utils/src/main.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import { base64Decode, base64Encode } from './main.js' - -describe('Base 64', () => { - test('Encodes and decodes', async () => { - expect(base64Decode(base64Encode('Hello'))).toBe('Hello') - }) -}) diff --git a/packages/runtime-utils/src/main.ts b/packages/runtime-utils/src/main.ts deleted file mode 100644 index 963932b..0000000 --- a/packages/runtime-utils/src/main.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { base64Decode, base64Encode } from './lib/base64.js' -export { getEnvironment, type EnvironmentVariables } from './lib/environment.js' diff --git a/packages/runtime-utils/tsconfig.json b/packages/runtime-utils/tsconfig.json deleted file mode 100644 index 7b592ea..0000000 --- a/packages/runtime-utils/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/runtime-utils/tsup.config.ts b/packages/runtime-utils/tsup.config.ts deleted file mode 100644 index 5d493d3..0000000 --- a/packages/runtime-utils/tsup.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - // We build both CJS and ESM because @netlify/blobs is dual-format and depends on this package. - // When @netlify/blobs becomes ESM-only, we can remove CJS here and go ESM-only too. - // See: https://github.com/netlify/primitives/issues/437 - format: ['cjs', 'esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - }, -]) diff --git a/packages/runtime/.gitignore b/packages/runtime/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/runtime/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/runtime/CHANGELOG.md b/packages/runtime/CHANGELOG.md deleted file mode 100644 index b40efff..0000000 --- a/packages/runtime/CHANGELOG.md +++ /dev/null @@ -1,608 +0,0 @@ -# Changelog - -## [4.1.25](https://github.com/netlify/primitives/compare/runtime-v4.1.24...runtime-v4.1.25) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.8 to ^10.7.9 - * @netlify/cache bumped from 3.4.7 to 3.4.8 - * @netlify/types bumped from 2.7.0 to 2.8.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.4.5 to ^4.4.6 - -## [4.1.24](https://github.com/netlify/primitives/compare/runtime-v4.1.23...runtime-v4.1.24) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.7 to ^10.7.8 - * @netlify/cache bumped from 3.4.6 to 3.4.7 - * @netlify/types bumped from 2.6.0 to 2.7.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.4.4 to ^4.4.5 - -## [4.1.23](https://github.com/netlify/primitives/compare/runtime-v4.1.22...runtime-v4.1.23) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.6 to ^10.7.7 - * @netlify/cache bumped from 3.4.5 to 3.4.6 - * devDependencies - * @netlify/dev-utils bumped from ^4.4.3 to ^4.4.4 - -## [4.1.22](https://github.com/netlify/primitives/compare/runtime-v4.1.21...runtime-v4.1.22) (2026-05-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.5 to ^10.7.6 - * @netlify/cache bumped from 3.4.4 to 3.4.5 - -## [4.1.21](https://github.com/netlify/primitives/compare/runtime-v4.1.20...runtime-v4.1.21) (2026-05-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.4 to ^10.7.5 - -## [4.1.20](https://github.com/netlify/primitives/compare/runtime-v4.1.19...runtime-v4.1.20) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.3 to ^10.7.4 - * @netlify/cache bumped from 3.4.3 to 3.4.4 - * @netlify/types bumped from 2.5.0 to 2.6.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.4.2 to ^4.4.3 - -## [4.1.19](https://github.com/netlify/primitives/compare/runtime-v4.1.18...runtime-v4.1.19) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.2 to ^10.7.3 - * @netlify/cache bumped from 3.4.2 to 3.4.3 - * @netlify/types bumped from 2.4.0 to 2.5.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.4.1 to ^4.4.2 - -## [4.1.18](https://github.com/netlify/primitives/compare/runtime-v4.1.17...runtime-v4.1.18) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.1 to ^10.7.2 - * @netlify/cache bumped from 3.4.1 to 3.4.2 - * @netlify/types bumped from 2.3.0 to 2.4.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.4.0 to ^4.4.1 - -## [4.1.17](https://github.com/netlify/primitives/compare/runtime-v4.1.16...runtime-v4.1.17) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.7.0 to ^10.7.1 - * @netlify/cache bumped from 3.4.0 to 3.4.1 - * devDependencies - * @netlify/dev-utils bumped from ^4.3.3 to ^4.4.0 - -## [4.1.16](https://github.com/netlify/primitives/compare/runtime-v4.1.15...runtime-v4.1.16) (2026-02-27) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 3.3.5 to 3.4.0 - -## [4.1.15](https://github.com/netlify/primitives/compare/runtime-v4.1.14...runtime-v4.1.15) (2026-02-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.6.0 to ^10.7.0 - -## [4.1.14](https://github.com/netlify/primitives/compare/runtime-v4.1.13...runtime-v4.1.14) (2026-02-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.5.0 to ^10.6.0 - * @netlify/cache bumped from 3.3.4 to 3.3.5 - * @netlify/runtime-utils bumped from 2.2.1 to 2.3.0 - -## [4.1.13](https://github.com/netlify/primitives/compare/runtime-v4.1.12...runtime-v4.1.13) (2025-12-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.4.4 to ^10.5.0 - -## [4.1.12](https://github.com/netlify/primitives/compare/runtime-v4.1.11...runtime-v4.1.12) (2025-12-16) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.4.3 to ^10.4.4 - -## [4.1.11](https://github.com/netlify/primitives/compare/runtime-v4.1.10...runtime-v4.1.11) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.4.2 to ^10.4.3 - * @netlify/cache bumped from 3.3.3 to 3.3.4 - * @netlify/types bumped from 2.2.0 to 2.3.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.3.2 to ^4.3.3 - -## [4.1.10](https://github.com/netlify/primitives/compare/runtime-v4.1.9...runtime-v4.1.10) (2025-12-03) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.4.1 to ^10.4.2 - -## [4.1.9](https://github.com/netlify/primitives/compare/runtime-v4.1.8...runtime-v4.1.9) (2025-11-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.4.0 to ^10.4.1 - -## [4.1.8](https://github.com/netlify/primitives/compare/runtime-v4.1.7...runtime-v4.1.8) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.3.3 to ^10.4.0 - * @netlify/cache bumped from 3.3.2 to 3.3.3 - * devDependencies - * @netlify/dev-utils bumped from ^4.3.1 to ^4.3.2 - -## [4.1.7](https://github.com/netlify/primitives/compare/runtime-v4.1.6...runtime-v4.1.7) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.3.2 to ^10.3.3 - * @netlify/cache bumped from 3.3.1 to 3.3.2 - * @netlify/types bumped from 2.1.0 to 2.2.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.3.0 to ^4.3.1 - -## [4.1.6](https://github.com/netlify/primitives/compare/runtime-v4.1.5...runtime-v4.1.6) (2025-11-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.3.1 to ^10.3.2 - * @netlify/cache bumped from 3.3.0 to 3.3.1 - * @netlify/runtime-utils bumped from 2.2.0 to 2.2.1 - -## [4.1.5](https://github.com/netlify/primitives/compare/runtime-v4.1.4...runtime-v4.1.5) (2025-10-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.3.0 to ^10.3.1 - -## [4.1.4](https://github.com/netlify/primitives/compare/runtime-v4.1.3...runtime-v4.1.4) (2025-10-27) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.2.1 to ^10.3.0 - -## [4.1.3](https://github.com/netlify/primitives/compare/runtime-v4.1.2...runtime-v4.1.3) (2025-10-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.2.0 to ^10.2.1 - -## [4.1.2](https://github.com/netlify/primitives/compare/runtime-v4.1.1...runtime-v4.1.2) (2025-10-22) - - -### Bug Fixes - -* **types:** allow `global.Netlify` declaration merging ([#494](https://github.com/netlify/primitives/issues/494)) ([bd39b15](https://github.com/netlify/primitives/commit/bd39b15ee03ba88362ccd3a83f61530c03b2ceaa)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.1.0 to ^10.2.0 - -## [4.1.1](https://github.com/netlify/primitives/compare/runtime-v4.1.0...runtime-v4.1.1) (2025-10-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 3.2.0 to 3.3.0 - -## [4.1.0](https://github.com/netlify/primitives/compare/runtime-v4.0.16...runtime-v4.1.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.11 to ^10.1.0 - * @netlify/cache bumped from 3.1.1 to 3.2.0 - * @netlify/runtime-utils bumped from 2.1.0 to 2.2.0 - * @netlify/types bumped from 2.0.3 to 2.1.0 - * devDependencies - * @netlify/dev-utils bumped from ^4.2.0 to ^4.3.0 - -## [4.0.16](https://github.com/netlify/primitives/compare/runtime-v4.0.15...runtime-v4.0.16) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.10 to ^10.0.11 - * @netlify/cache bumped from 3.1.0 to 3.1.1 - * devDependencies - * @netlify/dev-utils bumped from ^4.1.3 to ^4.2.0 - -## [4.0.15](https://github.com/netlify/primitives/compare/runtime-v4.0.14...runtime-v4.0.15) (2025-09-05) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 3.0.11 to 3.1.0 - -## [4.0.14](https://github.com/netlify/primitives/compare/runtime-v4.0.13...runtime-v4.0.14) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.9 to ^10.0.10 - * @netlify/cache bumped from 3.0.10 to 3.0.11 - * @netlify/types bumped from 2.0.2 to 2.0.3 - * devDependencies - * @netlify/dev-utils bumped from ^4.1.2 to ^4.1.3 - -## [4.0.13](https://github.com/netlify/primitives/compare/runtime-v4.0.12...runtime-v4.0.13) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.8 to ^10.0.9 - * @netlify/cache bumped from 3.0.9 to 3.0.10 - * devDependencies - * @netlify/dev-utils bumped from ^4.1.1 to ^4.1.2 - -## [4.0.12](https://github.com/netlify/primitives/compare/runtime-v4.0.11...runtime-v4.0.12) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.7 to ^10.0.8 - * @netlify/cache bumped from 3.0.8 to 3.0.9 - * devDependencies - * @netlify/dev-utils bumped from ^4.1.0 to ^4.1.1 - -## [4.0.11](https://github.com/netlify/primitives/compare/runtime-v4.0.10...runtime-v4.0.11) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.6 to ^10.0.7 - * @netlify/cache bumped from 3.0.7 to 3.0.8 - * devDependencies - * @netlify/dev-utils bumped from ^4.0.0 to ^4.1.0 - -## [4.0.10](https://github.com/netlify/primitives/compare/runtime-v4.0.9...runtime-v4.0.10) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.5 to ^10.0.6 - * @netlify/cache bumped from 3.0.6 to 3.0.7 - * devDependencies - * @netlify/dev-utils bumped from ^3.3.0 to ^4.0.0 - -## [4.0.9](https://github.com/netlify/primitives/compare/runtime-v4.0.8...runtime-v4.0.9) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.4 to ^10.0.5 - * @netlify/cache bumped from 3.0.5 to 3.0.6 - * devDependencies - * @netlify/dev-utils bumped from ^3.2.2 to ^3.3.0 - -## [4.0.8](https://github.com/netlify/primitives/compare/runtime-v4.0.7...runtime-v4.0.8) (2025-07-07) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.3 to ^10.0.4 - -## [4.0.7](https://github.com/netlify/primitives/compare/runtime-v4.0.6...runtime-v4.0.7) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.2 to ^10.0.3 - * @netlify/cache bumped from 3.0.4 to 3.0.5 - * devDependencies - * @netlify/dev-utils bumped from ^3.2.1 to ^3.2.2 - -## [4.0.6](https://github.com/netlify/primitives/compare/runtime-v4.0.5...runtime-v4.0.6) (2025-06-26) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.1 to ^10.0.2 - -## [4.0.5](https://github.com/netlify/primitives/compare/runtime-v4.0.4...runtime-v4.0.5) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^10.0.0 to ^10.0.1 - * @netlify/cache bumped from 3.0.3 to 3.0.4 - * devDependencies - * @netlify/dev-utils bumped from ^3.2.0 to ^3.2.1 - -## [4.0.4](https://github.com/netlify/primitives/compare/runtime-v4.0.3...runtime-v4.0.4) (2025-06-11) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.6 to ^10.0.0 - -## [4.0.3](https://github.com/netlify/primitives/compare/runtime-v4.0.2...runtime-v4.0.3) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.5 to ^9.1.6 - * @netlify/cache bumped from 3.0.2 to 3.0.3 - * devDependencies - * @netlify/dev-utils bumped from ^3.1.1 to ^3.2.0 - -## [4.0.2](https://github.com/netlify/primitives/compare/runtime-v4.0.1...runtime-v4.0.2) (2025-06-04) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 3.0.1 to 3.0.2 - * @netlify/types bumped from 2.0.1 to 2.0.2 - -## [4.0.1](https://github.com/netlify/primitives/compare/runtime-v4.0.0...runtime-v4.0.1) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.4 to ^9.1.5 - * @netlify/cache bumped from 3.0.0 to 3.0.1 - * devDependencies - * @netlify/dev-utils bumped from ^3.1.0 to ^3.1.1 - -## [4.0.0](https://github.com/netlify/primitives/compare/runtime-v3.0.0...runtime-v4.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Bug Fixes - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.3 to ^9.1.4 - * @netlify/cache bumped from 2.0.0 to 3.0.0 - * @netlify/runtime-utils bumped from 2.0.0 to 2.1.0 - * @netlify/types bumped from 2.0.0 to 2.0.1 - * devDependencies - * @netlify/dev-utils bumped from ^3.0.0 to ^3.1.0 - -## [3.0.0](https://github.com/netlify/primitives/compare/runtime-v2.2.2...runtime-v3.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Bug Fixes - -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/blobs bumped from ^9.1.2 to ^9.1.3 - * @netlify/cache bumped from 1.11.2 to 2.0.0 - * @netlify/runtime-utils bumped from 1.3.1 to 2.0.0 - * @netlify/types bumped from 1.2.0 to 2.0.0 - * devDependencies - * @netlify/dev-utils bumped from ^2.2.0 to ^3.0.0 - -## [2.2.2](https://github.com/netlify/primitives/compare/runtime-v2.2.1...runtime-v2.2.2) (2025-05-23) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 1.11.1 to 1.11.2 - * @netlify/types bumped from 1.1.1 to 1.2.0 - -## [2.2.1](https://github.com/netlify/primitives/compare/runtime-v2.2.0...runtime-v2.2.1) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 1.11.0 to 1.11.1 - * @netlify/runtime-utils bumped from 1.3.0 to 1.3.1 - * @netlify/types bumped from 1.1.0 to 1.1.1 - -## [2.2.0](https://github.com/netlify/primitives/compare/runtime-v2.1.1...runtime-v2.2.0) (2025-05-07) - - -### Features - -* add separate package for types ([#175](https://github.com/netlify/primitives/issues/175)) ([bb70188](https://github.com/netlify/primitives/commit/bb7018856ebda7a52ccff291cb306478e2853468)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @netlify/cache bumped from 1.10.0 to 1.11.0 - * @netlify/runtime-utils bumped from 1.2.0 to 1.3.0 - * @netlify/types bumped from 1.0.0 to 1.1.0 - -## [2.1.1](https://github.com/netlify/primitives/compare/runtime-v2.1.0...runtime-v2.1.1) (2025-05-06) - - -### Bug Fixes - -* adjust dependencies and exports ([#169](https://github.com/netlify/primitives/issues/169)) ([7ebbd3a](https://github.com/netlify/primitives/commit/7ebbd3aa3126c8ebe6c9880c62b3ad50b0b219c2)) - -## [2.1.0](https://github.com/netlify/primitives/compare/runtime-v2.0.0...runtime-v2.1.0) (2025-05-06) - - -### Features - -* make `fetchWithCache` use `waitUntil` if available ([#161](https://github.com/netlify/primitives/issues/161)) ([dd9b7fd](https://github.com/netlify/primitives/commit/dd9b7fd5d0bd8b236d446d3211bfe880fedf4887)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/cache bumped from 1.9.0 to 1.10.0 - * @netlify/runtime-utils bumped from 1.1.0 to 1.2.0 - -## [2.0.0](https://github.com/netlify/primitives/compare/runtime-v1.0.0...runtime-v2.0.0) (2025-05-02) - - -### ⚠ BREAKING CHANGES - -* The `BlobsServer` class now only exports the `start()` and `stop()` methods. This class is not part of the Netlify Blobs client, and it's mostly used internally by Netlify tooling and by some users for integration tests — if you're just using the methods listed in https://docs.netlify.com/blobs/overview/#api-reference, this change does not apply to you and you can safely upgrade. - -### Features - -* add `runtime` and `runtime-utils` packages ([#150](https://github.com/netlify/primitives/issues/150)) ([be2cbf0](https://github.com/netlify/primitives/commit/be2cbf05cd3b73a795b54f94b7f51dacbcf6ef34)) -* add `start` entry point ([#154](https://github.com/netlify/primitives/issues/154)) ([b23c607](https://github.com/netlify/primitives/commit/b23c607ed3aa5e76279efa773b8c6c4d0dee972c)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/cache bumped from 1.8.2 to 1.9.0 - * @netlify/runtime-utils bumped from 1.0.0 to 1.1.0 - -## Changelog diff --git a/packages/runtime/package.json b/packages/runtime/package.json deleted file mode 100644 index 2da5756..0000000 --- a/packages/runtime/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@netlify/runtime", - "version": "4.1.25", - "description": "Netlify compute runtime", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.js", - "exports": "./dist/main.js", - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/runtime" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "dependencies": { - "@netlify/blobs": "^10.7.9", - "@netlify/cache": "3.4.8", - "@netlify/runtime-utils": "2.3.0", - "@netlify/types": "2.8.0" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/node": "^20.17.57", - "tsup": "^8.0.0", - "vitest": "^3.0.0" - } -} diff --git a/packages/runtime/src/lib/environment/blobs.ts b/packages/runtime/src/lib/environment/blobs.ts deleted file mode 100644 index ed017c2..0000000 --- a/packages/runtime/src/lib/environment/blobs.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { EnvironmentContext } from '@netlify/blobs' -import { base64Encode } from '@netlify/runtime-utils' -import type { NetlifyGlobal } from '@netlify/types' - -export interface BlobsOptions { - edgeURL: string - primaryRegion: string - uncachedEdgeURL: string - token: string -} - -export interface SetupBlobsEnvironmentOptions extends BlobsOptions { - deployID: string - env: NetlifyGlobal['env'] - globalScope: Record - preferGlobal?: boolean - siteID: string -} - -export const setupBlobsEnvironment = ({ - deployID, - edgeURL, - env, - globalScope, - primaryRegion, - preferGlobal, - siteID, - token, - uncachedEdgeURL, -}: SetupBlobsEnvironmentOptions) => { - const context: EnvironmentContext = { - deployID, - edgeURL, - primaryRegion, - siteID, - token, - uncachedEdgeURL, - } - const serializedContext = base64Encode(JSON.stringify(context)) - - if (preferGlobal) { - globalScope.netlifyBlobsContext = serializedContext - } else { - env.set('NETLIFY_BLOBS_CONTEXT', serializedContext) - } -} diff --git a/packages/runtime/src/lib/environment/branch.ts b/packages/runtime/src/lib/environment/branch.ts deleted file mode 100644 index 90894ee..0000000 --- a/packages/runtime/src/lib/environment/branch.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { NetlifyGlobal } from '@netlify/types' - -export interface SetupCachePurgeEnvironmentOptions { - branch: string - env: NetlifyGlobal['env'] -} - -export const setupBranchEnvironment = ({ branch, env }: SetupCachePurgeEnvironmentOptions) => { - env.set('NETLIFY_BRANCH', branch) -} diff --git a/packages/runtime/src/lib/environment/purge.ts b/packages/runtime/src/lib/environment/purge.ts deleted file mode 100644 index d0965e7..0000000 --- a/packages/runtime/src/lib/environment/purge.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { NetlifyGlobal } from '@netlify/types' - -export interface SetupCachePurgeEnvironmentOptions { - env: NetlifyGlobal['env'] - token: string -} - -export const setupCachePurgeEnvironment = ({ env, token }: SetupCachePurgeEnvironmentOptions) => { - env.set('NETLIFY_PURGE_API_TOKEN', token) -} diff --git a/packages/runtime/src/lib/globals.ts b/packages/runtime/src/lib/globals.ts deleted file mode 100644 index a90e295..0000000 --- a/packages/runtime/src/lib/globals.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { type RequestContextFactory, NetlifyCacheStorage } from '@netlify/cache/bootstrap' -import type { Context, NetlifyGlobal } from '@netlify/types' - -import { GlobalScope } from './util.js' - -declare global { - // Using `var` instead of `const` to allow TypeScript declaration merging. - // Multiple packages can declare the same global with `var`, but `const` cannot be redeclared. - var Netlify: NetlifyGlobal -} - -const setCachesGlobal = (globalScope: GlobalScope, getContext: RequestContextFactory, userAgent?: string) => { - globalScope.caches = new NetlifyCacheStorage({ - getContext, - userAgent, - }) -} - -const setNetlifyGlobal = (globalScope: GlobalScope, env: NetlifyGlobal['env'], getContext: () => Context | null) => { - globalScope.Netlify = { - get context() { - return getContext() - }, - env, - } -} - -export interface SetGlobalsOptions { - env: NetlifyGlobal['env'] - getCacheContext: RequestContextFactory - getRequestContext: () => Context | null - globalScope: GlobalScope - userAgent?: string -} - -export const setGlobals = ({ env, getCacheContext, getRequestContext, globalScope, userAgent }: SetGlobalsOptions) => { - setCachesGlobal(globalScope, getCacheContext, userAgent) - setNetlifyGlobal(globalScope, env, getRequestContext) -} diff --git a/packages/runtime/src/lib/util.ts b/packages/runtime/src/lib/util.ts deleted file mode 100644 index 866412f..0000000 --- a/packages/runtime/src/lib/util.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const isNonEmptyString = (value: unknown): value is string => typeof value === 'string' && value.length !== 0 - -export type GlobalScope = Record diff --git a/packages/runtime/src/main.test.ts b/packages/runtime/src/main.test.ts deleted file mode 100644 index 5a80269..0000000 --- a/packages/runtime/src/main.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { NetlifyCacheStorage } from '@netlify/cache/bootstrap' -import { MockFetch } from '@netlify/dev-utils' -import { base64Decode } from '@netlify/runtime-utils' -import { describe, expect, test } from 'vitest' - -import type { Context, EnvironmentVariables } from '@netlify/types' -import type { GlobalScope } from './lib/util.js' -import { startRuntime } from './main.js' - -describe('`startRuntime`', () => { - test('Populates environment', async () => { - const envStore: Record = {} - const env: EnvironmentVariables = { - delete: (key: string) => delete envStore[key], - get: (key: string) => envStore[key], - has: (key: string) => Boolean(envStore[key]), - set: (key: string, value: string) => (envStore[key] = value), - toObject: () => envStore, - } - const globalScope: GlobalScope = {} - const blobs = { - edgeURL: 'https://edge.blobs.netlify', - primaryRegion: 'us-local-1', - uncachedEdgeURL: 'https://uncached-edge.blobs.netlify', - token: 'token123', - } - const cacheContext = { - host: 'host.netlify', - url: 'https://example.netlify/.netlify/cache', - token: 'mock-token', - } - const cachePurgeToken = 'token321' - const deployID = 'deploy123' - const siteID = 'site123' - const cachedResponseBody = 'Hello' - const mockFetch = new MockFetch() - .get({ - response: new Response(cachedResponseBody), - url: 'https://example.netlify/.netlify/cache/https%3A%2F%2Fnetlify.com%2F', - }) - .inject() - const requestContext: Context = { - account: { - id: 'account123', - }, - cookies: { - delete: () => {}, - get: () => '', - set: () => {}, - }, - deploy: { - context: 'production', - id: deployID, - published: true, - }, - geo: {}, - ip: '123.4.5.6', - json: Response.json, - log: console.log, - next: async () => new Response('Next'), - params: {}, - rewrite: async () => new Response('Rewrite'), - requestId: 'request123', - server: { - region: 'us-local-1', - }, - site: { - id: siteID, - }, - url: new URL('http://localhost/hello'), - waitUntil: () => {}, - } - - startRuntime({ - blobs, - cache: { - getCacheAPIContext: () => cacheContext, - purgeToken: cachePurgeToken, - }, - deployID, - env, - getRequestContext: () => requestContext, - globalScope, - siteID, - }) - - const blobsContext = JSON.parse(base64Decode(envStore.NETLIFY_BLOBS_CONTEXT)) - expect(blobsContext).toStrictEqual({ - ...blobs, - deployID, - siteID, - }) - - expect(globalScope.Netlify.context).toBe(requestContext) - expect(envStore.NETLIFY_PURGE_API_TOKEN).toBe(cachePurgeToken) - - expect(globalScope.caches).not.toBeUndefined() - const cache = await (globalScope.caches as NetlifyCacheStorage).open('my-cache') - const response = await cache.match('https://netlify.com') - - expect(await response?.text()).toBe(cachedResponseBody) - - mockFetch.restore() - expect(mockFetch.fulfilled).toBe(true) - }) -}) diff --git a/packages/runtime/src/main.ts b/packages/runtime/src/main.ts deleted file mode 100644 index 0f33efc..0000000 --- a/packages/runtime/src/main.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { RequestContextFactory } from '@netlify/cache/bootstrap' -import type { Context, NetlifyGlobal } from '@netlify/types' - -import { type BlobsOptions, setupBlobsEnvironment } from './lib/environment/blobs.js' -import { setupBranchEnvironment } from './lib/environment/branch.js' -import { setupCachePurgeEnvironment } from './lib/environment/purge.js' -import { setGlobals } from './lib/globals.js' -import { GlobalScope, isNonEmptyString } from './lib/util.js' - -interface StartRuntimeOptions { - blobs?: BlobsOptions - branch?: string - cache: { - getCacheAPIContext: RequestContextFactory - purgeToken?: string - } - deployID: string - env: NetlifyGlobal['env'] - getRequestContext: () => Context | null - globalScope?: GlobalScope - preferGlobal?: boolean - siteID: string - userAgent?: string -} - -export const startRuntime = ({ - blobs, - branch, - cache, - deployID, - env, - getRequestContext, - globalScope = globalThis, - preferGlobal, - siteID, - userAgent, -}: StartRuntimeOptions) => { - if (blobs) { - setupBlobsEnvironment({ - ...blobs, - deployID, - env, - globalScope, - preferGlobal, - siteID, - }) - } - - setGlobals({ - env, - getCacheContext: cache.getCacheAPIContext, - getRequestContext, - globalScope, - userAgent, - }) - - if (isNonEmptyString(cache.purgeToken)) { - setupCachePurgeEnvironment({ - env, - token: cache.purgeToken, - }) - } - - if (isNonEmptyString(branch)) { - setupBranchEnvironment({ branch, env }) - } -} diff --git a/packages/runtime/tsconfig.json b/packages/runtime/tsconfig.json deleted file mode 100644 index 8c07766..0000000 --- a/packages/runtime/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "rootDir": "./src", - "moduleResolution": "nodenext", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/runtime/tsup.config.ts b/packages/runtime/tsup.config.ts deleted file mode 100644 index c3b8320..0000000 --- a/packages/runtime/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - }, -]) diff --git a/packages/static/.gitignore b/packages/static/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/static/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/static/CHANGELOG.md b/packages/static/CHANGELOG.md deleted file mode 100644 index 1483489..0000000 --- a/packages/static/CHANGELOG.md +++ /dev/null @@ -1,307 +0,0 @@ -# Changelog - -## [3.1.10](https://github.com/netlify/primitives/compare/static-v3.1.9...static-v3.1.10) (2026-05-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.5 to ^4.4.6 - -## [3.1.9](https://github.com/netlify/primitives/compare/static-v3.1.8...static-v3.1.9) (2026-05-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.4 to ^4.4.5 - -## [3.1.8](https://github.com/netlify/primitives/compare/static-v3.1.7...static-v3.1.8) (2026-05-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.3 to ^4.4.4 - -## [3.1.7](https://github.com/netlify/primitives/compare/static-v3.1.6...static-v3.1.7) (2026-03-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.2 to ^4.4.3 - -## [3.1.6](https://github.com/netlify/primitives/compare/static-v3.1.5...static-v3.1.6) (2026-03-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.1 to ^4.4.2 - -## [3.1.5](https://github.com/netlify/primitives/compare/static-v3.1.4...static-v3.1.5) (2026-03-12) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.4.0 to ^4.4.1 - -## [3.1.4](https://github.com/netlify/primitives/compare/static-v3.1.3...static-v3.1.4) (2026-03-10) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.3 to ^4.4.0 - -## [3.1.3](https://github.com/netlify/primitives/compare/static-v3.1.2...static-v3.1.3) (2025-12-08) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.2 to ^4.3.3 - -## [3.1.2](https://github.com/netlify/primitives/compare/static-v3.1.1...static-v3.1.2) (2025-11-14) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.1 to ^4.3.2 - -## [3.1.1](https://github.com/netlify/primitives/compare/static-v3.1.0...static-v3.1.1) (2025-11-05) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.3.0 to ^4.3.1 - -## [3.1.0](https://github.com/netlify/primitives/compare/static-v3.0.11...static-v3.1.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.2.0 to ^4.3.0 - -## [3.0.11](https://github.com/netlify/primitives/compare/static-v3.0.10...static-v3.0.11) (2025-09-22) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.3 to ^4.2.0 - -## [3.0.10](https://github.com/netlify/primitives/compare/static-v3.0.9...static-v3.0.10) (2025-08-28) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.2 to ^4.1.3 - -## [3.0.9](https://github.com/netlify/primitives/compare/static-v3.0.8...static-v3.0.9) (2025-08-19) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.1 to ^4.1.2 - -## [3.0.8](https://github.com/netlify/primitives/compare/static-v3.0.7...static-v3.0.8) (2025-07-29) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.1.0 to ^4.1.1 - -## [3.0.7](https://github.com/netlify/primitives/compare/static-v3.0.6...static-v3.0.7) (2025-07-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^4.0.0 to ^4.1.0 - -## [3.0.6](https://github.com/netlify/primitives/compare/static-v3.0.5...static-v3.0.6) (2025-07-17) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.3.0 to ^4.0.0 - -## [3.0.5](https://github.com/netlify/primitives/compare/static-v3.0.4...static-v3.0.5) (2025-07-15) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.2 to ^3.3.0 - -## [3.0.4](https://github.com/netlify/primitives/compare/static-v3.0.3...static-v3.0.4) (2025-07-04) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.1 to ^3.2.2 - -## [3.0.3](https://github.com/netlify/primitives/compare/static-v3.0.2...static-v3.0.3) (2025-06-18) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.2.0 to ^3.2.1 - -## [3.0.2](https://github.com/netlify/primitives/compare/static-v3.0.1...static-v3.0.2) (2025-06-06) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.1.1 to ^3.2.0 - -## [3.0.1](https://github.com/netlify/primitives/compare/static-v3.0.0...static-v3.0.1) (2025-06-03) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.1.0 to ^3.1.1 - -## [3.0.0](https://github.com/netlify/primitives/compare/static-v2.0.0...static-v3.0.0) (2025-06-02) - - -### ⚠ BREAKING CHANGES - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) - -### Features - -* support multiple directories to serve static files ([#253](https://github.com/netlify/primitives/issues/253)) ([153f6ef](https://github.com/netlify/primitives/commit/153f6efda2e681d98753ebd7a1cb487ffc55560b)) - - -### Bug Fixes - -* drop EOL'd node 18 support in new packages ([#252](https://github.com/netlify/primitives/issues/252)) ([38791ab](https://github.com/netlify/primitives/commit/38791ab91dcbf1f05093ba123eaccdf960a2d6e7)) -* support publish dir being set to not root directory ([#256](https://github.com/netlify/primitives/issues/256)) ([4987223](https://github.com/netlify/primitives/commit/4987223d8850d4a724eb6f9bdbc855edbe463e50)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^3.0.0 to ^3.1.0 - -## [2.0.0](https://github.com/netlify/primitives/compare/static-v1.1.4...static-v2.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Bug Fixes - -* **deps:** update dependency mime-types to v3 ([#220](https://github.com/netlify/primitives/issues/220)) ([3278be8](https://github.com/netlify/primitives/commit/3278be806e465c3baa4ee75a977350e1ede1111b)) -* remove unused dependencies, add undeclared dependencies ([#230](https://github.com/netlify/primitives/issues/230)) ([180546a](https://github.com/netlify/primitives/commit/180546aa03b569000ed52cafb07014e9a4c76a1a)) - - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from ^2.2.0 to ^3.0.0 - -## [1.1.4](https://github.com/netlify/primitives/compare/static-v1.1.3...static-v1.1.4) (2025-05-23) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.1.1 to 2.2.0 - -## [1.1.3](https://github.com/netlify/primitives/compare/static-v1.1.2...static-v1.1.3) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.1.0 to 2.1.1 - -## [1.1.2](https://github.com/netlify/primitives/compare/static-v1.1.1...static-v1.1.2) (2025-05-06) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 2.0.0 to 2.1.0 - -## [1.1.1](https://github.com/netlify/primitives/compare/static-v1.1.0...static-v1.1.1) (2025-05-02) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 1.1.0 to 2.0.0 - -## [1.1.0](https://github.com/netlify/primitives/compare/static-v1.0.0...static-v1.1.0) (2025-04-16) - - -### Features - -* move primitives into monorepo ([#101](https://github.com/netlify/primitives/issues/101)) ([93b72b1](https://github.com/netlify/primitives/commit/93b72b1364022e45cbd87814dc6aa235f1e1c83e)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @netlify/dev-utils bumped from 1.0.0 to 1.1.0 diff --git a/packages/static/package.json b/packages/static/package.json deleted file mode 100644 index 7fd8177..0000000 --- a/packages/static/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@netlify/static", - "version": "3.1.10", - "description": "TypeScript implementtion of Netlify's static file serving logic", - "type": "module", - "engines": { - "node": ">=20.6.1" - }, - "main": "./dist/main.js", - "exports": "./dist/main.js", - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && vitest run", - "dev": "tsup-node --watch", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/static" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "directories": { - "test": "test" - }, - "devDependencies": { - "@netlify/dev-utils": "^4.4.6", - "@types/mime-types": "^2.1.4", - "tsup": "^8.5.0", - "vitest": "^3.1.4" - }, - "dependencies": { - "mime-types": "^3.0.0" - } -} diff --git a/packages/static/src/lib/fs.ts b/packages/static/src/lib/fs.ts deleted file mode 100644 index 01b112a..0000000 --- a/packages/static/src/lib/fs.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createReadStream, promises as fs } from 'node:fs' -import { Readable } from 'node:stream' - -export const fileExists = async (path: string) => { - try { - const stat = await fs.stat(path) - - if (stat.isFile()) { - return true - } - } catch { - // no-op - } - - return false -} - -export const getReadableStreamFromFile = (path: string) => { - const stream = createReadStream(path) - - return Readable.toWeb(stream) as ReadableStream -} diff --git a/packages/static/src/lib/paths.ts b/packages/static/src/lib/paths.ts deleted file mode 100644 index 3b18359..0000000 --- a/packages/static/src/lib/paths.ts +++ /dev/null @@ -1,37 +0,0 @@ -import path from 'node:path' - -// Used as an optimization to avoid dual lookups for missing assets -const assetExtensionRegExp = /\.(html?|png|jpg|js|css|svg|gif|ico|woff|woff2)$/ - -export const getFilePathsForURL = (pathname: string, baseDirectory = '') => { - const urlVariations = getURLVariations(pathname) - const possiblePaths = urlVariations.map((urlVariation) => { - const parts = urlVariation.split('/').filter(Boolean) - - return path.resolve.apply(null, [baseDirectory, ...parts]) - }) - - return possiblePaths -} - -export const getURLVariations = (pathname: string) => { - const paths: string[] = [] - - if (pathname.endsWith('/')) { - const end = pathname.length - 1 - - if (pathname !== '/') { - paths.push(`${pathname.slice(0, end)}.html`, `${pathname.slice(0, end)}.htm`) - } - - paths.push(`${pathname}index.html`, `${pathname}index.htm`) - } else if (!assetExtensionRegExp.test(pathname)) { - paths.push(`${pathname}.html`, `${pathname}.htm`, `${pathname}/index.html`, `${pathname}/index.htm`) - } - - if (!paths.includes(pathname)) { - return [pathname, ...paths] - } - - return paths -} diff --git a/packages/static/src/main.test.ts b/packages/static/src/main.test.ts deleted file mode 100644 index d89b70f..0000000 --- a/packages/static/src/main.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { join } from 'node:path' - -import { Fixture } from '@netlify/dev-utils' -import { describe, expect, test } from 'vitest' - -import { StaticHandler } from './main.js' - -describe('`StaticHandler`', () => { - test('Returns static files', async () => { - const fixture = new Fixture() - .withFile('public/index.html', `Hello from the root`) - .withFile('public/index.htm', `I should not see the light of day`) - .withFile('public/store/index.html', `Hello from the store`) - - const directory = await fixture.create() - const handler = new StaticHandler({ - directory: join(directory, 'public'), - }) - - const req1 = new Request('https://site.netlify/unknown') - const match1 = await handler.match(req1) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify') - const match2 = await handler.match(req2) - expect(match2).not.toBeUndefined() - const res2 = await match2?.handle() - expect(res2?.status).toBe(200) - expect(await res2?.text()).toBe('Hello from the root') - expect(res2?.headers.get('age')).toBe('0') - expect(res2?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res2?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - const req3 = new Request('https://site.netlify/') - const match3 = await handler.match(req3) - expect(match3).not.toBeUndefined() - const res3 = await match3?.handle() - expect(res3?.status).toBe(200) - expect(await res3?.text()).toBe('Hello from the root') - expect(res3?.headers.get('age')).toBe('0') - expect(res3?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res3?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - const req4 = new Request('https://site.netlify/store') - const match4 = await handler.match(req4) - expect(match4).not.toBeUndefined() - const res4 = await match4?.handle() - expect(res4?.status).toBe(200) - expect(await res4?.text()).toBe('Hello from the store') - expect(res4?.headers.get('age')).toBe('0') - expect(res4?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res4?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - const req5 = new Request('https://site.netlify/store/index.html') - const match5 = await handler.match(req5) - expect(match5).not.toBeUndefined() - const res5 = await match5?.handle() - expect(res5?.status).toBe(200) - expect(await res5?.text()).toBe('Hello from the store') - expect(res5?.headers.get('age')).toBe('0') - expect(res5?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res5?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - await fixture.destroy() - }) - - test('Supports multiple directories', async () => { - const fixture = new Fixture() - .withFile('public/index.html', `Hello from the root`) - .withFile('public/index.htm', `I should not see the light of day`) - .withFile('public/store/index.html', `Hello from the store`) - .withFile('other/hello.html', `Hello from the other directory`) - - const directory = await fixture.create() - const handler = new StaticHandler({ - directory: [join(directory, 'public'), join(directory, 'other')], - }) - - const req1 = new Request('https://site.netlify/unknown') - const match1 = await handler.match(req1) - expect(match1).toBeUndefined() - - const req2 = new Request('https://site.netlify') - const match2 = await handler.match(req2) - expect(match2).not.toBeUndefined() - const res2 = await match2?.handle() - expect(res2?.status).toBe(200) - expect(await res2?.text()).toBe('Hello from the root') - expect(res2?.headers.get('age')).toBe('0') - expect(res2?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res2?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - const req3 = new Request('https://site.netlify/hello') - const match3 = await handler.match(req3) - expect(match3).not.toBeUndefined() - const res3 = await match3?.handle() - expect(res3?.status).toBe(200) - expect(await res3?.text()).toBe('Hello from the other directory') - expect(res3?.headers.get('age')).toBe('0') - expect(res3?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res3?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - const req4 = new Request('https://site.netlify/store') - const match4 = await handler.match(req4) - expect(match4).not.toBeUndefined() - const res4 = await match4?.handle() - expect(res4?.status).toBe(200) - expect(await res4?.text()).toBe('Hello from the store') - expect(res4?.headers.get('age')).toBe('0') - expect(res4?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res4?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - const req5 = new Request('https://site.netlify/store/index.html') - const match5 = await handler.match(req5) - expect(match5).not.toBeUndefined() - const res5 = await match5?.handle() - expect(res5?.status).toBe(200) - expect(await res5?.text()).toBe('Hello from the store') - expect(res5?.headers.get('age')).toBe('0') - expect(res5?.headers.get('cache-control')).toBe('public, max-age=0, must-revalidate') - expect(res5?.headers.get('content-type')).toBe('text/html; charset=utf-8') - - await fixture.destroy() - }) -}) diff --git a/packages/static/src/main.ts b/packages/static/src/main.ts deleted file mode 100644 index b26736b..0000000 --- a/packages/static/src/main.ts +++ /dev/null @@ -1,53 +0,0 @@ -import path from 'node:path' - -import mime from 'mime-types' - -import { fileExists, getReadableStreamFromFile } from './lib/fs.js' -import { getFilePathsForURL } from './lib/paths.js' - -interface StaticHandlerOptions { - directory: string | string[] -} - -const staticHeaders = { - age: '0', - 'cache-control': 'public, max-age=0, must-revalidate', -} - -export interface StaticMatch { - handle: () => Promise -} - -export class StaticHandler { - private publicDirectories: string[] - - constructor(options: StaticHandlerOptions) { - this.publicDirectories = [...new Set(Array.isArray(options.directory) ? options.directory : [options.directory])] - } - - async match(request: Request): Promise { - const url = new URL(request.url) - const possiblePaths = this.publicDirectories.flatMap((directory) => getFilePathsForURL(url.pathname, directory)) - - for (const possiblePath of possiblePaths) { - if (!(await fileExists(possiblePath))) { - continue - } - - const headers = new Headers(staticHeaders) - const contentType = mime.contentType(path.extname(possiblePath)) - - if (contentType) { - headers.set('content-type', contentType) - } - - return { - handle: async () => { - const stream = getReadableStreamFromFile(possiblePath) - - return new Response(stream, { headers, status: 200 }) - }, - } - } - } -} diff --git a/packages/static/tsconfig.json b/packages/static/tsconfig.json deleted file mode 100644 index 7b592ea..0000000 --- a/packages/static/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/static/tsup.config.ts b/packages/static/tsup.config.ts deleted file mode 100644 index 9a08857..0000000 --- a/packages/static/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - format: ['esm'], - entry: ['src/main.ts'], - tsconfig: 'tsconfig.json', - splitting: false, - bundle: true, - dts: true, - outDir: './dist', - watch: argv.includes('--watch'), - }, -]) diff --git a/packages/types/.gitignore b/packages/types/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/packages/types/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md deleted file mode 100644 index b59d799..0000000 --- a/packages/types/CHANGELOG.md +++ /dev/null @@ -1,110 +0,0 @@ -# Changelog - -## [2.8.0](https://github.com/netlify/primitives/compare/types-v2.7.0...types-v2.8.0) (2026-05-29) - - -### Features - -* add function config properties ([#696](https://github.com/netlify/primitives/issues/696)) ([e43cd8f](https://github.com/netlify/primitives/commit/e43cd8f132ec7d5c4517c29cb7c6dbe9dbd5b6b7)) - -## [2.7.0](https://github.com/netlify/primitives/compare/types-v2.6.0...types-v2.7.0) (2026-05-18) - - -### Features - -* export function regions ([#689](https://github.com/netlify/primitives/issues/689)) ([1725879](https://github.com/netlify/primitives/commit/172587985ec7be9e2576839763f20e154b38ed25)) - -## [2.6.0](https://github.com/netlify/primitives/compare/types-v2.5.0...types-v2.6.0) (2026-03-19) - - -### Features - -* add event handler types ([#630](https://github.com/netlify/primitives/issues/630)) ([8b9bfb9](https://github.com/netlify/primitives/commit/8b9bfb9e3de5491da9db85cba8e7efbf9eb960a2)) - -## [2.5.0](https://github.com/netlify/primitives/compare/types-v2.4.0...types-v2.5.0) (2026-03-18) - - -### Features - -* update event types ([#627](https://github.com/netlify/primitives/issues/627)) ([ef80bce](https://github.com/netlify/primitives/commit/ef80bce73902bd5774316e12e386021701662fd6)) - -## [2.4.0](https://github.com/netlify/primitives/compare/types-v2.3.0...types-v2.4.0) (2026-03-12) - - -### Features - -* **types:** add types for platform events ([#622](https://github.com/netlify/primitives/issues/622)) ([b1c08f0](https://github.com/netlify/primitives/commit/b1c08f0c9b8abe8228316e0b79fc6184e0f95f10)) - -## [2.3.0](https://github.com/netlify/primitives/compare/types-v2.2.0...types-v2.3.0) (2025-12-08) - - -### Features - -* add `context.deploy.skewProtectionToken` ([#552](https://github.com/netlify/primitives/issues/552)) ([b8083e3](https://github.com/netlify/primitives/commit/b8083e3bd2e2255c6ec73d7d85dc0a3ae6b585c7)) - -## [2.2.0](https://github.com/netlify/primitives/compare/types-v2.1.0...types-v2.2.0) (2025-11-05) - - -### Features - -* implement functions timeout defaults and overrides in dev ([#346](https://github.com/netlify/primitives/issues/346)) ([c17753e](https://github.com/netlify/primitives/commit/c17753ec35bdef076db563fa37c1a4222bd5c149)) - -## [2.1.0](https://github.com/netlify/primitives/compare/types-v2.0.3...types-v2.1.0) (2025-10-10) - - -### Features - -* Adds W3C trace context propagation to tracer provider ([#471](https://github.com/netlify/primitives/issues/471)) ([afe4656](https://github.com/netlify/primitives/commit/afe4656df5c3bed13ae8c3357205c07efa27c698)) - -## [2.0.3](https://github.com/netlify/primitives/compare/types-v2.0.2...types-v2.0.3) (2025-08-28) - - -### Bug Fixes - -* restore missing `Netlify` global type in `@netlify/functions` ([#434](https://github.com/netlify/primitives/issues/434)) ([2e028b9](https://github.com/netlify/primitives/commit/2e028b9cbdc88a61da1641ec9bf30704e2b36220)) - -## [2.0.2](https://github.com/netlify/primitives/compare/types-v2.0.1...types-v2.0.2) (2025-06-04) - - -### Bug Fixes - -* reinstate missing edge functions types ([#280](https://github.com/netlify/primitives/issues/280)) ([f4360c9](https://github.com/netlify/primitives/commit/f4360c955812e7b96dfb1b0f8112d70496488ee2)) - -## [2.0.1](https://github.com/netlify/primitives/compare/types-v2.0.0...types-v2.0.1) (2025-06-02) - - -### Bug Fixes - -* ensure valid 18.14.0+ dependencies ([#254](https://github.com/netlify/primitives/issues/254)) ([09dd0d8](https://github.com/netlify/primitives/commit/09dd0d8e1ab0c028eee8715b05307d8961b28463)) - -## [2.0.0](https://github.com/netlify/primitives/compare/types-v1.2.0...types-v2.0.0) (2025-05-28) - - -### ⚠ BREAKING CHANGES - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) - -### Build System - -* fix `engines.node` ([#210](https://github.com/netlify/primitives/issues/210)) ([5604545](https://github.com/netlify/primitives/commit/56045450d0f6c24988a8956c1946209bda4502bc)) - -## [1.2.0](https://github.com/netlify/primitives/compare/types-v1.1.1...types-v1.2.0) (2025-05-23) - - -### Features - -* add support for environment variables ([#197](https://github.com/netlify/primitives/issues/197)) ([03878db](https://github.com/netlify/primitives/commit/03878dbfff4e7e379b9d3e4fb6d9d783e66cc2af)) - -## [1.1.1](https://github.com/netlify/primitives/compare/types-v1.1.0...types-v1.1.1) (2025-05-09) - - -### Bug Fixes - -* fix package settings and add publint ([#180](https://github.com/netlify/primitives/issues/180)) ([dc093b4](https://github.com/netlify/primitives/commit/dc093b4bece80c79b73981602033e60497f87aa4)) - -## [1.1.0](https://github.com/netlify/primitives/compare/types-v1.0.0...types-v1.1.0) (2025-05-07) - - -### Features - -* add separate package for types ([#175](https://github.com/netlify/primitives/issues/175)) ([bb70188](https://github.com/netlify/primitives/commit/bb7018856ebda7a52ccff291cb306478e2853468)) diff --git a/packages/types/README.md b/packages/types/README.md deleted file mode 100644 index f88304e..0000000 --- a/packages/types/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# @netlify/types - -[![npm version](https://img.shields.io/npm/v/@netlify/types.svg)](https://www.npmjs.com/package/@netlify/types) - -TypeScript types for Netlify platform primitives. - -## Installation - -```shell -npm install @netlify/types -``` - -### Requirements - -- Node.js 16.0.0 and above - -## Usage - -This package provides TypeScript type definitions for various Netlify platform primitives. Import the types you need in -your TypeScript code: - -```typescript -import type { Context } from '@netlify/types' -import type { NetlifyGlobal } from '@netlify/types' -``` - -## Types - -The package includes TypeScript definitions for: - -- `Context`: Type definitions for Netlify's context object -- `NetlifyGlobal`: Type definitions for Netlify's global variables - -## Contributing - -Contributions are welcome! If you encounter any issues or have suggestions for improvements, please open an issue or -submit a pull request. diff --git a/packages/types/package.json b/packages/types/package.json deleted file mode 100644 index 728af46..0000000 --- a/packages/types/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "@netlify/types", - "version": "2.8.0", - "description": "TypeScript definitions for the Netlify platform", - "type": "module", - "engines": { - "node": "^18.14.0 || >=20" - }, - "main": "./dist/main.js", - "types": "./dist/main.d.ts", - "files": [ - "dist/**/*" - ], - "scripts": { - "build": "tsup-node", - "prepack": "npm run build", - "test": "npm run types && vitest run", - "test:dev": "vitest", - "test:ci": "npm run build && npm run test", - "dev": "tsup-node --watch", - "types": "tsc --noEmit", - "publint": "npx -y publint --strict" - }, - "keywords": [], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/netlify/primitives.git", - "directory": "packages/types" - }, - "bugs": { - "url": "https://github.com/netlify/primitives/issues" - }, - "author": "Netlify Inc.", - "devDependencies": { - "@types/node": "^18.19.110", - "tsup": "^8.0.0", - "typescript": "^5.8.3", - "vitest": "^3.0.0" - } -} diff --git a/packages/types/src/lib/context/context.ts b/packages/types/src/lib/context/context.ts deleted file mode 100644 index efa9b07..0000000 --- a/packages/types/src/lib/context/context.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Cookies } from './cookies.js' -import { Geo } from './geo.js' -import { Server } from './server.js' -import { Site } from './site.js' - -interface NextOptions { - sendConditionalRequest?: boolean -} - -export interface Context { - account: { - id: string - } - cookies: Cookies - deploy: { - context: string - id: string - published: boolean - skewProtectionToken?: string - } - geo: Geo - ip: string - json: (input: unknown) => Response - log: { - (...data: any[]): void - (message?: any, ...optionalParams: any[]): void - } - next(options?: NextOptions): Promise - - /** - * @param request `Request` to be passed down the request chain. Defaults to the original `request` object passed into the Edge Function. - */ - next(request: Request, options?: NextOptions): Promise - - params: Record - - /** - * @deprecated Use a `URL` object instead: https://ntl.fyi/edge-rewrite - */ - rewrite(url: string | URL): Promise - - requestId: string - server: Server - site: Site - url: URL - waitUntil: (promise: Promise) => void -} diff --git a/packages/types/src/lib/context/cookies.ts b/packages/types/src/lib/context/cookies.ts deleted file mode 100644 index eb6caad..0000000 --- a/packages/types/src/lib/context/cookies.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface Cookie { - /** Name of the cookie. */ - name: string - /** Value of the cookie. */ - value: string - expires?: Date | number - /** The cookie's `Max-Age` attribute, in seconds. Must be a non-negative integer. A cookie with a `maxAge` of `0` expires immediately. */ - maxAge?: number - /** The cookie's `Domain` attribute. Specifies those hosts to which the cookie will be sent. */ - domain?: string - /** The cookie's `Path` attribute. A cookie with a path will only be included in the `Cookie` request header if the requested URL matches that path. */ - path?: string - /** The cookie's `Secure` attribute. If `true`, the cookie will only be included in the `Cookie` request header if the connection uses SSL and HTTPS. */ - secure?: boolean - /** The cookie's `HTTPOnly` attribute. If `true`, the cookie cannot be accessed via JavaScript. */ - httpOnly?: boolean - /** - * Allows servers to assert that a cookie ought not to - * be sent along with cross-site requests. - */ - sameSite?: 'Strict' | 'Lax' | 'None' - /** Additional key value pairs with the form "key=value" */ - unparsed?: string[] -} - -interface DeleteCookieOptions { - domain?: string - name: string - path?: string -} - -export interface Cookies { - delete: (input: string | DeleteCookieOptions) => void - get: (key: string) => string - set: { - (cookie: Cookie): void - (name: string, value: string): void - } -} diff --git a/packages/types/src/lib/context/geo.ts b/packages/types/src/lib/context/geo.ts deleted file mode 100644 index bfb05d9..0000000 --- a/packages/types/src/lib/context/geo.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface Geo { - city?: string - country?: { - code?: string - name?: string - } - postalCode?: string - subdivision?: { - code?: string - name?: string - } - latitude?: number - longitude?: number - timezone?: string -} diff --git a/packages/types/src/lib/context/server.ts b/packages/types/src/lib/context/server.ts deleted file mode 100644 index 8f66f0a..0000000 --- a/packages/types/src/lib/context/server.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Server { - region?: string -} diff --git a/packages/types/src/lib/context/site.ts b/packages/types/src/lib/context/site.ts deleted file mode 100644 index d8e78d9..0000000 --- a/packages/types/src/lib/context/site.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Site { - id?: string - name?: string - url?: string -} diff --git a/packages/types/src/lib/environment-variables.ts b/packages/types/src/lib/environment-variables.ts deleted file mode 100644 index 8c57a47..0000000 --- a/packages/types/src/lib/environment-variables.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface EnvironmentVariables { - delete: (key: string) => void - get: (key: string) => string | undefined - has: (key: string) => boolean - set: (key: string, value: string) => void - toObject: () => Record -} diff --git a/packages/types/src/lib/events/deploy.ts b/packages/types/src/lib/events/deploy.ts deleted file mode 100644 index 5f3449e..0000000 --- a/packages/types/src/lib/events/deploy.ts +++ /dev/null @@ -1,49 +0,0 @@ -export interface DeploySite { - id: string - name: string - url: string - adminUrl: string -} - -export interface Deploy { - id: string - siteId: string - buildId: string | null - state: string - errorMessage: string | null - url: string - sslUrl: string - permalinkUrl: string - adminUrl: string - context: string - branch: string | null - commitRef: string | null - commitUrl: string | null - commitMessage: string | null - committer: string | null - title: string | null - createdAt: string - publishedAt: string | null - time: number | null - manual: boolean - framework: string | null -} - -export interface DeployEvent { - deploy: Deploy - site: DeploySite -} - -export type DeployBuildingEvent = DeployEvent -export type DeploySucceededEvent = DeployEvent -export type DeployFailedEvent = DeployEvent -export type DeployDeletedEvent = DeployEvent -export type DeployLockedEvent = DeployEvent -export type DeployUnlockedEvent = DeployEvent - -export type DeployBuildingHandler = (event: DeployBuildingEvent) => void | Promise -export type DeploySucceededHandler = (event: DeploySucceededEvent) => void | Promise -export type DeployFailedHandler = (event: DeployFailedEvent) => void | Promise -export type DeployDeletedHandler = (event: DeployDeletedEvent) => void | Promise -export type DeployLockedHandler = (event: DeployLockedEvent) => void | Promise -export type DeployUnlockedHandler = (event: DeployUnlockedEvent) => void | Promise diff --git a/packages/types/src/lib/events/identity.ts b/packages/types/src/lib/events/identity.ts deleted file mode 100644 index c302748..0000000 --- a/packages/types/src/lib/events/identity.ts +++ /dev/null @@ -1,56 +0,0 @@ -export interface User { - id: string - email?: string - confirmedAt?: string - createdAt?: string - updatedAt?: string - role?: string - provider?: string - name?: string - pictureUrl?: string - roles?: string[] - invitedAt?: string - confirmationSentAt?: string - recoverySentAt?: string - pendingEmail?: string - emailChangeSentAt?: string - lastSignInAt?: string - userMetadata?: Record - appMetadata?: Record -} - -interface BaseIdentityEvent { - user: User -} - -interface DeniableIdentityEvent extends BaseIdentityEvent { - /** - * Denies the action that triggered this event. The end user's request is - * rejected with a 401. - * - * ```ts - * if (!isAllowedEmail(event.user.email)) { - * return event.deny() - * } - * ``` - */ - deny(): undefined -} - -interface IdentityHandlerResult { - user: User -} - -export type UserLoginEvent = DeniableIdentityEvent -export type UserSignupEvent = DeniableIdentityEvent -export type UserValidateEvent = DeniableIdentityEvent -export type UserModifiedEvent = DeniableIdentityEvent -export type UserDeletedEvent = BaseIdentityEvent - -type MaybePromise = T | Promise - -export type UserLoginHandler = (event: UserLoginEvent) => MaybePromise -export type UserSignupHandler = (event: UserSignupEvent) => MaybePromise -export type UserValidateHandler = (event: UserValidateEvent) => MaybePromise -export type UserModifiedHandler = (event: UserModifiedEvent) => MaybePromise -export type UserDeletedHandler = (event: UserDeletedEvent) => MaybePromise diff --git a/packages/types/src/lib/events/index.ts b/packages/types/src/lib/events/index.ts deleted file mode 100644 index a449f0f..0000000 --- a/packages/types/src/lib/events/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -export type { - DeployEvent, - Deploy, - DeploySite, - DeployBuildingEvent, - DeploySucceededEvent, - DeployFailedEvent, - DeployDeletedEvent, - DeployLockedEvent, - DeployUnlockedEvent, - DeployBuildingHandler, - DeploySucceededHandler, - DeployFailedHandler, - DeployDeletedHandler, - DeployLockedHandler, - DeployUnlockedHandler, -} from './deploy.js' -export type { - User, - UserLoginEvent, - UserSignupEvent, - UserValidateEvent, - UserModifiedEvent, - UserDeletedEvent, - UserLoginHandler, - UserSignupHandler, - UserValidateHandler, - UserModifiedHandler, - UserDeletedHandler, -} from './identity.js' -export type { FormSubmittedEvent, FormSubmittedHandler } from './submission.js' diff --git a/packages/types/src/lib/events/submission.ts b/packages/types/src/lib/events/submission.ts deleted file mode 100644 index 70616d7..0000000 --- a/packages/types/src/lib/events/submission.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface FormSubmittedEvent { - data: Record -} - -export type FormSubmittedHandler = (event: FormSubmittedEvent) => void | Promise diff --git a/packages/types/src/lib/function-regions.ts b/packages/types/src/lib/function-regions.ts deleted file mode 100644 index f1b729e..0000000 --- a/packages/types/src/lib/function-regions.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type FunctionRegion = - | 'cmh' - | 'dub' - | 'fra' - | 'gru' - | 'iad' - | 'lhr' - | 'nrt' - | 'pdx' - | 'sfo' - | 'sin' - | 'syd' - | 'yul' diff --git a/packages/types/src/lib/globals.ts b/packages/types/src/lib/globals.ts deleted file mode 100644 index 3b0ea8b..0000000 --- a/packages/types/src/lib/globals.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Context } from './context/context.js' -import type { EnvironmentVariables } from './environment-variables.js' - -export type NetlifyGlobal = { - context: Context | null - env: EnvironmentVariables -} diff --git a/packages/types/src/main.test.ts b/packages/types/src/main.test.ts deleted file mode 100644 index 72c2acd..0000000 --- a/packages/types/src/main.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { readFile } from 'node:fs/promises' -import { resolve } from 'node:path' -import { fileURLToPath } from 'node:url' - -import { expect, expectTypeOf, test } from 'vitest' - -import type { Context, NetlifyGlobal } from './main.js' -import * as main from './main.js' - -test('Exports types', () => { - expectTypeOf().toExtend() - expectTypeOf().toExtend() -}) - -test('Does not export runtime code', () => { - expect(Object.keys(main)).toStrictEqual([]) -}) - -test('Does not have dependencies', async () => { - const packageJSONPath = resolve(fileURLToPath(import.meta.url), '../../package.json') - const packageJSON = await readFile(packageJSONPath, 'utf8') - const { dependencies = {} } = JSON.parse(packageJSON) - - expect(dependencies).toStrictEqual({}) -}) diff --git a/packages/types/src/main.ts b/packages/types/src/main.ts deleted file mode 100644 index f410158..0000000 --- a/packages/types/src/main.ts +++ /dev/null @@ -1,37 +0,0 @@ -export type { Context } from './lib/context/context.js' -export type { Cookie } from './lib/context/cookies.js' -export type { - DeployEvent, - Deploy, - DeploySite, - DeployBuildingEvent, - DeploySucceededEvent, - DeployFailedEvent, - DeployDeletedEvent, - DeployLockedEvent, - DeployUnlockedEvent, - DeployBuildingHandler, - DeploySucceededHandler, - DeployFailedHandler, - DeployDeletedHandler, - DeployLockedHandler, - DeployUnlockedHandler, -} from './lib/events/deploy.js' -export type { - User, - UserLoginEvent, - UserSignupEvent, - UserValidateEvent, - UserModifiedEvent, - UserDeletedEvent, - UserLoginHandler, - UserSignupHandler, - UserValidateHandler, - UserModifiedHandler, - UserDeletedHandler, -} from './lib/events/identity.js' -export type { FormSubmittedEvent, FormSubmittedHandler } from './lib/events/submission.js' -export type { EnvironmentVariables } from './lib/environment-variables.js' -export type { FunctionRegion } from './lib/function-regions.js' -export type { NetlifyGlobal } from './lib/globals.js' -export type { Site } from './lib/context/site.js' diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json deleted file mode 100644 index 7b592ea..0000000 --- a/packages/types/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "rootDir": "./src", - "moduleResolution": "node", - "allowJs": true, - "declaration": true, - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": ["src"] -} diff --git a/packages/types/tsup.config.ts b/packages/types/tsup.config.ts deleted file mode 100644 index c3b8320..0000000 --- a/packages/types/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { argv } from 'node:process' - -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - clean: true, - entry: ['src/main.ts'], - outDir: 'dist', - format: ['esm'], - dts: true, - splitting: false, - watch: argv.includes('--watch'), - platform: 'node', - bundle: true, - }, -]) diff --git a/packages/types/vitest.config.ts b/packages/types/vitest.config.ts deleted file mode 100644 index 4428598..0000000 --- a/packages/types/vitest.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - typecheck: { - enabled: true, - }, - }, -}) diff --git a/packages/vite-plugin-tanstack-start/tsconfig.json b/packages/vite-plugin-tanstack-start/tsconfig.json index c9505ed..8e8484a 100644 --- a/packages/vite-plugin-tanstack-start/tsconfig.json +++ b/packages/vite-plugin-tanstack-start/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2022", "module": "ESNext", - "moduleResolution": "node", + "moduleResolution": "bundler", "allowJs": true, "resolveJsonModule": true, "declaration": true, diff --git a/packages/vite-plugin/.gitignore b/packages/vite-plugin/.gitignore index de4d1f0..d00f9a9 100644 --- a/packages/vite-plugin/.gitignore +++ b/packages/vite-plugin/.gitignore @@ -1,2 +1,5 @@ dist node_modules + +# Local Netlify folder +.netlify From 8110826474ae37ab4201d27947ce530708cb9351 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 18:11:51 +0530 Subject: [PATCH 02/19] remove primitives test --- .github/workflows/test.yaml | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 004460d..0bf8f00 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -80,38 +80,3 @@ jobs: echo "This workflow run does not have access to secrets (likely a fork PR)." >> "$GITHUB_STEP_SUMMARY" echo "Live tests that deploy to Netlify were skipped." >> "$GITHUB_STEP_SUMMARY" echo "Maintainers: before merging, verify that these tests pass or aren't relevant." >> "$GITHUB_STEP_SUMMARY" - test-node18: - name: Test Node.js 18 for specific packages - runs-on: ${{ matrix.os }} - timeout-minutes: 30 - strategy: - matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] - fail-fast: false - steps: - - run: git config --global core.symlinks true - - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - name: Node.js 18.14.0 - uses: actions/setup-node@v6 - with: - node-version: 18.14.0 - cache: 'npm' - - name: Setup Deno - uses: denoland/setup-deno@v1 - with: - deno-version: 2.5.6 - - name: Setup Deno dependencies - run: deno cache https://deno.land/x/eszip@v0.55.2/eszip.ts - - name: Install dependencies - run: npm ci - - name: Build - # NOTE: These are run in the specified order, so they must be in topological order - run: >- - npm run build -w ./packages/types -w ./packages/dev-utils -w ./packages/runtime-utils -w ./packages/otel -w - ./packages/blobs -w ./packages/edge-functions -w ./packages/functions - - name: Tests - run: >- - npm run test -w ./packages/types -w ./packages/dev-utils -w ./packages/runtime-utils -w ./packages/otel -w - ./packages/blobs -w ./packages/edge-functions -w ./packages/functions From 5faa0d101e88d7135374df10f894c336d748b583 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 18:31:43 +0530 Subject: [PATCH 03/19] update deps --- package-lock.json | 29 +---------------------------- packages/nuxt-module/package.json | 2 +- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3c2505d..4dafc4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9617,16 +9617,6 @@ "node": ">=12.20" } }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/comment-parser": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", @@ -24549,7 +24539,7 @@ "@nuxt/devtools-kit": "^2.6.2", "@nuxt/eslint-config": "^1.5.2", "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^3.17.6", + "@nuxt/schema": "^4.0.0", "@nuxt/test-utils": "^3.19.2", "@types/node": "^22.16.3", "eslint": "^9.30.1", @@ -24562,23 +24552,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "packages/nuxt-module/node_modules/@nuxt/schema": { - "version": "3.21.7", - "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.21.7.tgz", - "integrity": "sha512-H35IqlFu4YHXnW0Aw24yCpRuWOJjd9iwS6u9vinsopJo8rrM1/2aKMajX3l9ifhni1XN8nqcKo622z+5ZCQM4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/shared": "^3.5.34", - "defu": "^6.1.7", - "pathe": "^2.0.3", - "pkg-types": "^2.3.1", - "std-env": "^4.1.0" - }, - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, "packages/vite-plugin": { "name": "@netlify/vite-plugin", "version": "2.12.7", diff --git a/packages/nuxt-module/package.json b/packages/nuxt-module/package.json index c38208d..32f2458 100644 --- a/packages/nuxt-module/package.json +++ b/packages/nuxt-module/package.json @@ -64,7 +64,7 @@ "@nuxt/devtools-kit": "^2.6.2", "@nuxt/eslint-config": "^1.5.2", "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^3.17.6", + "@nuxt/schema": "^4.0.0", "@nuxt/test-utils": "^3.19.2", "@types/node": "^22.16.3", "eslint": "^9.30.1", From 4925d1bb61b0a6be594de753377282dd62d1df22 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 18:38:06 +0530 Subject: [PATCH 04/19] trigger actions From ec6f810eca86bf0d4747a84b1641b62613198323 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 18:45:09 +0530 Subject: [PATCH 05/19] change repo name in actions --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 0bf8f00..d73d911 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -65,7 +65,7 @@ jobs: - name: Flag fork PR if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != - 'netlify/primitives' }} + 'netlify/framework-adapters' }} run: echo "SKIP_LIVE_TESTS=true" >> "$GITHUB_ENV" - name: Tests run: npm run test --workspaces=true From da3b525434ba161699cd0553e8bcde705ce95920 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 19:00:04 +0530 Subject: [PATCH 06/19] fix test on macos --- packages/nuxt-module/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt-module/package.json b/packages/nuxt-module/package.json index 32f2458..222be7b 100644 --- a/packages/nuxt-module/package.json +++ b/packages/nuxt-module/package.json @@ -32,7 +32,7 @@ "prepack": "npm run build", "publint": "npx -y publint --strict", "test": "exit 0", - "test:ci": "vitest run", + "test:ci": "TMPDIR=/tmp vitest run", "test:dev": "vitest", "test:types": "vue-tsc --noEmit", "test:watch": "vitest watch" From ed92f8df0df3f184cbe66c6bb9c80bb8237def7e Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 22:26:04 +0530 Subject: [PATCH 07/19] skip liniting on node 20 --- .github/workflows/nuxt-module.yaml | 3 + package-lock.json | 712 ++++++++++++++++++----------- packages/nuxt-module/package.json | 2 +- 3 files changed, 454 insertions(+), 263 deletions(-) diff --git a/.github/workflows/nuxt-module.yaml b/.github/workflows/nuxt-module.yaml index 318910e..d012d16 100644 --- a/.github/workflows/nuxt-module.yaml +++ b/.github/workflows/nuxt-module.yaml @@ -46,8 +46,11 @@ jobs: - name: Build run: npm run build --workspaces - name: Lint + if: matrix.node-version != '20.19.0' run: npm run lint -w ./packages/nuxt-module - name: Typecheck run: npm run test:types -w ./packages/nuxt-module - name: Tests run: npm run test:ci -w ./packages/nuxt-module + env: + TMPDIR: /tmp diff --git a/package-lock.json b/package-lock.json index 4dafc4d..0f3dae4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1600,9 +1600,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1619,9 +1616,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1638,9 +1632,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1657,9 +1648,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1676,9 +1664,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1695,9 +1680,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1714,9 +1696,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1733,9 +1712,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1752,9 +1728,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1777,9 +1750,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1802,9 +1772,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1827,9 +1794,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1852,9 +1816,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1877,9 +1838,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1902,9 +1860,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1927,9 +1882,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -4709,9 +4661,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4729,9 +4678,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4749,9 +4695,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4769,9 +4712,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4789,9 +4729,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4809,9 +4746,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4829,9 +4763,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4849,9 +4780,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5075,9 +5003,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5095,9 +5020,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5115,9 +5037,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5135,9 +5054,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5155,9 +5071,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5175,9 +5088,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5195,9 +5105,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5215,9 +5122,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5451,9 +5355,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5471,9 +5372,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5491,9 +5389,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5511,9 +5406,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5531,9 +5423,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5551,9 +5440,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5571,9 +5457,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5591,9 +5474,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5819,9 +5699,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5842,9 +5719,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5865,9 +5739,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5888,9 +5759,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5911,9 +5779,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5934,9 +5799,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6185,9 +6047,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6205,9 +6064,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6225,9 +6081,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6245,9 +6098,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6265,9 +6115,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6285,9 +6132,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6604,11 +6448,13 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.61.1", @@ -6617,11 +6463,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.61.1", @@ -6630,11 +6478,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.61.1", @@ -6643,11 +6493,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.61.1", @@ -6656,11 +6508,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.61.1", @@ -6669,11 +6523,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.61.1", @@ -6682,14 +6538,13 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.61.1", @@ -6698,14 +6553,13 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.61.1", @@ -6714,14 +6568,13 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.61.1", @@ -6730,14 +6583,13 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.61.1", @@ -6746,14 +6598,13 @@ "cpu": [ "loong64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.61.1", @@ -6762,14 +6613,13 @@ "cpu": [ "loong64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.61.1", @@ -6778,14 +6628,13 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.61.1", @@ -6794,14 +6643,13 @@ "cpu": [ "ppc64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.61.1", @@ -6810,14 +6658,13 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.61.1", @@ -6826,14 +6673,13 @@ "cpu": [ "riscv64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.61.1", @@ -6842,14 +6688,13 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.61.1", @@ -6858,14 +6703,13 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.61.1", @@ -6874,14 +6718,13 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.61.1", @@ -6890,11 +6733,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.61.1", @@ -6903,11 +6748,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.61.1", @@ -6916,11 +6763,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.61.1", @@ -6929,11 +6778,13 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.61.1", @@ -6942,11 +6793,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.61.1", @@ -6955,11 +6808,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@simple-git/args-pathspec": { "version": "1.0.3", @@ -7528,9 +7383,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7545,9 +7397,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7562,9 +7411,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7579,9 +7425,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7596,9 +7439,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7613,9 +7453,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7630,9 +7467,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7647,9 +7481,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7664,9 +7495,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7681,9 +7509,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -12388,6 +12213,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -14332,6 +14158,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14353,6 +14180,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14374,6 +14202,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14395,6 +14224,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14416,6 +14246,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14432,14 +14263,12 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14456,14 +14285,12 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14480,14 +14307,12 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14504,14 +14329,12 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14533,6 +14356,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14554,6 +14378,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -23025,6 +22850,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -23042,6 +22868,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -23059,6 +22886,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -23076,6 +22904,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -23093,6 +22922,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -23110,6 +22940,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -23127,6 +22958,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23144,6 +22976,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23161,6 +22994,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23178,6 +23012,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23195,6 +23030,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23212,6 +23048,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23229,6 +23066,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23246,6 +23084,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23263,6 +23102,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23280,6 +23120,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23297,6 +23138,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23314,6 +23156,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23331,6 +23174,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23348,6 +23192,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23365,6 +23210,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23382,6 +23228,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -23399,6 +23246,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -23416,6 +23264,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -23433,6 +23282,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -23450,6 +23300,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -23534,6 +23385,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -24552,6 +24404,342 @@ "node": "^20.19.0 || >=22.12.0" } }, + "packages/nuxt-module/node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/nuxt-module/node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/nuxt-module/node_modules/@eslint/js": { + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", + "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "packages/nuxt-module/node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/nuxt-module/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/nuxt-module/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/nuxt-module/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "packages/nuxt-module/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "packages/nuxt-module/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/nuxt-module/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "packages/nuxt-module/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/nuxt-module/node_modules/eslint": { + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", + "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.35.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "packages/nuxt-module/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/nuxt-module/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "packages/nuxt-module/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "packages/nuxt-module/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/nuxt-module/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "packages/nuxt-module/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/nuxt-module/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/nuxt-module/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "packages/nuxt-module/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/nuxt-module/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/vite-plugin": { "name": "@netlify/vite-plugin", "version": "2.12.7", diff --git a/packages/nuxt-module/package.json b/packages/nuxt-module/package.json index 222be7b..32f2458 100644 --- a/packages/nuxt-module/package.json +++ b/packages/nuxt-module/package.json @@ -32,7 +32,7 @@ "prepack": "npm run build", "publint": "npx -y publint --strict", "test": "exit 0", - "test:ci": "TMPDIR=/tmp vitest run", + "test:ci": "vitest run", "test:dev": "vitest", "test:types": "vue-tsc --noEmit", "test:watch": "vitest watch" From 77aad6e6ab1f0b67edaad06ad119edecdcd09892 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 22:43:49 +0530 Subject: [PATCH 08/19] drop node 20.6 test as we no longer have primitives --- .github/workflows/test.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d73d911..eec0662 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,11 +23,8 @@ jobs: node-install-version: ['24.15.0'] include: - os: ubuntu-latest - # Many of our dependencies require 20.6.0, so we use the same minimum. - # But there is a blocking bug in 20.6.0, fixed in 20.6.1: - # https://github.com/nuxt/nuxt/issues/23020#issuecomment-1719828889 - node-version: '20.6.1' - node-install-version: '20.6.1' + node-version: '20.12.0' + node-install-version: '20.12.0' fail-fast: false steps: # Increasing the maximum number of open files. See: From 3445e2b184550f0e625a0d3a82053306cdb29860 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 22:57:52 +0530 Subject: [PATCH 09/19] update lockfile --- .github/workflows/nuxt-module.yaml | 4 +- .github/workflows/test.yaml | 2 + package-lock.json | 734 +++++++++++------------------ 3 files changed, 283 insertions(+), 457 deletions(-) diff --git a/.github/workflows/nuxt-module.yaml b/.github/workflows/nuxt-module.yaml index d012d16..513bed9 100644 --- a/.github/workflows/nuxt-module.yaml +++ b/.github/workflows/nuxt-module.yaml @@ -46,6 +46,8 @@ jobs: - name: Build run: npm run build --workspaces - name: Lint + # skip linting on node 20 due to eslint issues + # specifically, TypeError: Object.groupBy is not a function if: matrix.node-version != '20.19.0' run: npm run lint -w ./packages/nuxt-module - name: Typecheck @@ -53,4 +55,4 @@ jobs: - name: Tests run: npm run test:ci -w ./packages/nuxt-module env: - TMPDIR: /tmp + TMPDIR: ${{ runner.os == 'Windows' && 'C:\\Temp' || '/tmp' }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index eec0662..1fa7ba7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,6 +23,8 @@ jobs: node-install-version: ['24.15.0'] include: - os: ubuntu-latest + # min node-version required for styleText import from + # node:util in some dependency node-version: '20.12.0' node-install-version: '20.12.0' fail-fast: false diff --git a/package-lock.json b/package-lock.json index 0f3dae4..2c101ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1600,6 +1600,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1616,6 +1619,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1632,6 +1638,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1648,6 +1657,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1664,6 +1676,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1680,6 +1695,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1696,6 +1714,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1712,6 +1733,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1728,6 +1752,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1750,6 +1777,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1772,6 +1802,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1794,6 +1827,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1816,6 +1852,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1838,6 +1877,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1860,6 +1902,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1882,6 +1927,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -4661,6 +4709,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4678,6 +4729,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4695,6 +4749,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4712,6 +4769,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4729,6 +4789,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4746,6 +4809,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4763,6 +4829,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4780,6 +4849,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5003,6 +5075,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5020,6 +5095,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5037,6 +5115,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5054,6 +5135,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5071,6 +5155,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5088,6 +5175,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5105,6 +5195,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5122,6 +5215,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5355,6 +5451,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5372,6 +5471,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5389,6 +5491,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5406,6 +5511,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5423,6 +5531,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5440,6 +5551,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5457,6 +5571,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5474,6 +5591,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5699,6 +5819,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5719,6 +5842,9 @@ "cpu": [ "arm" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5739,6 +5865,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5759,6 +5888,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5779,6 +5911,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5799,6 +5934,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6047,6 +6185,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6064,6 +6205,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6081,6 +6225,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6098,6 +6245,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6115,6 +6265,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6132,6 +6285,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6448,13 +6604,11 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.61.1", @@ -6463,13 +6617,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.61.1", @@ -6478,13 +6630,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.61.1", @@ -6493,13 +6643,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.61.1", @@ -6508,13 +6656,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.61.1", @@ -6523,13 +6669,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.61.1", @@ -6538,13 +6682,14 @@ "cpu": [ "arm" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.61.1", @@ -6553,13 +6698,14 @@ "cpu": [ "arm" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.61.1", @@ -6568,13 +6714,14 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.61.1", @@ -6583,13 +6730,14 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.61.1", @@ -6598,13 +6746,14 @@ "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.61.1", @@ -6613,13 +6762,14 @@ "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.61.1", @@ -6628,13 +6778,14 @@ "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.61.1", @@ -6643,13 +6794,14 @@ "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.61.1", @@ -6658,13 +6810,14 @@ "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.61.1", @@ -6673,13 +6826,14 @@ "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.61.1", @@ -6688,13 +6842,14 @@ "cpu": [ "s390x" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.61.1", @@ -6703,13 +6858,14 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.61.1", @@ -6718,13 +6874,14 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.61.1", @@ -6733,13 +6890,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.61.1", @@ -6748,13 +6903,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.61.1", @@ -6763,13 +6916,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.61.1", @@ -6778,13 +6929,11 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.61.1", @@ -6793,13 +6942,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.61.1", @@ -6808,13 +6955,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@simple-git/args-pathspec": { "version": "1.0.3", @@ -7383,6 +7528,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7397,6 +7545,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7411,6 +7562,9 @@ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7425,6 +7579,9 @@ "loong64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7439,6 +7596,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7453,6 +7613,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7467,6 +7630,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7481,6 +7647,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7495,6 +7664,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7509,6 +7681,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -8698,9 +8873,9 @@ } }, "node_modules/bare-url": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.4.tgz", - "integrity": "sha512-zbQJi2YQUe3SrX19TItQ8DoPj9E1i5rrdE9iHV4PhUif1GodNRSe85lavVGbmU7P4M8579EQi4akGFuhCATWaQ==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz", + "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==", "license": "Apache-2.0", "dependencies": { "bare-path": "^3.0.0" @@ -9442,6 +9617,16 @@ "node": ">=12.20" } }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "extraneous": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/comment-parser": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", @@ -12213,7 +12398,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -14158,7 +14342,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14180,7 +14363,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14202,7 +14384,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14224,7 +14405,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14246,7 +14426,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14263,12 +14442,14 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14285,12 +14466,14 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14307,12 +14490,14 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14329,12 +14514,14 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14356,7 +14543,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14378,7 +14564,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -18684,9 +18869,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", + "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -22850,7 +23035,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -22868,7 +23052,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -22886,7 +23069,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -22904,7 +23086,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -22922,7 +23103,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -22940,7 +23120,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -22958,7 +23137,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -22976,7 +23154,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -22994,7 +23171,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23012,7 +23188,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23030,7 +23205,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23048,7 +23222,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23066,7 +23239,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23084,7 +23256,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23102,7 +23273,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23120,7 +23290,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23138,7 +23307,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23156,7 +23324,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23174,7 +23341,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23192,7 +23358,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23210,7 +23375,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23228,7 +23392,6 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": ">=18" } @@ -23246,7 +23409,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -23264,7 +23426,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -23282,7 +23443,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -23300,7 +23460,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -23385,7 +23544,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -24404,342 +24562,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "packages/nuxt-module/node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "packages/nuxt-module/node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "packages/nuxt-module/node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "packages/nuxt-module/node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.15.2", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "packages/nuxt-module/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "packages/nuxt-module/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "packages/nuxt-module/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "packages/nuxt-module/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "packages/nuxt-module/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "packages/nuxt-module/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "packages/nuxt-module/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/nuxt-module/node_modules/eslint": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", - "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.35.0", - "@eslint/plugin-kit": "^0.3.5", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "packages/nuxt-module/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/nuxt-module/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "packages/nuxt-module/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "packages/nuxt-module/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/nuxt-module/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "packages/nuxt-module/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/nuxt-module/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/nuxt-module/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/nuxt-module/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/nuxt-module/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/vite-plugin": { "name": "@netlify/vite-plugin", "version": "2.12.7", From c1c994287df90189ec653a9c4799e7b40fe04fc0 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 23:22:34 +0530 Subject: [PATCH 10/19] rollback vitest --- package-lock.json | 237 ++++++++++++++++++++++++++++-- packages/vite-plugin/package.json | 2 +- 2 files changed, 227 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c101ac..ed7d86a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9617,16 +9617,6 @@ "node": ">=12.20" } }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/comment-parser": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", @@ -24576,7 +24566,7 @@ "playwright": "^1.60.0", "tsup": "^8.0.0", "vite": "^6.3.6", - "vitest": "^3.0.0" + "vitest": "3.2.4" }, "engines": { "node": "^20.6.1 || >=22" @@ -25109,6 +25099,121 @@ "undici-types": "~6.21.0" } }, + "packages/vite-plugin/node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/vite-plugin/node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "packages/vite-plugin/node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/vite-plugin/node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/vite-plugin/node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/vite-plugin/node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/vite-plugin/node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "packages/vite-plugin/node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -25166,6 +25271,20 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "packages/vite-plugin/node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "packages/vite-plugin/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "packages/vite-plugin/node_modules/vite": { "version": "6.4.3", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", @@ -25240,6 +25359,102 @@ "optional": true } } + }, + "packages/vite-plugin/node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/vite-plugin/node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } } } } diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json index 7a17443..2970ca7 100644 --- a/packages/vite-plugin/package.json +++ b/packages/vite-plugin/package.json @@ -41,7 +41,7 @@ "playwright": "^1.60.0", "tsup": "^8.0.0", "vite": "^6.3.6", - "vitest": "^3.0.0" + "vitest": "3.2.4" }, "dependencies": { "@netlify/dev": "4.18.7", From eaac818dc12e3b33aaba9b32ad74563f46c1467c Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 12:18:32 -0600 Subject: [PATCH 11/19] update lockfile on ubuntu --- package-lock.json | 376 ++++++++++++++-------------------------------- 1 file changed, 114 insertions(+), 262 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed7d86a..4e6cfad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1600,9 +1600,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1619,9 +1616,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1638,9 +1632,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1657,9 +1648,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1676,9 +1664,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1695,9 +1680,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1714,9 +1696,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1733,9 +1712,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1752,9 +1728,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1777,9 +1750,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1802,9 +1772,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1827,9 +1794,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1852,9 +1816,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1877,9 +1838,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1902,9 +1860,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1927,9 +1882,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -4709,9 +4661,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4729,9 +4678,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4749,9 +4695,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4769,9 +4712,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4789,9 +4729,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4809,9 +4746,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4829,9 +4763,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4849,9 +4780,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5075,9 +5003,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5095,9 +5020,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5115,9 +5037,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5135,9 +5054,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5155,9 +5071,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5175,9 +5088,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5195,9 +5105,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5215,9 +5122,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5451,9 +5355,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5471,9 +5372,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5491,9 +5389,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5511,9 +5406,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5531,9 +5423,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5551,9 +5440,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5571,9 +5457,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5591,9 +5474,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5819,9 +5699,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5842,9 +5719,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5865,9 +5739,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5888,9 +5759,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5911,9 +5779,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5934,9 +5799,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6185,9 +6047,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6205,9 +6064,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6225,9 +6081,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6245,9 +6098,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6265,9 +6115,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6285,9 +6132,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6604,11 +6448,13 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.61.1", @@ -6617,11 +6463,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.61.1", @@ -6630,11 +6478,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.61.1", @@ -6643,11 +6493,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.61.1", @@ -6656,11 +6508,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.61.1", @@ -6669,11 +6523,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.61.1", @@ -6682,14 +6538,13 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.61.1", @@ -6698,14 +6553,13 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.61.1", @@ -6714,14 +6568,13 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.61.1", @@ -6730,14 +6583,13 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.61.1", @@ -6746,14 +6598,13 @@ "cpu": [ "loong64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.61.1", @@ -6762,14 +6613,13 @@ "cpu": [ "loong64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.61.1", @@ -6778,14 +6628,13 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.61.1", @@ -6794,14 +6643,13 @@ "cpu": [ "ppc64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.61.1", @@ -6810,14 +6658,13 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.61.1", @@ -6826,14 +6673,13 @@ "cpu": [ "riscv64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.61.1", @@ -6842,14 +6688,13 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.61.1", @@ -6858,14 +6703,13 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.61.1", @@ -6874,14 +6718,13 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.61.1", @@ -6890,11 +6733,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.61.1", @@ -6903,11 +6748,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.61.1", @@ -6916,11 +6763,13 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.61.1", @@ -6929,11 +6778,13 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.61.1", @@ -6942,11 +6793,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.61.1", @@ -6955,11 +6808,13 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@simple-git/args-pathspec": { "version": "1.0.3", @@ -7528,9 +7383,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7545,9 +7397,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7562,9 +7411,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7579,9 +7425,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7596,9 +7439,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7613,9 +7453,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7630,9 +7467,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7647,9 +7481,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7664,9 +7495,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7681,9 +7509,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -12388,6 +12213,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -14332,6 +14158,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14353,6 +14180,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14374,6 +14202,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14395,6 +14224,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14416,6 +14246,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14432,14 +14263,12 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14456,14 +14285,12 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14480,14 +14307,12 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14504,14 +14329,12 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14533,6 +14356,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14554,6 +14378,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -23025,6 +22850,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -23042,6 +22868,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -23059,6 +22886,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -23076,6 +22904,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -23093,6 +22922,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -23110,6 +22940,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -23127,6 +22958,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23144,6 +22976,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23161,6 +22994,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23178,6 +23012,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23195,6 +23030,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23212,6 +23048,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23229,6 +23066,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23246,6 +23084,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23263,6 +23102,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23280,6 +23120,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23297,6 +23138,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -23314,6 +23156,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23331,6 +23174,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23348,6 +23192,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23365,6 +23210,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -23382,6 +23228,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -23399,6 +23246,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -23416,6 +23264,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -23433,6 +23282,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -23450,6 +23300,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -23534,6 +23385,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } From e79df80e94c63a51c150974d9b1b1c3047846ea3 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 4 Jun 2026 23:57:43 +0530 Subject: [PATCH 12/19] switch to npm i --- .github/workflows/test.yaml | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1fa7ba7..0becf9b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -54,7 +54,12 @@ jobs: - name: Setup Deno dependencies run: deno cache https://deno.land/x/eszip@v0.55.2/eszip.ts - name: Install dependencies - run: npm ci + # npm ci has a known bug where it skips optional native bindings even when present in the + # lockfile (https://github.com/npm/cli/issues/4828). Use npm install on Node 20 Ubuntu to + # work around this; the lockfile still pins all versions so reproducibility is maintained. + # the lockfile was generated on ubuntu with node 20.12 when this change was made, + # yet the issue persisted so this was the only way ahead. + run: ${{ matrix.node-version == '20.12.0' && 'npm install' || 'npm ci' }} - name: Install playwright browsers run: npx playwright install --with-deps chromium - name: Build diff --git a/package.json b/package.json index 04b36b7..a3e5ea0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "netlify-primitives-monorepo", + "name": "netlify-framework-adapters-monorepo", "private": true, "type": "module", "workspaces": [ From 9f70e06fa536936172bb6d27f604390ec6dc0dfa Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Fri, 5 Jun 2026 00:02:24 +0530 Subject: [PATCH 13/19] update node for ubuntu test --- .github/workflows/test.yaml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 0becf9b..a6a4266 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,10 +23,9 @@ jobs: node-install-version: ['24.15.0'] include: - os: ubuntu-latest - # min node-version required for styleText import from - # node:util in some dependency - node-version: '20.12.0' - node-install-version: '20.12.0' + # min node-version required by optional native bindings (e.g. @oxc-parser) + node-version: '20.19.0' + node-install-version: '20.19.0' fail-fast: false steps: # Increasing the maximum number of open files. See: @@ -54,12 +53,7 @@ jobs: - name: Setup Deno dependencies run: deno cache https://deno.land/x/eszip@v0.55.2/eszip.ts - name: Install dependencies - # npm ci has a known bug where it skips optional native bindings even when present in the - # lockfile (https://github.com/npm/cli/issues/4828). Use npm install on Node 20 Ubuntu to - # work around this; the lockfile still pins all versions so reproducibility is maintained. - # the lockfile was generated on ubuntu with node 20.12 when this change was made, - # yet the issue persisted so this was the only way ahead. - run: ${{ matrix.node-version == '20.12.0' && 'npm install' || 'npm ci' }} + run: npm ci - name: Install playwright browsers run: npx playwright install --with-deps chromium - name: Build From 2deb5507e5423c859eaabef1c1fd8d548047d688 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Fri, 5 Jun 2026 00:15:30 +0530 Subject: [PATCH 14/19] remove extra packages from readme --- README.md | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/README.md b/README.md index 0ccbb06..4390172 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Netlify Primitives -Implementation of different Netlify platform primitives. Includes both developer-facing utilities as well as the logic -required for the local emulation of each primitive to aid local development workflows. +Implementation of different Netlify framework adapters. ## Installation @@ -29,21 +28,6 @@ npm run dev | Name | Description | Version | | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| 🤖 [@netlify/ai](packages/ai) | TypeScript utilities for interacting with Netlify AI features | [![npm version](https://img.shields.io/npm/v/@netlify/ai.svg)](https://www.npmjs.com/package/@netlify/ai) | -| 🔀 [@netlify/aws-lambda-compat](packages/aws-lambda-compat) | AWS Lambda compatibility wrapper for Netlify Functions | [![npm version](https://img.shields.io/npm/v/@netlify/aws-lambda-compat.svg)](https://www.npmjs.com/package/@netlify/aws-lambda-compat) | -| 🗄️ [@netlify/blobs](packages/blobs) | TypeScript client for Netlify Blobs | [![npm version](https://img.shields.io/npm/v/@netlify/blobs.svg)](https://www.npmjs.com/package/@netlify/blobs) | -| 💾 [@netlify/cache](packages/cache) | TypeScript utilities for interacting with the Netlify cache | [![npm version](https://img.shields.io/npm/v/@netlify/cache.svg)](https://www.npmjs.com/package/@netlify/cache) | -| 🛠️ [@netlify/dev](packages/dev) | Emulation of the Netlify environment for local development | [![npm version](https://img.shields.io/npm/v/@netlify/dev.svg)](https://www.npmjs.com/package/@netlify/dev) | -| 🔧 [@netlify/dev-utils](packages/dev-utils) | TypeScript utilities for the local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/dev-utils.svg)](https://www.npmjs.com/package/@netlify/dev-utils) | -| ⚡ [@netlify/functions](packages/functions) | TypeScript utilities for interacting with Netlify Functions | [![npm version](https://img.shields.io/npm/v/@netlify/functions.svg)](https://www.npmjs.com/package/@netlify/functions) | -| 📋 [@netlify/headers](packages/headers) | TypeScript implementation of Netlify's headers engine | [![npm version](https://img.shields.io/npm/v/@netlify/headers.svg)](https://www.npmjs.com/package/@netlify/headers) | -| 🖼️ [@netlify/images](packages/images) | TypeScript utilities for interacting with Netlify Image CDN | [![npm version](https://img.shields.io/npm/v/@netlify/images.svg)](https://www.npmjs.com/package/@netlify/images) | | 🚀 [@netlify/nuxt](packages/nuxt-module) | Nuxt module with a local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/nuxt.svg)](https://www.npmjs.com/package/@netlify/nuxt) | -| 🔍 [@netlify/otel](packages/otel) | TypeScript utilities to interact with Netlify's OpenTelemetry | [![npm version](https://img.shields.io/npm/v/@netlify/otel.svg)](https://www.npmjs.com/package/@netlify/otel) | -| 🔄 [@netlify/redirects](packages/redirects) | TypeScript implementation of Netlify's rewrites and redirects engine | [![npm version](https://img.shields.io/npm/v/@netlify/redirects.svg)](https://www.npmjs.com/package/@netlify/redirects) | -| 🏛️ [@netlify/runtime](packages/runtime) | Netlify compute runtime | [![npm version](https://img.shields.io/npm/v/@netlify/runtime.svg)](https://www.npmjs.com/package/@netlify/runtime) | -| 🔨 [@netlify/runtime-utils](packages/runtime-utils) | Cross-environment utilities for the Netlify runtime | [![npm version](https://img.shields.io/npm/v/@netlify/runtime-utils.svg)](https://www.npmjs.com/package/@netlify/runtime-utils) | -| 📁 [@netlify/static](packages/static) | TypeScript implementation of Netlify's static file serving logic | [![npm version](https://img.shields.io/npm/v/@netlify/static.svg)](https://www.npmjs.com/package/@netlify/static) | -| 🔢 [@netlify/types](packages/types) | TypeScript types for Netlify platform primitives | [![npm version](https://img.shields.io/npm/v/@netlify/types.svg)](https://www.npmjs.com/package/@netlify/types) | | 🔌 [@netlify/vite-plugin](packages/vite-plugin) | Vite plugin with a local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/vite-plugin.svg)](https://www.npmjs.com/package/@netlify/vite-plugin) | | 🔌 [@netlify/vite-plugin-tanstack-start](packages/vite-plugin-tanstack-start) | Vite plugin for TanStack Start on Netlify | [![npm version](https://img.shields.io/npm/v/@netlify/vite-plugin.svg)](https://www.npmjs.com/package/@netlify/vite-plugin-tanstack-start) | From 5eac62dd46ef53d68571f37afae669306ebc8840 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Fri, 5 Jun 2026 00:17:10 +0530 Subject: [PATCH 15/19] run prettier --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4390172..46c0389 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ npm run dev ## Packages -| Name | Description | Version | -| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| 🚀 [@netlify/nuxt](packages/nuxt-module) | Nuxt module with a local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/nuxt.svg)](https://www.npmjs.com/package/@netlify/nuxt) | -| 🔌 [@netlify/vite-plugin](packages/vite-plugin) | Vite plugin with a local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/vite-plugin.svg)](https://www.npmjs.com/package/@netlify/vite-plugin) | -| 🔌 [@netlify/vite-plugin-tanstack-start](packages/vite-plugin-tanstack-start) | Vite plugin for TanStack Start on Netlify | [![npm version](https://img.shields.io/npm/v/@netlify/vite-plugin.svg)](https://www.npmjs.com/package/@netlify/vite-plugin-tanstack-start) | +| Name | Description | Version | +| ----------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| 🚀 [@netlify/nuxt](packages/nuxt-module) | Nuxt module with a local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/nuxt.svg)](https://www.npmjs.com/package/@netlify/nuxt) | +| 🔌 [@netlify/vite-plugin](packages/vite-plugin) | Vite plugin with a local emulation of the Netlify environment | [![npm version](https://img.shields.io/npm/v/@netlify/vite-plugin.svg)](https://www.npmjs.com/package/@netlify/vite-plugin) | +| 🔌 [@netlify/vite-plugin-tanstack-start](packages/vite-plugin-tanstack-start) | Vite plugin for TanStack Start on Netlify | [![npm version](https://img.shields.io/npm/v/@netlify/vite-plugin.svg)](https://www.npmjs.com/package/@netlify/vite-plugin-tanstack-start) | From 1ea14751557a16758860d41db1f29ba55c94bad8 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Fri, 5 Jun 2026 17:48:23 +0530 Subject: [PATCH 16/19] remove extra publishing from release-please --- .github/workflows/release-please.yaml | 224 -------------------------- 1 file changed, 224 deletions(-) diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml index 73527f8..7b4ab3b 100644 --- a/.github/workflows/release-please.yaml +++ b/.github/workflows/release-please.yaml @@ -58,149 +58,6 @@ jobs: run: npm run build --workspaces=true # Publishing packages in topological order, as defined in `package.json`. - - if: ${{ steps.release.outputs['packages/types--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/types/ --provenance --access=public || true - else - npm publish packages/types/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/aws-lambda-compat--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/aws-lambda-compat/ --provenance --access=public || true - else - npm publish packages/aws-lambda-compat/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/dev-utils--release_created'] || github.event_name == 'workflow_dispatch' - }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/dev-utils/ --provenance --access=public || true - else - npm publish packages/dev-utils/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/runtime-utils--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/runtime-utils/ --provenance --access=public || true - else - npm publish packages/runtime-utils/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/otel--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/otel/ --provenance --access=public || true - else - npm publish packages/otel/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/blobs--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/blobs/ --provenance --access=public || true - else - npm publish packages/blobs/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/cache--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/cache/ --provenance --access=public || true - else - npm publish packages/cache/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/edge-functions/prod--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/edge-functions/prod/ --provenance --access=public || true - else - npm publish packages/edge-functions/prod/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/edge-functions/dev--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/edge-functions/dev/ --provenance --access=public || true - else - npm publish packages/edge-functions/dev/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/functions/prod--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/functions/prod/ --provenance --access=public || true - else - npm publish packages/functions/prod/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/functions/dev--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/functions/dev/ --provenance --access=public || true - else - npm publish packages/functions/dev/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/headers--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/headers/ --provenance --access=public || true - else - npm publish packages/headers/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/identity/prod--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/identity/prod/ --provenance --access=public || true - else - npm publish packages/identity/prod/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/images--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/images/ --provenance --access=public || true - else - npm publish packages/images/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - if: ${{ steps.release.outputs['packages/nuxt-module--release_created'] || github.event_name == 'workflow_dispatch' }} @@ -212,45 +69,6 @@ jobs: fi env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/redirects--release_created'] || github.event_name == 'workflow_dispatch' - }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/redirects/ --provenance --access=public || true - else - npm publish packages/redirects/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/runtime--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/runtime/ --provenance --access=public || true - else - npm publish packages/runtime/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/static--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/static/ --provenance --access=public || true - else - npm publish packages/static/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/dev--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/dev/ --provenance --access=public || true - else - npm publish packages/dev/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - if: ${{ steps.release.outputs['packages/vite-plugin--release_created'] || github.event_name == 'workflow_dispatch' }} @@ -273,45 +91,3 @@ jobs: fi env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: ${{ steps.release.outputs['packages/ai--release_created'] || github.event_name == 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/ai/ --provenance --access=public || true - else - npm publish packages/ai/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/database/prod--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/database/prod/ --provenance --access=public || true - else - npm publish packages/database/prod/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/database/proxy--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/database/proxy/ --provenance --access=public || true - else - npm publish packages/database/proxy/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - if: - ${{ steps.release.outputs['packages/database/dev--release_created'] || github.event_name == - 'workflow_dispatch' }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - npm publish packages/database/dev/ --provenance --access=public || true - else - npm publish packages/database/dev/ --provenance --access=public - fi - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} From 28799bb7031ea5b0b6f9aadd3472367c0d151080 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Thu, 11 Jun 2026 23:33:14 +0530 Subject: [PATCH 17/19] reviewed changes --- .release-please-manifest.json | 21 - README.md | 2 +- eslint_temporary_suppressions.js | 737 --------- package-lock.json | 1471 +++++++++-------- packages/nuxt-module/package.json | 6 +- .../vite-plugin-tanstack-start/package.json | 4 +- packages/vite-plugin/package.json | 4 +- release-please-config.json | 33 - 8 files changed, 807 insertions(+), 1471 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 09b13c9..e013c73 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,26 +1,5 @@ { - "packages/aws-lambda-compat": "1.0.2", - "packages/ai": "0.4.1", - "packages/blobs": "10.7.9", - "packages/cache": "3.4.8", - "packages/database/dev": "0.10.1", - "packages/database/prod": "1.0.0", - "packages/database/proxy": "0.1.5", - "packages/dev": "4.18.7", - "packages/dev-utils": "4.4.6", - "packages/edge-functions/dev": "1.0.20", - "packages/edge-functions/prod": "3.0.8", - "packages/functions/prod": "5.3.0", - "packages/functions/dev": "1.3.0", - "packages/headers": "2.1.11", - "packages/images": "1.3.10", - "packages/identity/prod": "1.2.0", "packages/nuxt-module": "0.3.7", - "packages/otel": "6.0.3", - "packages/redirects": "3.1.13", - "packages/runtime": "4.1.25", - "packages/runtime-utils": "2.3.0", - "packages/static": "3.1.10", "packages/types": "2.8.0", "packages/vite-plugin": "2.12.7", "packages/vite-plugin-tanstack-start": "1.3.15" diff --git a/README.md b/README.md index 46c0389..64bfc4e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Netlify Primitives +# Netlify Framework Adapters Implementation of different Netlify framework adapters. diff --git a/eslint_temporary_suppressions.js b/eslint_temporary_suppressions.js index ad24f91..8357cd1 100644 --- a/eslint_temporary_suppressions.js +++ b/eslint_temporary_suppressions.js @@ -8,745 +8,8 @@ /** @type { import("eslint").Linter.Config[] } */ export default [ - /* Global rule suppressions */ - - { - ignores: ['**/*.test.?(c|m)[jt]s?(x)', '**/test/*', '**/tsup.config.ts'], - rules: { - 'n/no-unsupported-features/node-builtins': [ - 'error', - { - ignores: [ - // The Fetch API was technically marked stable in node 21, but for all intents and purposes - // it's been stable since 18. - 'FormData', - 'Headers', - 'ReadableStream', - 'Response', - 'Request', - 'fetch', - - 'Blob', - 'fs/promises.cp', - 'stream.Readable.toWeb', - ], - }, - ], - }, - }, - /* Per-file rule suppressions */ - { - files: ['packages/blobs/src/client.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-enum-comparison': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - }, - }, - { - files: ['packages/blobs/src/environment.ts'], - rules: { - '@typescript-eslint/prefer-nullish-coalescing': 'off', - }, - }, - { - files: ['packages/blobs/src/main.test.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-floating-promises': 'off', - 'vitest/valid-expect': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/non-nullable-type-assertion-style': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/blobs/src/metadata.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - }, - }, - { - files: ['packages/blobs/src/retry.ts'], - rules: { - '@typescript-eslint/return-await': 'off', - }, - }, - { - files: ['packages/blobs/src/server.test.ts'], - rules: { - '@typescript-eslint/restrict-template-expressions': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - }, - }, - { - files: ['packages/blobs/src/server.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/no-unsafe-enum-comparison': 'off', - '@typescript-eslint/non-nullable-type-assertion-style': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - }, - }, - { - files: ['packages/blobs/src/store.ts'], - rules: { - '@typescript-eslint/unified-signatures': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - '@typescript-eslint/unbound-method': 'off', - }, - }, - { - files: ['packages/blobs/src/store_factory.ts'], - rules: { - '@typescript-eslint/unified-signatures': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/blobs/src/util.ts'], - rules: { - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/blobs/test/util.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/cache/src/bootstrap/cache.test.ts'], - rules: { - '@typescript-eslint/non-nullable-type-assertion-style': 'off', - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - }, - }, - { - files: ['packages/cache/src/bootstrap/cache.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/cache/src/bootstrap/environment.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/cache/src/cache-headers/cache-headers.test.ts'], - rules: { - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/cache/src/cache-headers/cache-headers.ts'], - rules: { - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/cache/src/cache-headers/validation.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - }, - }, - { - files: ['packages/cache/src/cache-status/cache-status.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/prefer-reduce-type-parameter': 'off', - '@typescript-eslint/unified-signatures': 'off', - }, - }, - { - files: ['packages/cache/src/fetchwithcache.test.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-floating-promises': 'off', - 'vitest/valid-expect': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - }, - }, - { - files: ['packages/cache/src/fetchwithcache.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/unified-signatures': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/cache/src/polyfill.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/cache/src/test/util.ts'], - rules: { - '@typescript-eslint/no-unnecessary-type-parameters': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/api-token.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/base64.test.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/gitignore.ts'], - rules: { - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/global-config.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/no-deprecated': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/local-state.ts'], - rules: { - '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/memoize.ts'], - rules: { - '@typescript-eslint/no-floating-promises': 'off', - }, - }, - { - files: ['packages/dev-utils/src/lib/watch-debounced.ts'], - rules: { - '@typescript-eslint/no-unused-vars': 'off', - }, - }, - { - files: ['packages/dev-utils/src/server/http_server.test.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/dev-utils/src/server/http_server.ts'], - rules: { - '@typescript-eslint/no-misused-promises': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/dev-utils/src/test/event_inspector.ts'], - rules: { - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/dev-utils/src/test/fetch.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/restrict-plus-operands': 'off', - '@typescript-eslint/prefer-promise-reject-errors': 'off', - }, - }, - { - files: ['packages/dev-utils/src/test/fixture.ts'], - rules: { - '@typescript-eslint/no-non-null-assertion': 'off', - }, - }, - { - files: ['packages/dev/src/lib/env.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/dev/src/lib/runtime.ts'], - rules: { - '@typescript-eslint/no-dynamic-delete': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/dev/src/main.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - }, - }, - { - files: ['packages/dev/test/mock-api.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-floating-promises': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/edge-functions/dev/src/node/main.test.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/edge-functions/dev/src/node/main.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/functions/dev/src/events.ts'], - rules: { - '@typescript-eslint/no-empty-object-type': 'off', - }, - }, - { - files: ['packages/functions/dev/src/function.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/functions/dev/src/main.test.ts'], - rules: { - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/functions/dev/src/main.ts'], - rules: { - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/no-misused-spread': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/functions/dev/src/registry.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-floating-promises': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-misused-promises': 'off', - }, - }, - { - files: ['packages/functions/dev/src/runtimes/index.ts'], - rules: { - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/functions/dev/src/runtimes/nodejs/builder.ts'], - rules: { - '@typescript-eslint/no-unused-vars': 'off', - 'n/no-missing-import': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - }, - }, - { - files: ['packages/functions/dev/src/runtimes/nodejs/config.ts'], - rules: { - '@typescript-eslint/prefer-reduce-type-parameter': 'off', - }, - }, - { - files: ['packages/functions/dev/src/runtimes/nodejs/index.ts'], - rules: { - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/functions/dev/src/runtimes/nodejs/lambda.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/functions/prod/internal.d.ts'], - rules: { - 'n/no-missing-import': 'off', - }, - }, - { - files: ['packages/functions/prod/src/function/handler.ts'], - rules: { - '@typescript-eslint/prefer-function-type': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - }, - }, - { - files: ['packages/functions/prod/src/function/handler_context.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/functions/prod/src/function/handler_response.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/builder.test.ts'], - rules: { - 'n/no-missing-import': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unused-vars': 'off', - 'vitest/expect-expect': 'off', - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/builder.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/purge_cache.test.ts'], - rules: { - 'n/no-missing-import': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/purge_cache.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/prefer-nullish-coalescing': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/schedule.ts'], - rules: { - '@typescript-eslint/no-unused-vars': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/system_logger.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - }, - }, - { - files: ['packages/functions/prod/src/lib/system_logger.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/functions/prod/test/types/Handler.test-d.ts'], - rules: { - '@typescript-eslint/no-unused-vars': 'off', - }, - }, - { - files: ['packages/identity/prod/src/account.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/identity/prod/src/admin.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - }, - }, - { - files: ['packages/identity/prod/src/auth.ts'], - rules: { - '@typescript-eslint/no-redundant-type-constituents': 'off', - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/src/config.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/identity/prod/src/cookies.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/src/environment.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/identity/prod/src/events.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - }, - }, - { - files: ['packages/identity/prod/src/nextjs.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/identity/prod/src/refresh.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/src/user.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/identity/prod/test/account.browser.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/test/admin.server.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/identity/prod/test/auth.browser.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/test/auth.server.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/test/refresh.browser.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-return': 'off', - }, - }, - { - files: ['packages/identity/prod/test/user.test.ts'], - rules: { - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/images/src/main.test.ts'], - rules: { - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/otel/src/bootstrap/main.ts'], - rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-confusing-void-expression': 'off', - }, - }, - { - files: ['packages/otel/src/exporters/netlify.ts'], - rules: { - '@typescript-eslint/unbound-method': 'off', - }, - }, - { - files: ['packages/otel/src/main.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/redirects/src/lib/rewriter.ts'], - rules: { - '@typescript-eslint/prefer-nullish-coalescing': 'off', - }, - }, - { - files: ['packages/redirects/src/main.test.ts'], - rules: { - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/redirects/src/main.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/runtime-utils/src/lib/base64.ts'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, - { - files: ['packages/runtime-utils/src/main.test.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/runtime/src/lib/environment/blobs.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/runtime/src/lib/util.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/runtime/src/main.test.ts'], - rules: { - '@typescript-eslint/no-dynamic-delete': 'off', - '@typescript-eslint/unbound-method': 'off', - '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['packages/static/src/main.ts'], - rules: { - '@typescript-eslint/require-await': 'off', - }, - }, - { - files: ['packages/types/src/lib/context/context.ts'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - { - files: ['packages/types/src/main.test.ts'], - rules: { - 'vitest/expect-expect': 'off', - 'vitest/valid-expect': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - }, - }, { files: ['packages/vite-plugin/src/lib/logger.ts'], rules: { diff --git a/package-lock.json b/package-lock.json index 4e6cfad..174973a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "netlify-primitives-monorepo", + "name": "netlify-framework-adapters-monorepo", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "netlify-primitives-monorepo", + "name": "netlify-framework-adapters-monorepo", "version": "0.0.0", "license": "MIT", "workspaces": [ @@ -679,15 +679,15 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz", - "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==", + "version": "0.87.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.87.0.tgz", + "integrity": "sha512-mFXZloZMzuJZXSHUmAFu/pXTk0ZJTJBluuAkrvbzidpTN8W6F2bpRFuedSH+85kbdlRLJqc+gfN+kD3JOLJK5g==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.8", - "@typescript-eslint/types": "^8.58.0", - "comment-parser": "1.4.6", + "@types/estree": "^1.0.9", + "@typescript-eslint/types": "^8.59.4", + "comment-parser": "1.4.7", "esquery": "^1.7.0", "jsdoc-type-pratt-parser": "~7.2.0" }, @@ -695,16 +695,6 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@es-joy/jsdoccomment/node_modules/comment-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", - "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/@es-joy/resolve.exports": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", @@ -1600,6 +1590,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1616,6 +1609,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1632,6 +1628,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1648,6 +1647,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1664,6 +1666,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1680,6 +1685,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1696,6 +1704,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1712,6 +1723,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1728,6 +1742,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1750,6 +1767,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1772,6 +1792,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1794,6 +1817,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1816,6 +1842,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1838,6 +1867,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1860,6 +1892,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1882,6 +1917,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2130,14 +2168,14 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.2" }, "funding": { "type": "github", @@ -2577,9 +2615,9 @@ "link": true }, "node_modules/@netlify/zip-it-and-ship-it": { - "version": "14.7.0", - "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-14.7.0.tgz", - "integrity": "sha512-SgqHGUTuPkarP5vpnjVKihsQAt7zQPfp+RjgpE+vJdW4tjJUEC3i6h954mE+3Mm7UZTF5xVRMMUJPi+d7oIiug==", + "version": "14.7.1", + "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-14.7.1.tgz", + "integrity": "sha512-In1BkoGFct5tid87oPTkTsITXrgUElgKDKzEmtxlezA4Oo95t2Gnv5m3IRVbI6eRcp3uygahxQPv/J8meX+n1Q==", "license": "MIT", "dependencies": { "@babel/parser": "^7.22.5", @@ -2789,9 +2827,9 @@ } }, "node_modules/@nuxt/devtools-kit/node_modules/@nuxt/kit": { - "version": "3.21.7", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.7.tgz", - "integrity": "sha512-kc7bEGcw3IHmSebr5PoO8B38MQ4N1CEcgEtrEpm+Dfmc0hE1j9KGygmHjk/eBwaYEATpSbgTzNUxjl2/cUU8ww==", + "version": "3.21.8", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.8.tgz", + "integrity": "sha512-kg63DUPY5AHPn+9XM7u8rYcdWHXjzwfUscgRDuiC5YUciQ+xdLRhdwXelYFxEAx2nxJHossliiQXbMm/Fleivw==", "dev": true, "license": "MIT", "dependencies": { @@ -2842,9 +2880,9 @@ } }, "node_modules/@nuxt/devtools/node_modules/@nuxt/kit": { - "version": "3.21.7", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.7.tgz", - "integrity": "sha512-kc7bEGcw3IHmSebr5PoO8B38MQ4N1CEcgEtrEpm+Dfmc0hE1j9KGygmHjk/eBwaYEATpSbgTzNUxjl2/cUU8ww==", + "version": "3.21.8", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.8.tgz", + "integrity": "sha512-kg63DUPY5AHPn+9XM7u8rYcdWHXjzwfUscgRDuiC5YUciQ+xdLRhdwXelYFxEAx2nxJHossliiQXbMm/Fleivw==", "dev": true, "license": "MIT", "dependencies": { @@ -2882,33 +2920,33 @@ "license": "MIT" }, "node_modules/@nuxt/eslint-config": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.15.2.tgz", - "integrity": "sha512-vS6mWB87tYjB8h3TxG/QziaZ6CGJpEOBd7N/j+64/tjNipUJzNgKwDzyGoOifNqyDDnlvgi6T3m9XpeYm4qRaA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.16.0.tgz", + "integrity": "sha512-YWEqctFWoKOUTaHWXe6TaUgZ1ewN7jeKz/ni4JopxDGIQ8AIMMST6VMWryybHqbPzEfpx8sEcAAFGM4W4quYhQ==", "dev": true, "license": "MIT", "dependencies": { "@antfu/install-pkg": "^1.1.0", - "@clack/prompts": "^1.0.1", - "@eslint/js": "^9.39.3", - "@nuxt/eslint-plugin": "1.15.2", - "@stylistic/eslint-plugin": "^5.9.0", - "@typescript-eslint/eslint-plugin": "^8.56.1", - "@typescript-eslint/parser": "^8.56.1", - "eslint-config-flat-gitignore": "^2.2.1", - "eslint-flat-config-utils": "^3.0.1", + "@clack/prompts": "^1.5.1", + "@eslint/js": "^10.0.1", + "@nuxt/eslint-plugin": "1.16.0", + "@stylistic/eslint-plugin": "^5.10.0", + "@typescript-eslint/eslint-plugin": "^8.61.0", + "@typescript-eslint/parser": "^8.61.0", + "eslint-config-flat-gitignore": "^2.3.0", + "eslint-flat-config-utils": "^3.2.0", "eslint-merge-processors": "^2.0.0", - "eslint-plugin-import-lite": "^0.5.2", - "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.7.1", - "eslint-plugin-regexp": "^3.0.0", - "eslint-plugin-unicorn": "^63.0.0", - "eslint-plugin-vue": "^10.8.0", + "eslint-plugin-import-lite": "^0.6.0", + "eslint-plugin-import-x": "^4.16.2", + "eslint-plugin-jsdoc": "^63.0.2", + "eslint-plugin-regexp": "^3.1.0", + "eslint-plugin-unicorn": "^65.0.1", + "eslint-plugin-vue": "^10.9.2", "eslint-processor-vue-blocks": "^2.0.0", - "globals": "^17.3.0", - "local-pkg": "^1.1.2", + "globals": "^17.6.0", + "local-pkg": "^1.2.1", "pathe": "^2.0.3", - "vue-eslint-parser": "^10.4.0" + "vue-eslint-parser": "^10.4.1" }, "peerDependencies": { "eslint": "^9.0.0 || ^10.0.0", @@ -2920,24 +2958,45 @@ } } }, + "node_modules/@nuxt/eslint-config/node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, "node_modules/@nuxt/eslint-plugin": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.15.2.tgz", - "integrity": "sha512-LZ4gEcPP5GjzAkb6Kk04a4v0vvkTLOpmnEvdDatnkSlxtQLUSwX8v11vcDGXL92ZQ98dFoC1Q1IA6Tz3jdFIig==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.16.0.tgz", + "integrity": "sha512-vbX9EsJqTqIRwf3+sv9mJ/OtFKhH8o8NIbNF9Q6weQZY1MRf8jGEvLnjsyJa5VEEHl5TXSXsPcyrmIK58jsRpw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.56.1", - "@typescript-eslint/utils": "^8.56.1" + "@typescript-eslint/types": "^8.61.0", + "@typescript-eslint/utils": "^8.61.0" }, "peerDependencies": { "eslint": "^9.0.0 || ^10.0.0" } }, "node_modules/@nuxt/kit": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.7.tgz", - "integrity": "sha512-QwtpqNxSOLyJH1UoDpcgsfzVEw95J0893hn1A+CvgeOxoTos1BGvD15D1v/OVQ2MK1EpfnFZJby51t1yudOvBA==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.8.tgz", + "integrity": "sha512-ZUlZ5iYfyfJFDPluhn6ZxFWcsuxWbLnZBc8w3MAROcQ4lYfZ+qFpALBLSNlpc0zhOa++33EE+5PEbOAdVIY+dw==", "license": "MIT", "dependencies": { "c12": "^3.3.4", @@ -3008,14 +3067,14 @@ } }, "node_modules/@nuxt/nitro-server": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@nuxt/nitro-server/-/nitro-server-4.4.7.tgz", - "integrity": "sha512-mlu/DQ2P0CUb62uKlWr/uiWEG//gxEzGoTHtqREb1iso15zMmRMpFajILOdCknSGNoOyDOhqdAe7w6Yod9o50g==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/@nuxt/nitro-server/-/nitro-server-4.4.8.tgz", + "integrity": "sha512-cc1fxgSx34Htesx3JBO+hMhbqd6VljXDC06P+UOA5z53cR224TmEFYT/MUuZDkrtt4qLnSG8yq0IxhEM3NCUlw==", "dev": true, "license": "MIT", "dependencies": { "@nuxt/devalue": "^2.0.2", - "@nuxt/kit": "4.4.7", + "@nuxt/kit": "4.4.8", "@unhead/vue": "^2.1.15", "@vue/shared": "^3.5.35", "consola": "^3.4.2", @@ -3049,7 +3108,7 @@ "@babel/plugin-proposal-decorators": "^7.25.0", "@babel/plugin-syntax-typescript": "^7.25.0", "@rollup/plugin-babel": "^6.0.0 || ^7.0.0", - "nuxt": "^4.4.7" + "nuxt": "^4.4.8" }, "peerDependenciesMeta": { "@babel/plugin-proposal-decorators": { @@ -3064,9 +3123,9 @@ } }, "node_modules/@nuxt/schema": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.4.7.tgz", - "integrity": "sha512-jcyXJlOR/GmxDQHrIEdEevUCUuBv7B6GCQXIBt4oKTCasIwWgGuqo48IM35RsxdQVTb4tBohnqJbS2lKJlCBWg==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.4.8.tgz", + "integrity": "sha512-igfWuMF0x0Pmx/XwhPwH/bcXgbuwNnjUjqxCAsY6VQhmGKo0e9soJq3Q0ohj+rBkBfX6o2ysTP1/t2M82aK4qA==", "dev": true, "license": "MIT", "dependencies": { @@ -3217,9 +3276,9 @@ } }, "node_modules/@nuxt/test-utils/node_modules/@nuxt/kit": { - "version": "3.21.7", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.7.tgz", - "integrity": "sha512-kc7bEGcw3IHmSebr5PoO8B38MQ4N1CEcgEtrEpm+Dfmc0hE1j9KGygmHjk/eBwaYEATpSbgTzNUxjl2/cUU8ww==", + "version": "3.21.8", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.8.tgz", + "integrity": "sha512-kg63DUPY5AHPn+9XM7u8rYcdWHXjzwfUscgRDuiC5YUciQ+xdLRhdwXelYFxEAx2nxJHossliiQXbMm/Fleivw==", "dev": true, "license": "MIT", "dependencies": { @@ -3257,13 +3316,13 @@ "license": "MIT" }, "node_modules/@nuxt/vite-builder": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-4.4.7.tgz", - "integrity": "sha512-EnMofNWpZF/dg4948PXk1kqrdR5uUR301sSudVbYj4DCjCa4NnBISwRbd4qe04F5Yw5OMHcR3svd8phZm1Yc7Q==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-4.4.8.tgz", + "integrity": "sha512-54M/k6qVY85Qeoe1m/lPZ0SANGJEbI50r5uYgh3XT942ENve3K5Nk6TMYp8i5wGGC4TWvPea+1mlCrp8rjsXag==", "dev": true, "license": "MIT", "dependencies": { - "@nuxt/kit": "4.4.7", + "@nuxt/kit": "4.4.8", "@rollup/plugin-replace": "^6.0.3", "@vitejs/plugin-vue": "^6.0.7", "@vitejs/plugin-vue-jsx": "^5.1.5", @@ -3298,7 +3357,7 @@ "peerDependencies": { "@babel/plugin-proposal-decorators": "^7.25.0", "@babel/plugin-syntax-jsx": "^7.25.0", - "nuxt": "4.4.7", + "nuxt": "4.4.8", "rolldown": "^1.0.0-beta.38", "rollup-plugin-visualizer": "^6.0.0 || ^7.0.1", "vue": "^3.3.4" @@ -3760,14 +3819,25 @@ "node": ">=18" } }, + "node_modules/@nuxt/vite-builder/node_modules/caniuse-api": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-4.0.0.tgz", + "integrity": "sha512-B0hQ1OLyJuHTQSOWXvwibWqM6DCoqJdvBA6X1S/53bd4XU7LJ1yurIPlrsouol3mw1jh9pGI4ivubSpmJeIqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0" + } + }, "node_modules/@nuxt/vite-builder/node_modules/cssnano": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.1.tgz", - "integrity": "sha512-oSiOnPQNNYjusTUlYJiE6xvFQG4don3N0QavaoV1BxIsC1zjvxOwikXlR7lG1EVmZNDDaJkHbQx1VRB8kaoMHA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.2.tgz", + "integrity": "sha512-K+a76gA1v0/CsYgcsE95HGGyIuPKxpQSetwSwz4nHEM8fFXqSkzq2JzEXFL8v5+CCjxzVVVhPcTK3Oo8SaF/xA==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-preset-default": "^8.0.1", + "cssnano-preset-default": "^8.0.2", "lilconfig": "^3.1.3" }, "engines": { @@ -3778,64 +3848,64 @@ "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/cssnano-preset-default": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.1.tgz", - "integrity": "sha512-OTdKeYMlvQ8KBgyej5ysktnWJoeyo7rGrVnm+bdpIHGvxhbTGPsOkB+7T1EdTuX00dGlQQb2UEbSPB1OpMXULw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.2.tgz", + "integrity": "sha512-+jQAqIKCqMmBjZs7741XkilU93ITZ/EW8gjAkMmujdCzfDkfjrDBv2VqkSu29Fzeig/0rZ3S9IAwfPLlmXEUfQ==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-calc": "^10.1.1", - "postcss-colormin": "^8.0.0", - "postcss-convert-values": "^8.0.0", - "postcss-discard-comments": "^8.0.0", - "postcss-discard-duplicates": "^8.0.0", - "postcss-discard-empty": "^8.0.0", - "postcss-discard-overridden": "^8.0.0", - "postcss-merge-longhand": "^8.0.0", - "postcss-merge-rules": "^8.0.0", - "postcss-minify-font-values": "^8.0.0", - "postcss-minify-gradients": "^8.0.0", - "postcss-minify-params": "^8.0.0", - "postcss-minify-selectors": "^8.0.1", - "postcss-normalize-charset": "^8.0.0", - "postcss-normalize-display-values": "^8.0.0", - "postcss-normalize-positions": "^8.0.0", - "postcss-normalize-repeat-style": "^8.0.0", - "postcss-normalize-string": "^8.0.0", - "postcss-normalize-timing-functions": "^8.0.0", - "postcss-normalize-unicode": "^8.0.0", - "postcss-normalize-url": "^8.0.0", - "postcss-normalize-whitespace": "^8.0.0", - "postcss-ordered-values": "^8.0.0", - "postcss-reduce-initial": "^8.0.0", - "postcss-reduce-transforms": "^8.0.0", - "postcss-svgo": "^8.0.0", - "postcss-unique-selectors": "^8.0.0" + "postcss-colormin": "^8.0.1", + "postcss-convert-values": "^8.0.1", + "postcss-discard-comments": "^8.0.1", + "postcss-discard-duplicates": "^8.0.1", + "postcss-discard-empty": "^8.0.1", + "postcss-discard-overridden": "^8.0.1", + "postcss-merge-longhand": "^8.0.1", + "postcss-merge-rules": "^8.0.1", + "postcss-minify-font-values": "^8.0.1", + "postcss-minify-gradients": "^8.0.1", + "postcss-minify-params": "^8.0.1", + "postcss-minify-selectors": "^8.0.2", + "postcss-normalize-charset": "^8.0.1", + "postcss-normalize-display-values": "^8.0.1", + "postcss-normalize-positions": "^8.0.1", + "postcss-normalize-repeat-style": "^8.0.1", + "postcss-normalize-string": "^8.0.1", + "postcss-normalize-timing-functions": "^8.0.1", + "postcss-normalize-unicode": "^8.0.1", + "postcss-normalize-url": "^8.0.1", + "postcss-normalize-whitespace": "^8.0.1", + "postcss-ordered-values": "^8.0.1", + "postcss-reduce-initial": "^8.0.1", + "postcss-reduce-transforms": "^8.0.1", + "postcss-svgo": "^8.0.1", + "postcss-unique-selectors": "^8.0.1" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/cssnano-utils": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.0.tgz", - "integrity": "sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.1.tgz", + "integrity": "sha512-zk65GIxA8tCjqVk7nTm1mE+ZKxtnxAvU5JSUaBLXbAr3ZF7IOvz3fbPOnEDvZKhnS7GOIitXTS5BgehLzNoc8Q==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/esbuild": { @@ -3896,28 +3966,28 @@ } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-colormin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.0.tgz", - "integrity": "sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.1.tgz", + "integrity": "sha512-qBY4ABQ6d8/mk5RRZHwMllrZMxeMey3azVY2dZUEk+RgiUC4ARdPR3/AITzNqqKTbvW/3y/MJKinDrzwqn8RDQ==", "dev": true, "license": "MIT", "dependencies": { "@colordx/core": "^5.4.3", "browserslist": "^4.28.2", - "caniuse-api": "^3.0.0", + "caniuse-api": "^4.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-convert-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.0.tgz", - "integrity": "sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.1.tgz", + "integrity": "sha512-IdOSIX3BzfMvCc1TAHIha2gfy17xnb5vfML8e2BIKARnFOghksESfaSAB/3CXgyLfMozZAbTRPVQF5dbuKOidw==", "dev": true, "license": "MIT", "dependencies": { @@ -3928,104 +3998,104 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-comments": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.0.tgz", - "integrity": "sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.1.tgz", + "integrity": "sha512-FDvzm3tXlEsQBO2XQgnta5ugsAqwBrgWH+j5QgXpegEIDYA0VPnZg2aP7LtmWtC49POskeIhXesFiU/k3NyFHA==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-duplicates": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.0.tgz", - "integrity": "sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.1.tgz", + "integrity": "sha512-stTDXkI8YkCUfADurQhp03oq5ynsgSx6Qrw5B1swds6oTHtAeOZ9I0SHGK8cY/VpWUsIYFDWMs3IWf9jIEfFvA==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-empty": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.0.tgz", - "integrity": "sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.1.tgz", + "integrity": "sha512-Zv4fM1Yfhk71tbt6gfiptbL6jDHi+7apSnaMeaO9n1uET+1embrXQw5m93Zp5x28UyQSuv+AVkFY193jdwZ33w==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-discard-overridden": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.0.tgz", - "integrity": "sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.1.tgz", + "integrity": "sha512-ykt4fvrC7yYGzbxKyqBVjDCbsjF/11JgWK8enrdkobRyqqEtb/uDUCbKOGdvrK8X7BrShW8Lv5cCRNbdkNHGkQ==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-merge-longhand": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.0.tgz", - "integrity": "sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.1.tgz", + "integrity": "sha512-huTfSYgQ13O81SFvAuOi7GWnO48vvybjj3xF+X3qUoPjzvvaLpJH5DcUqqXcwOEulZUcvaV4s0V9WtWs+IAQPA==", "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^8.0.0" + "stylehacks": "^8.0.1" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-merge-rules": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.0.tgz", - "integrity": "sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.1.tgz", + "integrity": "sha512-o3rk4UpnPNg469tklYwbR/NtvKc/f/wJiVDTnNQ/EFPw/LeiPOHUCvV1GIBQIZHGrBAYdPjToK6a+ojYprsrxQ==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^6.0.0", - "postcss-selector-parser": "^7.1.1" + "caniuse-api": "^4.0.0", + "cssnano-utils": "^6.0.1", + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-font-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.0.tgz", - "integrity": "sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.1.tgz", + "integrity": "sha512-L8Nzs/PRlBSPrLdY/7rAiU5ZN5800+2J/4LRbfyG8SJnPljmgMaXVmQiCklvRS+yObfVRNtvmk/Ean/eoYcSeg==", "dev": true, "license": "MIT", "dependencies": { @@ -4035,81 +4105,81 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-gradients": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.0.tgz", - "integrity": "sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.1.tgz", + "integrity": "sha512-qf+4s/hZMqTwpWN2teqf6+1yvR/SZK5HgHqXYuACeJXV7ABe7AXtBEomgxagUzcN4bSnmqBh5vnIml0dYqykYg==", "dev": true, "license": "MIT", "dependencies": { "@colordx/core": "^5.4.3", - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-params": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.0.tgz", - "integrity": "sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.1.tgz", + "integrity": "sha512-L0h3H59deFfFg0wQN1NVaS/8E/LfGvaMuZKGO7siwlG995zo3OshtQyRkqKdVqcBwAORBvZ1nDZrKPLRapYkQw==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-minify-selectors": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.1.tgz", - "integrity": "sha512-c31D46811kTkQDxV1KTTow79axX6gj/01AY5G7cGZg3s31KvAwP13jEFXGAzQbJ7NvOFV1pRqEia6nrAdHU7qg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.2.tgz", + "integrity": "sha512-3icdxc/zght5UAizdwqZBDE2KOWHf1jMQCxET6iLACeNlRxfTPyXS0/COpGk8CQ2cECyaEKTRUd/i/k8Gxmz4g==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-api": "^3.0.0", + "caniuse-api": "^4.0.0", "cssesc": "^3.0.0", - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-charset": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.0.tgz", - "integrity": "sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.1.tgz", + "integrity": "sha512-xzqr36F8UeIZOvOHsf3aul+RVJCADvSwuwpMLgizqKjisHZpBfztgW0XFLBfJvz9pJgaStaOXAtGb0zLqT6B0w==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-display-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.0.tgz", - "integrity": "sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.1.tgz", + "integrity": "sha512-ZDWOijOK1FFMlpgiQCUO9fCNKd7HJ9L7z9HWEq4iyubnUFWzdTSwm/LcrMbNW6iZ1oAtqeLYA0WA3xHszOI08g==", "dev": true, "license": "MIT", "dependencies": { @@ -4119,13 +4189,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-positions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.0.tgz", - "integrity": "sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.1.tgz", + "integrity": "sha512-uuivan2poSqbE48ST4do20dGaFUeXey9/H8rhHzoyVHB2I6BmkoVLZ/C9+BRjUlpaAFYVOoDY7epkiidzaYbvA==", "dev": true, "license": "MIT", "dependencies": { @@ -4135,13 +4205,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-repeat-style": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.0.tgz", - "integrity": "sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.1.tgz", + "integrity": "sha512-q2hq5fmKxk29K6DjKA3nZ17Q2dtjhLYFNmFweKALmooUqx6UWAHF1bBoWTu/EqlJ88josb82A/J0Atj9LJUmpQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4151,13 +4221,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-string": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.0.tgz", - "integrity": "sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.1.tgz", + "integrity": "sha512-+Wf+kQJhm1WgSGEAuUaswE9rdpR9QbrKRVemcVHs6rhOoOTVIdAbgaicftfYA6vLM346P8onRzkEVbFN29ktKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4167,13 +4237,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-timing-functions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.0.tgz", - "integrity": "sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.1.tgz", + "integrity": "sha512-W8/tvwRlm3T+yjGkg0IRTF4bvHj0vILYr/LOogCrJKHz2ey2HFRwfsAA8Bk9N4BGR7z7WmmDu/KzzwhJ6FoGPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4183,13 +4253,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-unicode": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.0.tgz", - "integrity": "sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.1.tgz", + "integrity": "sha512-Ad0YHNRBp4WHEOYUM/4wL/8MoL2fimEF8se/0q+Rt/owMzYpbxsypC1P8fN/oluwoRmRKdNVX7X2oycEobPWcQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4200,13 +4270,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.0.tgz", - "integrity": "sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.1.tgz", + "integrity": "sha512-tkYcip6pCDY806xuxpJYqMW2M3/623jzGFJmz3m5Us47q8P28+gbRZxaea3Rr/CmwwLUiVlh+BTGYwQ6gvaP8A==", "dev": true, "license": "MIT", "dependencies": { @@ -4216,13 +4286,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-normalize-whitespace": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.0.tgz", - "integrity": "sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.1.tgz", + "integrity": "sha512-XzORadNfSrKWDZZpgAEHPKINKx8r9r9RIfE9c70g/HThdpbmPHhDYCodHSVESDxmKeySAYw1p4liuBCf7j6LyA==", "dev": true, "license": "MIT", "dependencies": { @@ -4232,47 +4302,47 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-ordered-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.0.tgz", - "integrity": "sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.1.tgz", + "integrity": "sha512-OLXq5lR1yk3KWQ1FPK6aWjFFdktHE9f9kb8cnt4LmIw7w30DnzgD9+sOVYJc5HenkWCX8i1MJhhFwmqc/GYqLg==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-reduce-initial": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.0.tgz", - "integrity": "sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.1.tgz", + "integrity": "sha512-+aQsR6+61KRoIfcFNLP3v9RM7+0iYOTtPnjl1wr6JqMW1zx6S+t2ktHRefXwacFdHIDj5+ETG0KY7K3+SGQ4Nw==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "caniuse-api": "^3.0.0" + "caniuse-api": "^4.0.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-reduce-transforms": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.0.tgz", - "integrity": "sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.1.tgz", + "integrity": "sha512-x71slHVykiFi5RuKEXM0wgYpY2PngC78x6R8TnZhHF3lhqt+u/w3MGwYLX+2t5O87ssRiMfEAhQH+3J4QwVzCw==", "dev": true, "license": "MIT", "dependencies": { @@ -4282,13 +4352,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-svgo": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.0.tgz", - "integrity": "sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.1.tgz", + "integrity": "sha512-HpnvWii7W0/FPrsejJa6ZTi0kNtTJP/Iba7CUMPX0xPV6QpnndOp+SDP74tFtgjA2cYKYNWJPOlmLXMsvi/9yA==", "dev": true, "license": "MIT", "dependencies": { @@ -4299,40 +4369,40 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/postcss-unique-selectors": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.0.tgz", - "integrity": "sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.1.tgz", + "integrity": "sha512-+xvKI5+/Cl8yYQwxDV39Uhuc4WV951xngFvPPjiPj2NIbIfm6vbbRTXblyw0FioLkIoGlw+7qUcY1h2YhaZYgw==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/stylehacks": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.0.tgz", - "integrity": "sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.1.tgz", + "integrity": "sha512-Gv095oTD0N+BdJALNFDsxZpETHZLTxbOl5RyIO7y6VAE6sR3z0MnV3Nix7N0IATNldNTrkvSASp2KR1Yt526HA==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/@nuxt/vite-builder/node_modules/vite": { @@ -4661,6 +4731,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4678,6 +4751,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4695,6 +4771,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4712,6 +4791,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4729,6 +4811,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4746,6 +4831,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4763,6 +4851,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4780,6 +4871,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5003,6 +5097,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5020,6 +5117,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5037,6 +5137,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5054,6 +5157,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5071,6 +5177,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5088,6 +5197,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5105,6 +5217,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5122,6 +5237,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5355,6 +5473,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5372,6 +5493,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5389,6 +5513,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5406,6 +5533,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5423,6 +5553,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5440,6 +5573,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5457,6 +5593,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5474,6 +5613,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5699,6 +5841,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5719,6 +5864,9 @@ "cpu": [ "arm" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5739,6 +5887,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5759,6 +5910,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5779,6 +5933,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5799,6 +5956,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6047,6 +6207,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6064,6 +6227,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6081,6 +6247,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6098,6 +6267,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6115,6 +6287,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -6132,6 +6307,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -6448,13 +6626,11 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.61.1", @@ -6463,13 +6639,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.61.1", @@ -6478,13 +6652,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.61.1", @@ -6493,13 +6665,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.61.1", @@ -6508,13 +6678,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.61.1", @@ -6523,13 +6691,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.61.1", @@ -6538,13 +6704,14 @@ "cpu": [ "arm" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.61.1", @@ -6553,13 +6720,14 @@ "cpu": [ "arm" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.61.1", @@ -6568,13 +6736,14 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.61.1", @@ -6583,13 +6752,14 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.61.1", @@ -6598,13 +6768,14 @@ "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.61.1", @@ -6613,13 +6784,14 @@ "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.61.1", @@ -6628,13 +6800,14 @@ "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.61.1", @@ -6643,13 +6816,14 @@ "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.61.1", @@ -6658,13 +6832,14 @@ "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.61.1", @@ -6673,13 +6848,14 @@ "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.61.1", @@ -6688,13 +6864,14 @@ "cpu": [ "s390x" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.61.1", @@ -6703,13 +6880,14 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.61.1", @@ -6718,13 +6896,14 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.61.1", @@ -6733,13 +6912,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.61.1", @@ -6748,13 +6925,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.61.1", @@ -6763,13 +6938,11 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.61.1", @@ -6778,13 +6951,11 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.61.1", @@ -6793,13 +6964,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.61.1", @@ -6808,13 +6977,11 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@simple-git/args-pathspec": { "version": "1.0.3", @@ -6883,9 +7050,9 @@ } }, "node_modules/@speed-highlight/core": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.15.tgz", - "integrity": "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==", + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.16.tgz", + "integrity": "sha512-yNm/fYEcnpRjYduLMaddTK9XKYil6xB88+qFg79ZdZhHu1PadfoQmFW7pVTx7FZqMBNcUuThiAhxhENgtAO2/w==", "dev": true, "license": "CC0-1.0" }, @@ -6969,9 +7136,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", - "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "version": "22.19.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.21.tgz", + "integrity": "sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7014,17 +7181,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", - "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz", + "integrity": "sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/type-utils": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/type-utils": "8.61.0", + "@typescript-eslint/utils": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -7037,22 +7204,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.60.1", + "@typescript-eslint/parser": "^8.61.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", - "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.0.tgz", + "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3" }, "engines": { @@ -7068,13 +7235,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.0.tgz", + "integrity": "sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", + "@typescript-eslint/tsconfig-utils": "^8.61.0", + "@typescript-eslint/types": "^8.61.0", "debug": "^4.4.3" }, "engines": { @@ -7089,14 +7256,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.0.tgz", + "integrity": "sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7107,9 +7274,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz", + "integrity": "sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7123,15 +7290,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", - "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.0.tgz", + "integrity": "sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/utils": "8.61.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -7148,9 +7315,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.0.tgz", + "integrity": "sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7161,15 +7328,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.0.tgz", + "integrity": "sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", + "@typescript-eslint/project-service": "8.61.0", + "@typescript-eslint/tsconfig-utils": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -7188,16 +7355,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.0.tgz", + "integrity": "sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7212,12 +7379,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.0.tgz", + "integrity": "sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/types": "8.61.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -7264,19 +7431,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@unhead/vue/node_modules/unhead": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.15.tgz", - "integrity": "sha512-MCt5T90mCWyr3Z6pUCdM9lVRXoMoVBlL7z7U4CYVIiaDiuzad/UCfLuMqz5MeNmpZUgoBCQnrucJimU7EZR+XA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hookable": "^6.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/harlan-zw" - } - }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", @@ -7383,6 +7537,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7397,6 +7554,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7411,6 +7571,9 @@ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7425,6 +7588,9 @@ "loong64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7439,6 +7605,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7453,6 +7622,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7467,6 +7639,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7481,6 +7656,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7495,6 +7673,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -7509,6 +7690,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -7661,9 +7845,9 @@ } }, "node_modules/@vitest/eslint-plugin": { - "version": "1.6.19", - "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.19.tgz", - "integrity": "sha512-zodmXRsVKFsuHxHJILuTFaaKsrsxm0YsiOX65clk+LpCW9JrVXaf6ERXr0caDs+NEk0S62Jyk0K7XYQ7gWXheA==", + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.20.tgz", + "integrity": "sha512-xRwWHFG0Utp6hXtbGiWk4VdKXCGdExD8kbWrrmFEiG5dk8anOJ+vbWbeOa8EbkocKQRTsx7JAWETccZiBgFp/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7890,13 +8074,13 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", - "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.3", - "@vue/shared": "3.5.35", + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -7909,26 +8093,26 @@ "license": "MIT" }, "node_modules/@vue/compiler-dom": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", - "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz", - "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.3", - "@vue/compiler-core": "3.5.35", - "@vue/compiler-dom": "3.5.35", - "@vue/compiler-ssr": "3.5.35", - "@vue/shared": "3.5.35", + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.15", @@ -7942,13 +8126,13 @@ "license": "MIT" }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz", - "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/devtools-api": { @@ -8033,9 +8217,9 @@ } }, "node_modules/@vue/language-core": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.3.tgz", - "integrity": "sha512-X6p+7nfY7vVT6dQwUJ+v0Jfq/lwIfhL2jMi91dQ3ln4hnlGXlxsDu/FNkeyHYgvYtyQy18ZX76IZy7X4diDbiQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.4.tgz", + "integrity": "sha512-IuHqQ5zGGOE7CXP72VX6A42IVeIzYv4WAhO6arej11TRNqtdZfGyH8Yr2FOCaDX0dSQG+JwULLoFHGY1igYVjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8049,57 +8233,57 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz", - "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.35" + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz", - "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz", - "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", + "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.35", - "@vue/runtime-core": "3.5.35", - "@vue/shared": "3.5.35", + "@vue/reactivity": "3.5.38", + "@vue/runtime-core": "3.5.38", + "@vue/shared": "3.5.38", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz", - "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", + "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { - "vue": "3.5.35" + "vue": "3.5.38" } }, "node_modules/@vue/shared": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", - "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", "license": "MIT" }, "node_modules/@whatwg-node/disposablestack": { @@ -8199,9 +8383,9 @@ } }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -8672,9 +8856,9 @@ } }, "node_modules/bare-stream": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", - "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.2.tgz", + "integrity": "sha512-2V5j0dOfxv3iIngIWMnW1O6UPXpeoU70HJzUJGVth/+RURhDyq7SEWTD70Y2SkUB0MQonYYWpIX3f85P/I22+Q==", "license": "Apache-2.0", "dependencies": { "streamx": "^2.25.0", @@ -8727,9 +8911,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", - "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "version": "2.10.36", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.36.tgz", + "integrity": "sha512-lVq/Df7LXlO79MVaaUHztSwWiG9oXoWHlgvNS51v8Dpd4+G4/VIy6qYePTw31nAVls33nUtnfezYeLkYAak9dg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -9131,9 +9315,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", "dev": true, "funding": [ { @@ -9249,29 +9433,6 @@ "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", "license": "MIT" }, - "node_modules/clean-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/clean-regexp/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -9442,6 +9603,16 @@ "node": ">=12.20" } }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "extraneous": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/comment-parser": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", @@ -9702,9 +9873,9 @@ } }, "node_modules/crossws": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.4.5.tgz", - "integrity": "sha512-wUR89x/Rw7/8t+vn0CmGDYM9TD6VtARGb0LD5jq2wjtMy1vCP4M+sm6N6TigWeTYvnA8MoW29NqqXD0ep0rfBA==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.4.6.tgz", + "integrity": "sha512-/Wxe9Z007EbJ496j88nToZEvyPZ8PY/wjZJ18Agh/GCA9cYHyLbxtrpdFlFzAw3TV20F0SUYGl0g6PzChbwUrg==", "license": "MIT", "peerDependencies": { "srvx": ">=0.11.5" @@ -10177,6 +10348,19 @@ "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", "license": "MIT" }, + "node_modules/detect-indent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", + "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -10479,9 +10663,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.367", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.367.tgz", - "integrity": "sha512-4Mk/mrynCNQ+atY40D3UpmhLWB6AHMbYMlIrPhHcMF6x0L7O0b052FCAsxw1LlaR++UFuNg3D/A6XCuGDa0guQ==", + "version": "1.5.371", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.371.tgz", + "integrity": "sha512-e9htk9mAYL6AzmkEhSvVVw7IWGSBJ/Bqdn2eRyRLrj1g6sncN4WbFt5qnILYoCktktr45pyjIrOiRvBThQ808w==", "dev": true, "license": "ISC" }, @@ -10526,9 +10710,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.22.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.2.tgz", - "integrity": "sha512-0rxICaFZ7NQho/sHely2bvOPRP0Eu2B0NZ9zM54YvRvWMn7jfz3DmnOZDR9LlXDdDcqntAVc6Hfy4gr/tdH/Ag==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz", + "integrity": "sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11070,16 +11254,16 @@ } }, "node_modules/eslint-plugin-import-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-lite/-/eslint-plugin-import-lite-0.5.2.tgz", - "integrity": "sha512-XvfdWOC5dSLEI9krIPRlNmKSI2ViIE9pVylzfV9fCq0ZpDaNeUk6o0wZv0OzN83QdadgXp1NsY0qjLINxwYCsw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-lite/-/eslint-plugin-import-lite-0.6.0.tgz", + "integrity": "sha512-80vevx2A7i3H7n1/6pqDO8cc5wRz6OwLDvIyVl9UflBV1N1f46e9Ihzi65IOLYoSxM6YykK2fTw1xm0Ixx6aTQ==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=9.0.0" + "eslint": "^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-import-x": { @@ -11121,44 +11305,34 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "62.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz", - "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==", + "version": "63.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.2.tgz", + "integrity": "sha512-0TchoK1uS4VxHSo3P4CyWQ31Lm+6zsT+xkHMC5KbFKwgOf8YrXPf1Bl8EP7kpgw1wfe/Ui5jz5mSX7ou8WAVuw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.86.0", + "@es-joy/jsdoccomment": "~0.87.0", "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.6", + "comment-parser": "1.4.7", "debug": "^4.4.3", "escape-string-regexp": "^4.0.0", "espree": "^11.2.0", "esquery": "^1.7.0", "html-entities": "^2.6.0", - "object-deep-merge": "^2.0.0", + "object-deep-merge": "^2.0.1", "parse-imports-exports": "^0.2.4", - "semver": "^7.7.4", + "semver": "^7.8.2", "spdx-expression-parse": "^4.0.0", "to-valid-identifier": "^1.0.0" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": "^22.13.0 || >=24" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/comment-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", - "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -11276,27 +11450,26 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "63.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-63.0.0.tgz", - "integrity": "sha512-Iqecl9118uQEXYh7adylgEmGfkn5es3/mlQTLLkd4pXkIk9CTGrAbeUux+YljSa2ohXCBmQQ0+Ej1kZaFgcfkA==", + "version": "65.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-65.0.1.tgz", + "integrity": "sha512-daCrQrgxOoOz2uMPWB3Y3vvv/5q+ncwICI8IjoebiwtW87CaY4tAN5EEiRXTYVnf7qi1v1BGBdHOSnZLV0rx6A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", - "@eslint-community/eslint-utils": "^4.9.0", + "@eslint-community/eslint-utils": "^4.9.1", "change-case": "^5.4.4", - "ci-info": "^4.3.1", - "clean-regexp": "^1.0.0", - "core-js-compat": "^3.46.0", + "ci-info": "^4.4.0", + "core-js-compat": "^3.49.0", + "detect-indent": "^7.0.2", "find-up-simple": "^1.0.1", - "globals": "^16.4.0", + "globals": "^17.4.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", - "regexp-tree": "^0.1.27", "regjsparser": "^0.13.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "strip-indent": "^4.1.1" }, "engines": { @@ -11309,19 +11482,6 @@ "eslint": ">=9.38.0" } }, - "node_modules/eslint-plugin-unicorn/node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-vue": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.2.tgz", @@ -12213,7 +12373,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -12263,9 +12422,9 @@ } }, "node_modules/fuse.js": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.4.1.tgz", - "integrity": "sha512-AY7lKAXK71hi3WgUvDy6oZL67UEHOOtvCAwVdOXHyJd6ZzftBy7QqxuXt4HxmmAhYjmp/YCuOELZtIvAdlZ+fw==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.4.2.tgz", + "integrity": "sha512-LVbzjD4WA6UP5B1UnP8wuaXJiLnqMdM/E4fiJXTJ5haJ5b/MBNsK29h2fm6swEoQaVQjvYFWKLE2RanyZIoRVQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -12435,9 +12594,9 @@ } }, "node_modules/giget": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz", - "integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-3.3.0.tgz", + "integrity": "sha512-gzi2D96p+AMfDcmJHGDj3KJ9NRiwvlFAU5yfa3ROwWZmFUjX4P43x3BcyRaOMMLto1vUo7C+86+MFhYTl6Ryiw==", "license": "MIT", "bin": { "giget": "dist/cli.mjs" @@ -12974,9 +13133,9 @@ } }, "node_modules/import-in-the-middle": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.1.tgz", - "integrity": "sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.2.tgz", + "integrity": "sha512-LGLYRl0A2gtyUJb2WDliBHmk6TtlHwdDjxonacZ8QrEs/ZW+YDgNv2QAfjRQWpS8HqvNcq6GGnN6jrOa5FysDQ==", "license": "Apache-2.0", "dependencies": { "acorn": "^8.15.0", @@ -14158,7 +14317,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14180,7 +14338,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14202,7 +14359,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14224,7 +14380,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14246,7 +14401,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14263,12 +14417,14 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14285,12 +14441,14 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14307,12 +14465,14 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14329,12 +14489,14 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14356,7 +14518,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14378,7 +14539,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -16007,20 +16167,20 @@ } }, "node_modules/nuxt": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.7.tgz", - "integrity": "sha512-4ASIbcOVF2O1HJqoKRVntxOphl9zmikgmj25D9c93l795yp8x0f4TItzrnT0xyrFxMkpL6z3rHhrfQQfoxNXxw==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.8.tgz", + "integrity": "sha512-r/DGE4cNkEDclOw9tbJ18zqu+ix3me+7QCfumPdl5lBXGWgCajskzuq/HzDkHKfIZsn7ACVEjMLRNA2teh++bQ==", "dev": true, "license": "MIT", "dependencies": { "@dxup/nuxt": "^0.4.1", "@nuxt/cli": "^3.35.2", "@nuxt/devtools": "^3.2.4", - "@nuxt/kit": "4.4.7", - "@nuxt/nitro-server": "4.4.7", - "@nuxt/schema": "4.4.7", + "@nuxt/kit": "4.4.8", + "@nuxt/nitro-server": "4.4.8", + "@nuxt/schema": "4.4.8", "@nuxt/telemetry": "^2.8.0", - "@nuxt/vite-builder": "4.4.7", + "@nuxt/vite-builder": "4.4.8", "@unhead/vue": "^2.1.15", "@vue/shared": "^3.5.35", "chokidar": "^5.0.0", @@ -16062,7 +16222,7 @@ "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", "unctx": "^2.5.0", - "unhead": "^3.1.1", + "unhead": "^2.1.15", "unimport": "^6.3.0", "unplugin": "^3.0.0", "unrouting": "^0.1.7", @@ -16346,15 +16506,15 @@ } }, "node_modules/nypm": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.6.tgz", - "integrity": "sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.7.tgz", + "integrity": "sha512-s3ds97SD5pd1dULE+tHUk1DrV0cSHOnsfpcdGATJ8JpBo21DoKqN9exTH4/2nhPQNOLomBdTFMicN94S4DrZrQ==", "dev": true, "license": "MIT", "dependencies": { "citty": "^0.2.2", "pathe": "^2.0.3", - "tinyexec": "^1.1.1" + "tinyexec": "^1.2.4" }, "bin": { "nypm": "dist/cli.mjs" @@ -17642,9 +17802,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", "dev": true, "license": "MIT", "dependencies": { @@ -17792,9 +17952,9 @@ } }, "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { @@ -18684,9 +18844,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", - "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -18904,14 +19064,14 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -19230,9 +19390,9 @@ } }, "node_modules/streamx": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.26.0.tgz", - "integrity": "sha512-VvNG1K72Po/xwJzxZFnZ++Tbrv4lwSptsbkFuzXCJAYZvCK5nnxsvXU6ajqkv7chyiI1Y0YXq2Jh8Iy8Y7NF/A==", + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.27.0.tgz", + "integrity": "sha512-WZ189TKnHoAokYHvwzaAQMpd55cgUmFIcJFzBSgGcb886jau5DL+XdDhTWV4ps3FLvk+OORp0dLRTPsLZ21CSA==", "license": "MIT", "dependencies": { "events-universal": "^1.0.0", @@ -19309,18 +19469,19 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -19330,15 +19491,15 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "es-object-atoms": "^1.1.2" }, "engines": { "node": ">= 0.4" @@ -20656,16 +20817,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", - "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.0.tgz", + "integrity": "sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.60.1", - "@typescript-eslint/parser": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1" + "@typescript-eslint/eslint-plugin": "8.61.0", + "@typescript-eslint/parser": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/utils": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -21345,25 +21506,16 @@ } }, "node_modules/unhead": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-3.1.1.tgz", - "integrity": "sha512-tKPzJLM/maN/OQ5xhFJawHEp91U3LgQL5kd8lrZcU1hc/B8U+fM0EJqSe49AjgSUAkbLPXoL4YVPrMx2894WUA==", + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.15.tgz", + "integrity": "sha512-MCt5T90mCWyr3Z6pUCdM9lVRXoMoVBlL7z7U4CYVIiaDiuzad/UCfLuMqz5MeNmpZUgoBCQnrucJimU7EZR+XA==", "dev": true, "license": "MIT", "dependencies": { - "hookable": "^6.1.1", - "unplugin": "^3.0.0" + "hookable": "^6.0.1" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" - }, - "peerDependencies": { - "vite": ">=6.4.2" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } } }, "node_modules/unhead/node_modules/hookable": { @@ -21373,21 +21525,6 @@ "dev": true, "license": "MIT" }, - "node_modules/unhead/node_modules/unplugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", - "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "picomatch": "^4.0.3", - "webpack-virtual-modules": "^0.6.2" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -22850,7 +22987,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -22868,7 +23004,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -22886,7 +23021,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -22904,7 +23038,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -22922,7 +23055,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -22940,7 +23072,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -22958,7 +23089,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -22976,7 +23106,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -22994,7 +23123,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23012,7 +23140,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23030,7 +23157,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23048,7 +23174,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23066,7 +23191,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23084,7 +23208,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23102,7 +23225,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23120,7 +23242,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23138,7 +23259,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -23156,7 +23276,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23174,7 +23293,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23192,7 +23310,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23210,7 +23327,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -23228,7 +23344,6 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": ">=18" } @@ -23246,7 +23361,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -23264,7 +23378,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -23282,7 +23395,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -23300,7 +23412,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -23385,7 +23496,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -23510,17 +23620,17 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz", - "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", + "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.35", - "@vue/compiler-sfc": "3.5.35", - "@vue/runtime-dom": "3.5.35", - "@vue/server-renderer": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-sfc": "3.5.38", + "@vue/runtime-dom": "3.5.38", + "@vue/server-renderer": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { "typescript": "*" @@ -23754,14 +23864,14 @@ } }, "node_modules/vue-tsc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.3.tgz", - "integrity": "sha512-SWUEG7YRUeDJHT7Xsuhf02elYX2gxPzzAII7OxDAh4KNOr4QHQ0Lls0YfnaO5GNd560CwVa2HTfdqmA5MqvRqQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.4.tgz", + "integrity": "sha512-XA/JqmQwS2GZmfgpjOEGdrKwaTSEuPwxpHa7/t6f4yiGrJb3gVHTPb9wBfByMNZwQ+xDXs41b8gaS2DKsOozUw==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.3.3" + "@vue/language-core": "3.3.4" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -23888,9 +23998,9 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.21.tgz", - "integrity": "sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==", + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -24391,7 +24501,7 @@ "@nuxt/devtools-kit": "^2.6.2", "@nuxt/eslint-config": "^1.5.2", "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^4.0.0", + "@nuxt/schema": "^3.17.6", "@nuxt/test-utils": "^3.19.2", "@types/node": "^22.16.3", "eslint": "^9.30.1", @@ -24404,6 +24514,23 @@ "node": "^20.19.0 || >=22.12.0" } }, + "packages/nuxt-module/node_modules/@nuxt/schema": { + "version": "3.21.8", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.21.8.tgz", + "integrity": "sha512-BMxtf2x0E9sFji4Txz1boeMiwkhjQQFixdB6+lZXvCGpExZou4TLz82LDcIAZkpJVL0IEcfs96hTLVVBkjGulQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "^3.5.34", + "defu": "^6.1.7", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "std-env": "^4.1.0" + }, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "packages/vite-plugin": { "name": "@netlify/vite-plugin", "version": "2.12.7", @@ -24942,9 +25069,9 @@ } }, "packages/vite-plugin/node_modules/@types/node": { - "version": "20.19.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", - "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/packages/nuxt-module/package.json b/packages/nuxt-module/package.json index 32f2458..b049d42 100644 --- a/packages/nuxt-module/package.json +++ b/packages/nuxt-module/package.json @@ -46,11 +46,11 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/netlify/primitives.git", + "url": "https://github.com/netlify/framework-adapters.git", "directory": "packages/nuxt-module" }, "bugs": { - "url": "https://github.com/netlify/primitives/issues" + "url": "https://github.com/netlify/framework-adapters/issues" }, "author": "Netlify Inc.", "dependencies": { @@ -64,7 +64,7 @@ "@nuxt/devtools-kit": "^2.6.2", "@nuxt/eslint-config": "^1.5.2", "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^4.0.0", + "@nuxt/schema": "^3.17.6", "@nuxt/test-utils": "^3.19.2", "@types/node": "^22.16.3", "eslint": "^9.30.1", diff --git a/packages/vite-plugin-tanstack-start/package.json b/packages/vite-plugin-tanstack-start/package.json index ea5f03f..8291249 100644 --- a/packages/vite-plugin-tanstack-start/package.json +++ b/packages/vite-plugin-tanstack-start/package.json @@ -32,11 +32,11 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/netlify/primitives.git", + "url": "https://github.com/netlify/framework-adapters.git", "directory": "packages/vite-plugin-tanstack-start" }, "bugs": { - "url": "https://github.com/netlify/primitives/issues" + "url": "https://github.com/netlify/framework-adapters/issues" }, "author": "Netlify Inc.", "devDependencies": { diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json index 2970ca7..8786a34 100644 --- a/packages/vite-plugin/package.json +++ b/packages/vite-plugin/package.json @@ -29,11 +29,11 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/netlify/primitives.git", + "url": "https://github.com/netlify/framework-adapters.git", "directory": "packages/vite-plugin" }, "bugs": { - "url": "https://github.com/netlify/primitives/issues" + "url": "https://github.com/netlify/framework-adapters/issues" }, "author": "Netlify Inc.", "devDependencies": { diff --git a/release-please-config.json b/release-please-config.json index 7c8e111..994fd79 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -6,40 +6,7 @@ "release-type": "node", "separate-pull-requests": false, "packages": { - "packages/aws-lambda-compat": { - "prerelease": true, - "prerelease-type": "beta" - }, - "packages/ai": {}, - "packages/blobs": {}, - "packages/cache": {}, - "packages/database/dev": { - "prerelease": true, - "prerelease-type": "beta" - }, - "packages/database/prod": {}, - "packages/database/proxy": { - "prerelease": true, - "prerelease-type": "beta", - "bump-minor-pre-major": true, - "bump-patch-for-minor-pre-major": true - }, - "packages/dev": {}, - "packages/dev-utils": {}, - "packages/edge-functions/dev": {}, - "packages/edge-functions/prod": {}, - "packages/functions/dev": {}, - "packages/functions/prod": {}, - "packages/headers": {}, - "packages/identity/prod": {}, - "packages/images": {}, "packages/nuxt-module": {}, - "packages/otel": {}, - "packages/redirects": {}, - "packages/runtime": {}, - "packages/runtime-utils": {}, - "packages/static": {}, - "packages/types": {}, "packages/vite-plugin": {}, "packages/vite-plugin-tanstack-start": { "exclude-paths": ["packages/vite-plugin-tanstack-start/test"] From ae496f44842245b40172815dcd1afce665354dfd Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Mon, 15 Jun 2026 19:53:18 +0530 Subject: [PATCH 18/19] revert nuxt/schema to v4 --- package-lock.json | 266 +----------------------------- packages/nuxt-module/package.json | 2 +- 2 files changed, 2 insertions(+), 266 deletions(-) diff --git a/package-lock.json b/package-lock.json index 174973a..63f2441 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1590,9 +1590,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1609,9 +1606,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1628,9 +1622,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1647,9 +1638,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1666,9 +1654,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1685,9 +1670,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1704,9 +1686,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1723,9 +1702,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1742,9 +1718,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1767,9 +1740,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1792,9 +1762,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1817,9 +1784,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1842,9 +1806,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1867,9 +1828,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1892,9 +1850,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1917,9 +1872,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -4731,9 +4683,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4751,9 +4700,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4771,9 +4717,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4791,9 +4734,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4811,9 +4751,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4831,9 +4768,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4851,9 +4785,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4871,9 +4802,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5097,9 +5025,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5117,9 +5042,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5137,9 +5059,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5157,9 +5076,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5177,9 +5093,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5197,9 +5110,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5217,9 +5127,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5237,9 +5144,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5473,9 +5377,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5493,9 +5394,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5513,9 +5411,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5533,9 +5428,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5553,9 +5445,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5573,9 +5462,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5593,9 +5479,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5613,9 +5496,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5841,9 +5721,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5864,9 +5741,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5887,9 +5761,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5910,9 +5781,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5933,9 +5801,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5956,9 +5821,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6207,9 +6069,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6227,9 +6086,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6247,9 +6103,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6267,9 +6120,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6287,9 +6137,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6307,9 +6154,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6704,9 +6548,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6720,9 +6561,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6736,9 +6574,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6752,9 +6587,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6768,9 +6600,6 @@ "cpu": [ "loong64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6784,9 +6613,6 @@ "cpu": [ "loong64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6800,9 +6626,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6816,9 +6639,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6832,9 +6652,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6848,9 +6665,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6864,9 +6678,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6880,9 +6691,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6896,9 +6704,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7537,9 +7342,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7554,9 +7356,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7571,9 +7370,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7588,9 +7384,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7605,9 +7398,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7622,9 +7412,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7639,9 +7426,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7656,9 +7440,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7673,9 +7454,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7690,9 +7468,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -9603,16 +9378,6 @@ "node": ">=12.20" } }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/comment-parser": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", @@ -14417,9 +14182,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -14441,9 +14203,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -14465,9 +14224,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -14489,9 +14245,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -24501,7 +24254,7 @@ "@nuxt/devtools-kit": "^2.6.2", "@nuxt/eslint-config": "^1.5.2", "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^3.17.6", + "@nuxt/schema": "^4.0.0", "@nuxt/test-utils": "^3.19.2", "@types/node": "^22.16.3", "eslint": "^9.30.1", @@ -24514,23 +24267,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "packages/nuxt-module/node_modules/@nuxt/schema": { - "version": "3.21.8", - "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.21.8.tgz", - "integrity": "sha512-BMxtf2x0E9sFji4Txz1boeMiwkhjQQFixdB6+lZXvCGpExZou4TLz82LDcIAZkpJVL0IEcfs96hTLVVBkjGulQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/shared": "^3.5.34", - "defu": "^6.1.7", - "pathe": "^2.0.3", - "pkg-types": "^2.3.1", - "std-env": "^4.1.0" - }, - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, "packages/vite-plugin": { "name": "@netlify/vite-plugin", "version": "2.12.7", diff --git a/packages/nuxt-module/package.json b/packages/nuxt-module/package.json index b049d42..aae2ef3 100644 --- a/packages/nuxt-module/package.json +++ b/packages/nuxt-module/package.json @@ -64,7 +64,7 @@ "@nuxt/devtools-kit": "^2.6.2", "@nuxt/eslint-config": "^1.5.2", "@nuxt/module-builder": "^1.0.1", - "@nuxt/schema": "^3.17.6", + "@nuxt/schema": "^4.0.0", "@nuxt/test-utils": "^3.19.2", "@types/node": "^22.16.3", "eslint": "^9.30.1", From 8d4e6e017c3c117da09e04adac2d3d77fa9a14a0 Mon Sep 17 00:00:00 2001 From: Hrishikesh Kokate Date: Mon, 15 Jun 2026 19:53:51 +0530 Subject: [PATCH 19/19] remove extra package --- .release-please-manifest.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e013c73..7fd1835 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,6 +1,5 @@ { "packages/nuxt-module": "0.3.7", - "packages/types": "2.8.0", "packages/vite-plugin": "2.12.7", "packages/vite-plugin-tanstack-start": "1.3.15" }