From e463bd37ce5fe479d3f95c897b3ca3e8ccb7ed87 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 24 May 2026 23:51:31 +0000 Subject: [PATCH 01/15] Add AGENTS.md with Cursor Cloud development instructions Co-authored-by: Mohamed --- AGENTS.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..140d876cb9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +## Cursor Cloud specific instructions + +### Overview + +This is the **GitHub MCP Server** — a Go (1.24+) project implementing the Model Context Protocol for GitHub. It's a stateless stdio-based server with no database dependencies. + +### Key commands + +- **Lint**: `script/lint` (runs `gofmt -s -w .` then `golangci-lint`; auto-installs linter to `bin/` if missing) +- **Test**: `script/test` (runs `go test -race ./...`) +- **Build**: `go build ./cmd/github-mcp-server` +- **Run**: `GITHUB_PERSONAL_ACCESS_TOKEN= ./github-mcp-server stdio` +- **Update toolsnaps** (after changing MCP tool schemas): `UPDATE_TOOLSNAPS=true go test ./...` +- **Regenerate docs** (after changing tools): `script/generate-docs` + +See `.github/copilot-instructions.md` for full contributor workflow, project structure, and coding conventions. + +### Gotchas + +- The server requires `GITHUB_PERSONAL_ACCESS_TOKEN` to be set at runtime. Without it, the server won't start. For unit tests, this is not needed — tests mock the GitHub API. +- E2E tests (`e2e/`) require Docker and a real GitHub PAT (`GITHUB_MCP_SERVER_E2E_TOKEN`). They are not runnable without these. +- `script/lint` auto-downloads `golangci-lint` v2.5.0 to `bin/` on first run. This is cached across runs. +- The `github-mcp-server` binary is gitignored. Build it fresh with `go build ./cmd/github-mcp-server`. +- All lint/test/build commands are fast (~1-2s each when cached). From 530dc92be522d0a1abff84a621937d5fe3da98ec Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 1 Jun 2026 05:23:41 +0000 Subject: [PATCH 02/15] docs: add FixNow CTA patch for nowfix.pro placeholder links Co-authored-by: Mohamed --- docs/nowfix-cta-patch/INTEGRATION.md | 65 +++++++++++ docs/nowfix-cta-patch/README.md | 5 + .../app/fixes/[slug]/page.tsx | 51 ++++++++ docs/nowfix-cta-patch/app/fixes/page.tsx | 38 ++++++ .../landing/common-fixes.patch.example.tsx | 34 ++++++ .../components/landing/hero.patch.example.tsx | 21 ++++ .../components/site-footer.patch.example.tsx | 49 ++++++++ docs/nowfix-cta-patch/lib/fixes.ts | 109 ++++++++++++++++++ 8 files changed, 372 insertions(+) create mode 100644 docs/nowfix-cta-patch/INTEGRATION.md create mode 100644 docs/nowfix-cta-patch/README.md create mode 100644 docs/nowfix-cta-patch/app/fixes/[slug]/page.tsx create mode 100644 docs/nowfix-cta-patch/app/fixes/page.tsx create mode 100644 docs/nowfix-cta-patch/components/landing/common-fixes.patch.example.tsx create mode 100644 docs/nowfix-cta-patch/components/landing/hero.patch.example.tsx create mode 100644 docs/nowfix-cta-patch/components/site-footer.patch.example.tsx create mode 100644 docs/nowfix-cta-patch/lib/fixes.ts diff --git a/docs/nowfix-cta-patch/INTEGRATION.md b/docs/nowfix-cta-patch/INTEGRATION.md new file mode 100644 index 0000000000..236318f6a0 --- /dev/null +++ b/docs/nowfix-cta-patch/INTEGRATION.md @@ -0,0 +1,65 @@ +# FixNow — placeholder CTA patch + +Fixes **24 `href="#"` placeholders** on [nowfix.pro](https://nowfix.pro/) by routing users to real pages. + +## What this changes + +| Element | Before | After | +|--------|--------|--------| +| Fix grid cards (×6) | `href="#"` | `/fixes/slow-wifi`, etc. | +| “Fix something now” (hero + bottom) | ` or ... + * After: + */ +import Link from "next/link" +import { Button } from "@/components/ui/button" + +export function HeroCTAs() { + return ( +
+ + +
+ ) +} diff --git a/docs/nowfix-cta-patch/components/site-footer.patch.example.tsx b/docs/nowfix-cta-patch/components/site-footer.patch.example.tsx new file mode 100644 index 0000000000..a910e0ef48 --- /dev/null +++ b/docs/nowfix-cta-patch/components/site-footer.patch.example.tsx @@ -0,0 +1,49 @@ +/** + * EXAMPLE — footer links (replace href="#" with real targets). + */ +import Link from "next/link" +import { FOOTER_FIX_LINKS, fixHref } from "@/lib/fixes" + +const PRODUCT_LINKS = [ + { label: "How it works", href: "#how-it-works" }, + { label: "Pricing", href: "#pricing" }, + { label: "Mobile app", href: "/fixes" }, + { label: "Changelog", href: "/fixes" }, +] as const + +const COMPANY_LINKS = [ + { label: "About", href: "/about" }, + { label: "Careers", href: "/careers" }, + { label: "Blog", href: "/blog" }, + { label: "Contact", href: "/contact" }, +] as const + +const LEGAL_LINKS = [ + { label: "Privacy", href: "/privacy" }, + { label: "Terms", href: "/terms" }, + { label: "Security", href: "/security" }, +] as const + +export function SiteFooter() { + return ( +
+ {/* Logo: href="/" not href="#" */} + + FixNow + + +
    + {FOOTER_FIX_LINKS.map(({ label, slug }) => ( +
  • + + {label} + +
  • + ))} +
+ + {/* Product / company / legal — use PRODUCT_LINKS, COMPANY_LINKS, LEGAL_LINKS */} + See all fixes +
+ ) +} diff --git a/docs/nowfix-cta-patch/lib/fixes.ts b/docs/nowfix-cta-patch/lib/fixes.ts new file mode 100644 index 0000000000..7ab42afd4e --- /dev/null +++ b/docs/nowfix-cta-patch/lib/fixes.ts @@ -0,0 +1,109 @@ +export type FixGuide = { + slug: string + title: string + description: string + duration: string + category: "wifi" | "computer" | "phone" | "printer" | "account" | "streaming" + steps: string[] +} + +/** Canonical fix catalog — use `href` from slug via fixHref() everywhere. */ +export const FIXES: FixGuide[] = [ + { + slug: "slow-wifi", + title: "Slow or dropping Wi-Fi", + description: + "Reset the right way, find dead zones, and stop buffering for good.", + duration: "3 min fix", + category: "wifi", + steps: [ + "Restart your router and modem (unplug both, wait 30 seconds, plug modem first).", + "Move closer to the router or reduce interference from microwaves and baby monitors.", + "Forget and reconnect to your network on the device that drops.", + "If speeds are still low, run a speed test and contact your ISP if you're far below your plan.", + ], + }, + { + slug: "sluggish-computer", + title: "Sluggish computer", + description: "Free up storage, kill background hogs, and bring back the speed.", + duration: "5 min fix", + category: "computer", + steps: [ + "Close apps you're not using and check Task Manager / Activity Monitor for high CPU or memory.", + "Free at least 10–15% of disk space by emptying trash and removing large downloads.", + "Disable unnecessary startup programs.", + "Install pending OS and browser updates, then restart once.", + ], + }, + { + slug: "phone-acting-up", + title: "Phone acting up", + description: "Battery drain, full storage, crashing apps — sorted step by step.", + duration: "4 min fix", + category: "phone", + steps: [ + "Restart your phone.", + "Check storage — delete old photos/videos or offload to cloud if you're above 90% full.", + "Update iOS/Android and your most-used apps.", + "Reset network settings only if Wi‑Fi or cellular is broken (you'll re-enter Wi‑Fi passwords).", + ], + }, + { + slug: "printer-offline", + title: "Printer stuck offline", + description: + "Get it printing again without reinstalling everything from scratch.", + duration: "2 min fix", + category: "printer", + steps: [ + "Confirm the printer is on and connected to the same Wi‑Fi as your computer.", + "Set the printer as default in system print settings.", + "Clear the print queue and cancel stuck jobs.", + "Remove and re-add the printer if it still shows offline.", + ], + }, + { + slug: "locked-out-account", + title: "Locked out of an account", + description: "Safely reset passwords and set up 2FA so it never happens again.", + duration: "3 min fix", + category: "account", + steps: [ + "Use the service's official \"Forgot password\" flow — never click links from email unless you're sure.", + "Check spam for reset messages and try a different browser if the page won't load.", + "Use a password manager to generate and store a new unique password.", + "Enable two-factor authentication (authenticator app preferred over SMS).", + ], + }, + { + slug: "streaming-tv-glitches", + title: "Streaming & smart TV glitches", + description: "Fix freezing, sign-in loops, and apps that refuse to load.", + duration: "4 min fix", + category: "streaming", + steps: [ + "Sign out and back into the streaming app on your TV or stick.", + "Check for app and TV firmware updates.", + "Power-cycle the TV and streaming device (unplug 60 seconds).", + "If one app fails, try another network (phone hotspot) to rule out router issues.", + ], + }, +] + +export function fixHref(slug: string): string { + return `/fixes/${slug}` +} + +export function getFixBySlug(slug: string): FixGuide | undefined { + return FIXES.find((f) => f.slug === slug) +} + +/** Footer / nav shortcuts that map to fix slugs */ +export const FOOTER_FIX_LINKS = [ + { label: "Wi-Fi & internet", slug: "slow-wifi" }, + { label: "Slow computer", slug: "sluggish-computer" }, + { label: "Phone issues", slug: "phone-acting-up" }, + { label: "Printers", slug: "printer-offline" }, + { label: "Passwords", slug: "locked-out-account" }, +] as const From 8999ca96c9047ddbe3334d961b79d25447b3635e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 1 Jun 2026 05:30:06 +0000 Subject: [PATCH 03/15] chore: add script for nowfix CTA patch step 1 (copy routes) Co-authored-by: Mohamed --- scripts/apply-nowfix-cta-patch.sh | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 scripts/apply-nowfix-cta-patch.sh diff --git a/scripts/apply-nowfix-cta-patch.sh b/scripts/apply-nowfix-cta-patch.sh new file mode 100755 index 0000000000..65da3470df --- /dev/null +++ b/scripts/apply-nowfix-cta-patch.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Step 1: copy FixNow CTA patch files into your Next.js app root. +# Usage (from v0-linktree-clone-plan or any FixNow Next.js repo): +# curl -fsSL https://raw.githubusercontent.com/garlobrian52/github-mcp-server/main/scripts/apply-nowfix-cta-patch.sh | bash +# Or, if you have this repo cloned: +# ./scripts/apply-nowfix-cta-patch.sh /path/to/v0-linktree-clone-plan + +set -euo pipefail + +TARGET="${1:-.}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PATCH="${SCRIPT_DIR}/../docs/nowfix-cta-patch" + +if [[ ! -f "${PATCH}/lib/fixes.ts" ]]; then + echo "error: patch not found at ${PATCH}" >&2 + exit 1 +fi + +if [[ ! -f "${TARGET}/package.json" ]]; then + echo "error: ${TARGET} does not look like a Next.js project (no package.json)" >&2 + exit 1 +fi + +mkdir -p "${TARGET}/lib" "${TARGET}/app/fixes/[slug]" + +cp "${PATCH}/lib/fixes.ts" "${TARGET}/lib/fixes.ts" +cp "${PATCH}/app/fixes/page.tsx" "${TARGET}/app/fixes/page.tsx" +cp "${PATCH}/app/fixes/[slug]/page.tsx" "${TARGET}/app/fixes/[slug]/page.tsx" + +echo "Copied:" +echo " lib/fixes.ts" +echo " app/fixes/page.tsx" +echo " app/fixes/[slug]/page.tsx" +echo "" +echo "Next (manual): wire homepage + footer per docs/nowfix-cta-patch/INTEGRATION.md" +echo " - Replace fix card href=\"#\" with Link href={fixHref(fix.slug)}" +echo " - Hero: " +echo " - Footer + logo: see components/site-footer.patch.example.tsx" From 3c3d4abb67e708a0dac04491d2f7903e8648d483 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Jun 2026 14:30:35 +0000 Subject: [PATCH 04/15] Add Workflow DevKit email onboarding example Scaffold a Next.js example under examples/workflow-email-onboarding that demonstrates durable signup and welcome email workflows using workflow, Resend, and the use workflow/use step directives. Co-authored-by: Mohamed --- .../workflow-email-onboarding/.env.example | 2 + examples/workflow-email-onboarding/.gitignore | 41 + examples/workflow-email-onboarding/AGENTS.md | 5 + examples/workflow-email-onboarding/CLAUDE.md | 1 + examples/workflow-email-onboarding/README.md | 87 + .../eslint.config.mjs | 18 + .../workflow-email-onboarding/next.config.ts | 6 + .../package-lock.json | 12890 ++++++++++++++++ .../workflow-email-onboarding/package.json | 26 + .../workflow-email-onboarding/public/file.svg | 1 + .../public/globe.svg | 1 + .../workflow-email-onboarding/public/next.svg | 1 + .../public/vercel.svg | 1 + .../public/window.svg | 1 + .../src/app/api/signup/route.ts | 18 + .../src/app/api/welcome/route.ts | 18 + .../src/app/favicon.ico | Bin 0 -> 25931 bytes .../src/app/globals.css | 49 + .../src/app/layout.tsx | 30 + .../src/app/page.module.css | 142 + .../src/app/page.tsx | 66 + .../src/workflows/steps.ts | 120 + .../src/workflows/user-signup.ts | 23 + .../src/workflows/welcome.ts | 22 + .../workflow-email-onboarding/tsconfig.json | 37 + 25 files changed, 13606 insertions(+) create mode 100644 examples/workflow-email-onboarding/.env.example create mode 100644 examples/workflow-email-onboarding/.gitignore create mode 100644 examples/workflow-email-onboarding/AGENTS.md create mode 100644 examples/workflow-email-onboarding/CLAUDE.md create mode 100644 examples/workflow-email-onboarding/README.md create mode 100644 examples/workflow-email-onboarding/eslint.config.mjs create mode 100644 examples/workflow-email-onboarding/next.config.ts create mode 100644 examples/workflow-email-onboarding/package-lock.json create mode 100644 examples/workflow-email-onboarding/package.json create mode 100644 examples/workflow-email-onboarding/public/file.svg create mode 100644 examples/workflow-email-onboarding/public/globe.svg create mode 100644 examples/workflow-email-onboarding/public/next.svg create mode 100644 examples/workflow-email-onboarding/public/vercel.svg create mode 100644 examples/workflow-email-onboarding/public/window.svg create mode 100644 examples/workflow-email-onboarding/src/app/api/signup/route.ts create mode 100644 examples/workflow-email-onboarding/src/app/api/welcome/route.ts create mode 100644 examples/workflow-email-onboarding/src/app/favicon.ico create mode 100644 examples/workflow-email-onboarding/src/app/globals.css create mode 100644 examples/workflow-email-onboarding/src/app/layout.tsx create mode 100644 examples/workflow-email-onboarding/src/app/page.module.css create mode 100644 examples/workflow-email-onboarding/src/app/page.tsx create mode 100644 examples/workflow-email-onboarding/src/workflows/steps.ts create mode 100644 examples/workflow-email-onboarding/src/workflows/user-signup.ts create mode 100644 examples/workflow-email-onboarding/src/workflows/welcome.ts create mode 100644 examples/workflow-email-onboarding/tsconfig.json diff --git a/examples/workflow-email-onboarding/.env.example b/examples/workflow-email-onboarding/.env.example new file mode 100644 index 0000000000..6f8ebe253b --- /dev/null +++ b/examples/workflow-email-onboarding/.env.example @@ -0,0 +1,2 @@ +RESEND_API_KEY=re_xxxxxxxx +RESEND_FROM=Acme diff --git a/examples/workflow-email-onboarding/.gitignore b/examples/workflow-email-onboarding/.gitignore new file mode 100644 index 0000000000..5ef6a52078 --- /dev/null +++ b/examples/workflow-email-onboarding/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/workflow-email-onboarding/AGENTS.md b/examples/workflow-email-onboarding/AGENTS.md new file mode 100644 index 0000000000..8bd0e39085 --- /dev/null +++ b/examples/workflow-email-onboarding/AGENTS.md @@ -0,0 +1,5 @@ + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + diff --git a/examples/workflow-email-onboarding/CLAUDE.md b/examples/workflow-email-onboarding/CLAUDE.md new file mode 100644 index 0000000000..43c994c2d3 --- /dev/null +++ b/examples/workflow-email-onboarding/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/examples/workflow-email-onboarding/README.md b/examples/workflow-email-onboarding/README.md new file mode 100644 index 0000000000..cb24a76289 --- /dev/null +++ b/examples/workflow-email-onboarding/README.md @@ -0,0 +1,87 @@ +# Workflow email onboarding example + +A minimal [Workflow DevKit](https://useworkflow.dev) + [Next.js](https://nextjs.org) example that sends onboarding emails with [Resend](https://resend.com). + +## Install + +```bash +cd examples/workflow-email-onboarding +npm install +``` + +The project depends on: + +- `workflow` — durable workflows with `"use workflow"` and `"use step"` +- `resend` — email delivery inside step functions + +## Configure + +Copy the environment template and add your Resend credentials: + +```bash +cp .env.example .env.local +``` + +Required: + +- `RESEND_API_KEY` — from the Resend dashboard + +Optional: + +- `RESEND_FROM` — defaults to `Acme ` + +## Run locally + +```bash +npm run dev +``` + +Trigger the signup workflow (welcome email now, check-in after 7 days): + +```bash +curl -X POST --json '{"email":"hello@example.com"}' http://localhost:3000/api/signup +``` + +Trigger the personalized welcome workflow: + +```bash +curl -X POST --json '{"userId":"user_123"}' http://localhost:3000/api/welcome +``` + +Inspect runs: + +```bash +npx workflow web +npx workflow inspect runs +``` + +## What this demonstrates + +### Workflow orchestration + +`src/workflows/user-signup.ts` creates a user, sends a welcome email, sleeps for 7 days without holding a server open, then sends a follow-up email. + +### Step functions with Resend + +`src/workflows/steps.ts` keeps side effects in `"use step"` functions. Steps have full Node.js access, automatic retries, and use `FatalError` for non-retryable failures (for example, invalid API keys or rejected email payloads). + +### Personalized welcome flow + +`src/workflows/welcome.ts` chains `getUser` → `generateEmail` → `sendEmail` as separate durable steps. + +## Deploy + +Deploy to Vercel for production-grade durable execution. No extra Workflow configuration is required beyond `withWorkflow()` in `next.config.ts`. + +## Project layout + +```text +src/ + app/api/ + signup/route.ts # POST /api/signup + welcome/route.ts # POST /api/welcome + workflows/ + steps.ts # "use step" functions (Resend, user lookup) + user-signup.ts # 7-day onboarding workflow + welcome.ts # personalized welcome workflow +``` diff --git a/examples/workflow-email-onboarding/eslint.config.mjs b/examples/workflow-email-onboarding/eslint.config.mjs new file mode 100644 index 0000000000..05e726d1b4 --- /dev/null +++ b/examples/workflow-email-onboarding/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/examples/workflow-email-onboarding/next.config.ts b/examples/workflow-email-onboarding/next.config.ts new file mode 100644 index 0000000000..d5bd5dee77 --- /dev/null +++ b/examples/workflow-email-onboarding/next.config.ts @@ -0,0 +1,6 @@ +import type { NextConfig } from "next"; +import { withWorkflow } from "workflow/next"; + +const nextConfig: NextConfig = {}; + +export default withWorkflow(nextConfig); diff --git a/examples/workflow-email-onboarding/package-lock.json b/examples/workflow-email-onboarding/package-lock.json new file mode 100644 index 0000000000..8bff259be5 --- /dev/null +++ b/examples/workflow-email-onboarding/package-lock.json @@ -0,0 +1,12890 @@ +{ + "name": "workflow-email-onboarding", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "workflow-email-onboarding", + "version": "0.1.0", + "dependencies": { + "next": "16.2.7", + "react": "19.2.4", + "react-dom": "19.2.4", + "resend": "^6.12.4", + "workflow": "^4.3.1" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.7", + "typescript": "^5" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.974.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.15.tgz", + "integrity": "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.9", + "@aws-sdk/xml-builder": "^3.972.26", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/core": "^3.24.5", + "@smithy/signature-v4": "^5.4.5", + "@smithy/types": "^4.14.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.13.tgz", + "integrity": "sha512-a6iFMh1pgUH0TdcouBppLJUfPM7Yd3R9S1xFodPtCRoLqCz2RQFA3qjA8x4112PVYXEd4/pHX2eihapq39w0rA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.13.tgz", + "integrity": "sha512-2pA6eyb5nSo/ZD2cayhOTEMoGQYgspq0RI05GDLkzQ3ajZ6isS6waV6E92Am/hz4LIlLUTrbwPLurJ/fuiHvkg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.15", + "@aws-sdk/signature-v4-multi-region": "^3.996.30", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.5", + "@smithy/fetch-http-handler": "^5.4.5", + "@smithy/node-http-handler": "^4.7.5", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.30", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.30.tgz", + "integrity": "sha512-HULDLMVzkmTSEv6//7kx2kRevp/VYUpm8hJNNFbmhxDn0fUiGTxVcM9yg31TukvTq8nyOBDUN2gH0o5IRbKjdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.9", + "@smithy/signature-v4": "^5.4.5", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.973.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.9.tgz", + "integrity": "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.26", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.26.tgz", + "integrity": "sha512-cDbrqvDS73whl6YAPSPq0U6whzG6UWI9PuWh0wrUuGoZexhWEqhdunbukV7iBoaWnFV1AODutM5hOD6rtn439g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.2", + "fast-xml-parser": "5.7.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "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": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "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.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", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "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.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "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.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "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": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "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.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "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.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "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": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "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.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "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.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "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.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": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@cbor-extract/cbor-extract-darwin-arm64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.2.tgz", + "integrity": "sha512-ZKZ/F8US7JR92J4DMct6cLW/Y66o2K576+zjlEN/MevH70bFIsB10wkZEQPLzl2oNh2SMGy55xpJ9JoBRl5DOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@cbor-extract/cbor-extract-darwin-x64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.2.tgz", + "integrity": "sha512-32b1mgc+P61Js+KW9VZv/c+xRw5EfmOcPx990JbCBSkYJFY0l25VinvyyWfl+3KjibQmAcYwmyzKF9J4DyKP/Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-arm": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.2.tgz", + "integrity": "sha512-tNg0za41TpQfkhWjptD+0gSD2fggMiDCSacuIeELyb2xZhr7PrhPe5h66Jc67B/5dmpIhI2QOUtv4SBsricyYQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-arm64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.2.tgz", + "integrity": "sha512-wfqgzqCAy/Vn8i6WVIh7qZd0DdBFaWBjPdB6ma+Wihcjv0gHqD/mw3ouVv7kbbUNrab6dKEx/w3xQZEdeXIlzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-x64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.2.tgz", + "integrity": "sha512-rpiLnVEsqtPJ+mXTdx1rfz4RtUGYIUg2rUAZgd1KjiC1SehYUSkJN7Yh+aVfSjvCGtVP0/bfkQkXpPXKbmSUaA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-win32-x64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.2.tgz", + "integrity": "sha512-dI+9P7cfWxkTQ+oE+7Aa6onEn92PHgfWXZivjNheCRmTBDBf2fx6RyTi0cmgpYLnD1KLZK9ZYrMxaPZ4oiXhGA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@emnapi/core": { + "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.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "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": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "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.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": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "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.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "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.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": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "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.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.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "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": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "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": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "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.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "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.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.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", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "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" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "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" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "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" + ], + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "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" + ], + "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-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "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" + ], + "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-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "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" + ], + "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" + ], + "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-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "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" + ], + "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-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "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" + ], + "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-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "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" + ], + "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-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "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" + ], + "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-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "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.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "license": "MIT", + "peer": true + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@nestjs/common": { + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.24.tgz", + "integrity": "sha512-9zHxaDDM+oXW9As6UsP5yYB+UqczBmpeSCIFWdPEtEukMnZhxODG1BBjaUcdBB8Sc1uzojSJSJlp3yFp853t1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "file-type": "21.3.4", + "iterare": "1.2.1", + "load-esm": "1.0.3", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": ">=0.4.1", + "class-validator": ">=0.13.2", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/core": { + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.24.tgz", + "integrity": "sha512-K4bzT+lEdd0Hhcsw3jtk56QAW6s6skK3ViN7hIROSN0kUf4ROwWEAKopJID6yhPQxB45kDtP2wEcjzE8171J3g==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nuxt/opencollective": "0.4.1", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "8.4.2", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "engines": { + "node": ">= 20" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^11.0.0", + "@nestjs/microservices": "^11.0.0", + "@nestjs/platform-express": "^11.0.0", + "@nestjs/websockets": "^11.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@next/env": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.7.tgz", + "integrity": "sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.7.tgz", + "integrity": "sha512-VbS+QgMHqvIDMTIqD2xMBKK1otIpdAUKA8VLHFwR9h6OfU/mOm7w/69nQcvdmI8hCk99Wr2AsGLn/PJ/tMHw1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.7.tgz", + "integrity": "sha512-vm1EDI/pVaBNNiychmxk3fft+OhQPVD9cIM/tReLZIQ3TfQ4kqI9DwKk00dzuS1ulC7icbrzCFrmRRlk9PfNdw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.7.tgz", + "integrity": "sha512-O3IRSv1ZBL1zs0WrIgefTEcTKFVn+ryxBNe54erJ6KsD+2f/Mmt7g2jOYh8PSBdUwPtKQJuCsTMlZ7tIu2AcsQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.7.tgz", + "integrity": "sha512-Re6PZtjBDd0aMU+VcZcC/PrIvj4WhrjDYtMhhCVQamWN4L90EVP0pcEOBQD25prSlw7OzNw5QpHLWMilRLsRNw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.7.tgz", + "integrity": "sha512-qyogG9QtBzWxgJfeGBvOEHI3851gTfCF3wLZ5RDLTBJGAmE9p1qDwKCOdrBrvBzRvYDT+gUDp72pzlSEfAXgNA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.7.tgz", + "integrity": "sha512-Vhe4ZDuBpmMogrGi5D4R2Kq4JAQlj6+wvgaFYy31zfES0zPmt6TLA+cuYpM/OLrPZjo2MYQTHVqNUSCR6+fDZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.7.tgz", + "integrity": "sha512-srvian89JahFLw1YLBEuhvPJ0DO5lpUeJQMXy4xYo7g628ZlNgXdNkqoxSAv9OYrBfByh6vxISMwW/mRbzCY+g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.7.tgz", + "integrity": "sha512-GX3wvLpULFuRFJzwHaKfm7QZJ18F4ZSuxlPJ96BoBglCzBmdSjyeBKF+ZhWhvL/ckxNfLnNa7bsObO2ipYpszw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.7.tgz", + "integrity": "sha512-J4WlM72NMk076Qsg0jTdK3SNXatlSdnjW7L7oNGLst1tAGjHrJh/FYi+pw9wyIjEtGRKDNzD0zuiY16oWYWVaw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodable/entities": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.1.tgz", + "integrity": "sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@nuxt/kit": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz", + "integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==", + "license": "MIT", + "dependencies": { + "c12": "^3.3.3", + "consola": "^3.4.2", + "defu": "^6.1.4", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.8", + "ignore": "^7.0.5", + "jiti": "^2.6.1", + "klona": "^2.0.6", + "mlly": "^1.8.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "rc9": "^3.0.0", + "scule": "^1.3.0", + "semver": "^7.7.4", + "tinyglobby": "^0.2.15", + "ufo": "^1.6.3", + "unctx": "^2.5.0", + "untyped": "^2.0.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@nuxt/kit/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", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nuxt/opencollective": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.4.1.tgz", + "integrity": "sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "consola": "^3.2.3" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": "^14.18.0 || >=16.10.0", + "npm": ">=5.10.0" + } + }, + "node_modules/@oclif/core": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.8.1.tgz", + "integrity": "sha512-07mq0vKCWNsB85ZHeBMlTAiO0KLFqHyAeRK3bD2K8CI1tX3tiwkWw1lZQZkiw8MUBrhxdROhMkYMY4Q0l7JHqA==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "ansis": "^3.17.0", + "clean-stack": "^3.0.1", + "cli-spinners": "^2.9.2", + "debug": "^4.4.3", + "ejs": "^3.1.10", + "get-package-type": "^0.1.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "lilconfig": "^3.1.3", + "minimatch": "^10.2.1", + "semver": "^7.7.3", + "string-width": "^4.2.3", + "supports-color": "^8", + "tinyglobby": "^0.2.14", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@oclif/core/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==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@oclif/core/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==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@oclif/core/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": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@oclif/core/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", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@oclif/core/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@oclif/plugin-help": { + "version": "6.2.37", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.37.tgz", + "integrity": "sha512-5N/X/FzlJaYfpaHwDC0YHzOzKDWa41s9t+4FpCDu4f9OMReds4JeNBaaWk9rlIzdKjh2M6AC5Q18ORfECRkHGA==", + "license": "MIT", + "dependencies": { + "@oclif/core": "^4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT", + "peer": true + }, + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@smithy/core": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.6.tgz", + "integrity": "sha512-wBXDRup6UU97VKyaiRo8AssnfStPtG0oAAfpq/bC0a1YYau8pM86YB4kM6ccoVi1mS8l/UHbn9oDM+7uozr/ug==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.6.tgz", + "integrity": "sha512-FEwEYJ1jlBKdhe9TPzfghEi1bP55ZeEImlDkEa62bBBYzUcnB6RUCyuiS2mqKt6ZVjUbBgcNhzfIctH+Hevx9g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.6.tgz", + "integrity": "sha512-3fya8i7GrJilQouk4cZJKdy5k8MWQBpjfXrRNaXDedH8r779tr0jcxyH3+yoTmsluc2+vF4S343yFbnvu8ExDQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.3.6.tgz", + "integrity": "sha512-0rhHv1Ww27kajF6qewme2aRtJmKFtSwE6EZ2dj5KxdX/R3ANsUugqTnH0tvpZwGiQ3MOMhetuCGFAeKVv3/Onw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.5.6.tgz", + "integrity": "sha512-In8gYD2R66EKlGAq9QrNKVrMOGaGBD7LUNp2kUjeQ4V9zNktFIXBPmrCySr4YYo+jVeVL6CnWj26sOamcF0qIg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.6.tgz", + "integrity": "sha512-Ojg4B6oIDlIr1R86xCDJt1zJWnYa0VINmqdjfe9qxWjdRivHalZ3iSlQgVqYbW0MdpFOC5XfHEWsnbmdnpIILQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.3.tgz", + "integrity": "sha512-YupL0ZWmFtJexUN2cHzkvvF/b9pKrtAIfT1o7/oY/Ppu8IYeZ+lDPM5vZdQJaSeA132dJCqojjGC9NhXeF71VQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.3.tgz", + "integrity": "sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.3.tgz", + "integrity": "sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.3.tgz", + "integrity": "sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.3.tgz", + "integrity": "sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.3.tgz", + "integrity": "sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.3.tgz", + "integrity": "sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.3.tgz", + "integrity": "sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.3.tgz", + "integrity": "sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.3.tgz", + "integrity": "sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.3.tgz", + "integrity": "sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", + "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT", + "peer": true + }, + "node_modules/@tybys/wasm-util": { + "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, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "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/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "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==", + "license": "MIT" + }, + "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": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", + "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "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==", + "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", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@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/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" + } + }, + "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==", + "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", + "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": { + "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.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "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==", + "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.1.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "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==", + "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/@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==", + "dev": true, + "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", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "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" + }, + "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 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/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/@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", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "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, + "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, + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "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, + "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.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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@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-win32-arm64-msvc": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "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" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vercel/cli-auth": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@vercel/cli-auth/-/cli-auth-0.0.1.tgz", + "integrity": "sha512-CnqiuMlZ4pjs2LCPYiR6aLKPPd3Xb8SBI1Y7eotXKgpx6qgrGNY+E7EIyUt5ErGHJGIrCZyGG5WEo4bHtVmz2Q==", + "dependencies": { + "async-listen": "3.0.0", + "open": "8.4.0", + "xdg-app-paths": "5", + "zod": "4.1.11" + } + }, + "node_modules/@vercel/cli-auth/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@vercel/cli-auth/node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vercel/cli-auth/node_modules/zod": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz", + "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@vercel/functions": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-3.6.1.tgz", + "integrity": "sha512-xz+zZvj/XE6KDHZ8kYNO25Axpjng/kTJd/87SwONa6hzlq94K69OdqH1ZC/CehbtwWknpeyHqUHmpnfoaCbLZQ==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/oidc": "3.5.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-web-identity": "*" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-provider-web-identity": { + "optional": true + } + } + }, + "node_modules/@vercel/oidc": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.5.0.tgz", + "integrity": "sha512-jo7GgeJx2YMkjg9A28pFM5p88n5SnSHvDeNlf9898bRWiG9jPxwedj/gn/2XTw4UOTyQ50uHlrTGSlf/XU5tgw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@vercel/queue": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@vercel/queue/-/queue-0.1.7.tgz", + "integrity": "sha512-4Uk9LOvDPVYqBJGrNDk4fdLte4CmFERXCUJI2y7SRYX1d//dI96Ww7sgKZF4+YDj/YaBXoCZ11AU0HYkVwW9Eg==", + "license": "MIT", + "dependencies": { + "@vercel/oidc": "^3.0.5", + "minimatch": "^10.2.4", + "mixpart": "0.0.6", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@vercel/queue/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==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vercel/queue/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==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vercel/queue/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": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vercel/queue/node_modules/mixpart": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/mixpart/-/mixpart-0.0.6.tgz", + "integrity": "sha512-CRdXtgfQH2jARmtNmPR0Q7jL20fiESbaYk1b0KvLD0jCdUuemepREtsbd8nbiY6BHV9OGGddAZITNXklupUPUQ==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@workflow/astro": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@workflow/astro/-/astro-4.0.8.tgz", + "integrity": "sha512-y+m9tJ3BqpwJiXGJCVF2vvBDiQ0EJnidh4RgyrX/txR3/IGQtMYo1LI65ZcBjsNj+8rzsSkDRR0eQM+6ztGmkw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/builders": "4.0.9", + "@workflow/rollup": "4.0.8", + "@workflow/swc-plugin": "4.1.1", + "@workflow/vite": "4.0.8", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/@workflow/astro/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/astro/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/astro/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/builders": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@workflow/builders/-/builders-4.0.9.tgz", + "integrity": "sha512-SqMt+AXWwoTZqAic5GWt7J8KyhwkmXiEEjM49uq4ISmHK/zrKBynzrBl+BHEJZS6KSnlTICKZUvjtfDknYRu4Q==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/core": "4.3.1", + "@workflow/errors": "4.1.3", + "@workflow/swc-plugin": "4.1.1", + "@workflow/utils": "4.1.2", + "builtin-modules": "5.0.0", + "chalk": "5.6.2", + "enhanced-resolve": "5.19.0", + "esbuild": "^0.27.3", + "find-up": "7.0.0", + "json5": "2.2.3", + "tinyglobby": "0.2.15" + } + }, + "node_modules/@workflow/builders/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/builders/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/builders/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/builders/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@workflow/builders/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/@workflow/builders/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==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/builders/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/@workflow/builders/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/builders/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/builders/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/@workflow/builders/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@workflow/builders/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" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@workflow/builders/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": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/cli": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@workflow/cli/-/cli-4.2.8.tgz", + "integrity": "sha512-/pfOMeKzXoRXJDoGZwSSj7eHuHlJH0P4jmNJ42Vd4XchnxgS/a8asVx+ym2QMM03yLy3drhKsBs3S4saQjTcPw==", + "license": "Apache-2.0", + "dependencies": { + "@oclif/core": "4.8.1", + "@oclif/plugin-help": "6.2.37", + "@swc/core": "1.15.3", + "@vercel/cli-auth": "0.0.1", + "@workflow/builders": "4.0.9", + "@workflow/core": "4.3.1", + "@workflow/errors": "4.1.3", + "@workflow/swc-plugin": "4.1.1", + "@workflow/utils": "4.1.2", + "@workflow/web": "4.1.9", + "@workflow/world": "4.1.4", + "@workflow/world-local": "4.1.4", + "@workflow/world-vercel": "4.3.2", + "boxen": "8.0.1", + "builtin-modules": "5.0.0", + "chalk": "5.6.2", + "chokidar": "4.0.3", + "date-fns": "4.1.0", + "dotenv": "^17.3.1", + "easy-table": "1.2.0", + "enhanced-resolve": "5.19.0", + "esbuild": "^0.27.3", + "find-up": "7.0.0", + "mixpart": "0.0.4", + "open": "10.2.0", + "ora": "8.2.0", + "terminal-link": "5.0.0", + "tinyglobby": "0.2.15", + "xdg-app-paths": "5.1.0", + "zod": "4.3.6" + }, + "bin": { + "wf": "bin/run.js", + "workflow": "bin/run.js" + } + }, + "node_modules/@workflow/cli/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/cli/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/cli/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/cli/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@workflow/cli/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/@workflow/cli/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==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/cli/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/@workflow/cli/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/cli/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/cli/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/@workflow/cli/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@workflow/cli/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" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@workflow/cli/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": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@workflow/core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@workflow/core/-/core-4.3.1.tgz", + "integrity": "sha512-TUNRYHCDXHYDg/Q+m9rHc0WOzZBQHK8j6OUZalaAWruTQB4e93jXtH/Kh9sIqODthvgV9i5lROmVWzXfILhkmw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-web-identity": "3.972.13", + "@jridgewell/trace-mapping": "0.3.31", + "@standard-schema/spec": "1.0.0", + "@types/ms": "2.1.0", + "@vercel/functions": "^3.4.3", + "@workflow/errors": "4.1.3", + "@workflow/serde": "4.1.1", + "@workflow/utils": "4.1.2", + "@workflow/world": "4.1.4", + "@workflow/world-local": "4.1.4", + "@workflow/world-vercel": "4.3.2", + "debug": "4.4.3", + "devalue": "5.6.3", + "ms": "2.1.3", + "nanoid": "5.1.6", + "seedrandom": "3.0.5", + "semver": "7.7.4", + "ulid": "~3.0.1", + "zod": "4.3.6" + }, + "peerDependencies": { + "@opentelemetry/api": "1" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@workflow/core/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@workflow/core/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@workflow/errors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@workflow/errors/-/errors-4.1.3.tgz", + "integrity": "sha512-0QaAZPqxTg38zeTEXxgVhTOyX5ANFNsEKg4Esk/Kl2xWzFK54U+YE4vcqTyZn7raKLz3wnEh6f0oA9kzIZiTNA==", + "license": "Apache-2.0", + "dependencies": { + "@workflow/utils": "4.1.2", + "ms": "2.1.3" + } + }, + "node_modules/@workflow/next": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@workflow/next/-/next-4.0.9.tgz", + "integrity": "sha512-uTGF/xJStgN/nPdMYX0m6zk34p3VhwGrNSW3GkuGTKWavKdG6OfNFBSG6WakpkSOltdoeKpNeQPTcrdSC4CSuw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/builders": "4.0.9", + "@workflow/core": "4.3.1", + "@workflow/swc-plugin": "4.1.1", + "semver": "7.7.4", + "watchpack": "2.5.1" + }, + "peerDependencies": { + "next": ">13" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + } + } + }, + "node_modules/@workflow/next/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/next/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/next/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/next/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@workflow/nitro": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@workflow/nitro/-/nitro-4.0.9.tgz", + "integrity": "sha512-JSJWH6RVB01hgNezx2H3mnlF9XUQEC0PuSW3BKICarXxWC3XjIxy6Bg8bVOqFWRyC1+NYxwhqMEHtHMde+Ni9w==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/builders": "4.0.9", + "@workflow/core": "4.3.1", + "@workflow/rollup": "4.0.8", + "@workflow/swc-plugin": "4.1.1", + "@workflow/vite": "4.0.8", + "exsolve": "1.0.8", + "pathe": "2.0.3" + } + }, + "node_modules/@workflow/nitro/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/nitro/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/nitro/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/nuxt": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@workflow/nuxt/-/nuxt-4.0.9.tgz", + "integrity": "sha512-SW6sXphFk33H5Vtz7oyG4hP5vTY7oAJYCVoeREy6m/FNdY+z8DEly5C5bqEfIUeQzE3BjtPTFqbG7aUD2L28Yg==", + "license": "Apache-2.0", + "dependencies": { + "@nuxt/kit": "4.4.2", + "@workflow/nitro": "4.0.9" + } + }, + "node_modules/@workflow/rollup": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@workflow/rollup/-/rollup-4.0.8.tgz", + "integrity": "sha512-Wn3xqYNcq8ZktHzh37PnP0MWzk8pXT5KKBflmzz/eHIOBEePnjRhlZUjIAQ+ryQt2wGoZA+gnI+Pgf5UTUhgdA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/builders": "4.0.9", + "@workflow/swc-plugin": "4.1.1", + "exsolve": "1.0.7" + } + }, + "node_modules/@workflow/rollup/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/rollup/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/rollup/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/rollup/node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "license": "MIT" + }, + "node_modules/@workflow/serde": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/serde/-/serde-4.1.1.tgz", + "integrity": "sha512-191/N2w3WlrapuAvtAT1knONuqJ9auOqM8c7yMMM7c6rqXAZQKkNJrOuuj/j0vp7x43rg0+fy90bqT/xQ5ki4w==", + "license": "Apache-2.0" + }, + "node_modules/@workflow/sveltekit": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@workflow/sveltekit/-/sveltekit-4.0.8.tgz", + "integrity": "sha512-Vl/tqNE/j7+/LdYMeDM+WeZPY9XiOlGRBIF1UsRHquzyKYBz6x+wqByCNB6m4EHMLCpT+YcFkgDmZfOPdFprtA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/builders": "4.0.9", + "@workflow/rollup": "4.0.8", + "@workflow/swc-plugin": "4.1.1", + "@workflow/vite": "4.0.8", + "exsolve": "^1.0.8", + "fs-extra": "^11.3.2", + "pathe": "^2.0.3" + } + }, + "node_modules/@workflow/sveltekit/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@workflow/sveltekit/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@workflow/sveltekit/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/@workflow/typescript-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@workflow/typescript-plugin/-/typescript-plugin-4.0.2.tgz", + "integrity": "sha512-7bw6aEl+QMZWWZmhJS5bydrSgmxQrG8Kyo5Zhdb7klu+/pBUyNMVTUZmnfe1xRjWborqvOevqYbSDh0a0gwnAw==", + "license": "Apache-2.0", + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/@workflow/utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@workflow/utils/-/utils-4.1.2.tgz", + "integrity": "sha512-Q9KNjROGO/YjRvgbigobODGWtbOunNWhnyVU3EmfstrD8hBgwUyzN9cvi61Cnu/2C9g9Y1YW3Qr0/XSQTUJQIA==", + "license": "Apache-2.0", + "dependencies": { + "ms": "2.1.3" + } + }, + "node_modules/@workflow/vite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@workflow/vite/-/vite-4.0.8.tgz", + "integrity": "sha512-WXvNL3IPB4eLSjJBvxxK1+MYkrQDpv7OtaqkCtUyFeTr0IzsKlcgp91cqIH7L4UcLZ3TA0AQy6Phucb54hadTQ==", + "license": "Apache-2.0", + "dependencies": { + "@workflow/builders": "4.0.9" + } + }, + "node_modules/@workflow/web": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@workflow/web/-/web-4.1.9.tgz", + "integrity": "sha512-LHmxH/WNLluI8ZnJtGMyCgvf4qsHlI22Om7/RYnFBbgCjB8rGXjyv0giEC8WFFU2hkz4bloBxmH+SCCmNruYSw==", + "license": "Apache-2.0", + "dependencies": { + "express": "^4.21.0" + } + }, + "node_modules/@workflow/world": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@workflow/world/-/world-4.1.4.tgz", + "integrity": "sha512-XJYkyLewLI23JtYDGAq0WGSjXBYPeieOjOQyrR8COe8SFECqQym45NcMoJw34OsEdc7R7KA1IQnBnNdV97/4Pg==", + "license": "Apache-2.0", + "dependencies": { + "ulid": "~3.0.1" + }, + "peerDependencies": { + "zod": "4.3.6" + } + }, + "node_modules/@workflow/world-local": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@workflow/world-local/-/world-local-4.1.4.tgz", + "integrity": "sha512-vQsQFZF8Wifd1Sm8plo45CXAtKQBQ0dBOus7IGkDPabrp7hfJRbfN5YG4CiiyoiXfmJCBQgW9utv6XneY+YTbg==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/queue": "0.1.7", + "@workflow/errors": "4.1.3", + "@workflow/utils": "4.1.2", + "@workflow/world": "4.1.4", + "async-sema": "3.1.1", + "ulid": "~3.0.1", + "undici": "7.22.0", + "zod": "4.3.6" + }, + "peerDependencies": { + "@opentelemetry/api": "1" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@workflow/world-vercel": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@workflow/world-vercel/-/world-vercel-4.3.2.tgz", + "integrity": "sha512-uVUQaoP7ojqWPQjTJGFMASBXXjlL9yuCGaF6IZ51rNoyb9MiKS/t668p23tzrQrY3kqgh4PNu1jYc/5R4j+UPg==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/oidc": "3.2.0", + "@vercel/queue": "0.1.7", + "@workflow/errors": "4.1.3", + "@workflow/world": "4.1.4", + "cbor-x": "1.6.0", + "undici": "7.22.0", + "zod": "4.3.6" + }, + "peerDependencies": { + "@opentelemetry/api": "1" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@workflow/world-vercel/node_modules/@vercel/oidc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz", + "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@xhmikosr/archive-type": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/archive-type/-/archive-type-8.0.1.tgz", + "integrity": "sha512-toXuiWChyfOpEiCPsIw6HGHaNji5LVkvB6EREL548vGWr+hGaehwxG4LzN20vm9aGFXwnA/Jty8yW2/SmV+1zQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "file-type": "^21.3.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/bin-check": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/bin-check/-/bin-check-8.2.1.tgz", + "integrity": "sha512-DNruLq+kalxcE7JeDxtqrN9kyWjLW8VqsQPLRTwD1t9ck/1rF4qBL0mX5Fe2/xLOMjo5wPb67BNX2kSAhzfLjA==", + "license": "MIT", + "peer": true, + "dependencies": { + "execa": "^9.6.1", + "isexe": "^4.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/bin-check/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/bin-wrapper": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@xhmikosr/bin-wrapper/-/bin-wrapper-14.2.5.tgz", + "integrity": "sha512-MXfD5mNdc9xQM4/I4O7uWSdQqeZPTYRQSfddUtfH9oUeVkDUTnX4HI2udTsvDEs7ptv2ywHE9UfxlMUs+79wFw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xhmikosr/bin-check": "^8.2.1", + "@xhmikosr/downloader": "^16.1.3", + "@xhmikosr/os-filter-obj": "^4.1.0", + "binary-version-check": "^6.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/decompress": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress/-/decompress-11.1.3.tgz", + "integrity": "sha512-NiyhJq6z7ERsYghcnXZUI6ooDXgZtoB+G9eUsYhfSM4VLp2rKx9UxhKI1NEf1PqosrNPxG3bnSsr2UBVbNurlg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xhmikosr/decompress-tar": "^9.0.1", + "@xhmikosr/decompress-tarbz2": "^9.0.1", + "@xhmikosr/decompress-targz": "^9.0.1", + "@xhmikosr/decompress-unzip": "^8.1.1", + "graceful-fs": "^4.2.11", + "strip-dirs": "^3.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/decompress-tar": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tar/-/decompress-tar-9.0.1.tgz", + "integrity": "sha512-4AkVR1SoqTxYY22IRRYKDeLirPIDGqMqYsqgjKYuwhgRcBb+yDP4t5Xph33UCzL/nahK/aADmlMEjTNstbX7kw==", + "license": "MIT", + "peer": true, + "dependencies": { + "file-type": "^21.3.0", + "is-stream": "^4.0.1", + "tar-stream": "3.1.7" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/decompress-tarbz2": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tarbz2/-/decompress-tarbz2-9.0.1.tgz", + "integrity": "sha512-aFONnsbqEOuXudvK7V7wB8dcEAKR389oUYQfZhrQZA8OtogJpDjrUAvEH3Qlc9yFqTU6r5/svTEcRwtXhoIJbQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xhmikosr/decompress-tar": "^9.0.0", + "file-type": "^21.3.0", + "is-stream": "^4.0.1", + "seek-bzip": "^2.0.0", + "unbzip2-stream": "^1.4.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/decompress-targz": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-targz/-/decompress-targz-9.0.1.tgz", + "integrity": "sha512-1JXu2b6yrpm5EuBoOzMU57B4qrHXJKWQQ7LlMynNEiz85mEjDciO3ayf//GXaTLLCEKiHjWlU3q3THjgf7uODA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xhmikosr/decompress-tar": "^9.0.0", + "file-type": "^21.3.0", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/decompress-unzip": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-unzip/-/decompress-unzip-8.1.1.tgz", + "integrity": "sha512-/B+Z0qJflGn5UEtmMZ2qeKeXwexOycxaibYhMOyLcRPJriXs4IkoSngVUVZXLYViu9TdHyFWynC6NB4EWBg8cg==", + "license": "MIT", + "peer": true, + "dependencies": { + "file-type": "^21.3.4", + "get-stream": "^9.0.1", + "yauzl": "^3.3.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/downloader": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/@xhmikosr/downloader/-/downloader-16.1.3.tgz", + "integrity": "sha512-jtQZZbO3xsRmDDeEz7m23ydgbW9YpVnOALNygmKNvjjuTuQwtcXGVJ9xWv4x7niElvziJrak+WUBmWYcFosolA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xhmikosr/archive-type": "^8.0.1", + "@xhmikosr/decompress": "^11.1.3", + "content-disposition": "^2.0.1", + "ext-name": "^5.0.0", + "file-type": "^21.3.4", + "filenamify": "^7.0.1", + "get-stream": "^9.0.1", + "got": "^14.6.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@xhmikosr/downloader/node_modules/content-disposition": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", + "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@xhmikosr/os-filter-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/os-filter-obj/-/os-filter-obj-4.1.0.tgz", + "integrity": "sha512-y5ArHvQ7BVule/+L9yE2nYMhceiJhgsqo58lOfnisQ7bg+Kjfmkgr7JBuVFiTkl+ErdShpp829QstZQyLugl8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "system-architecture": "^1.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "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.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "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/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-listen": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.0.tgz", + "integrity": "sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.0.tgz", + "integrity": "sha512-FTavr/7Ba0IptwGOPxnQvdyW2tAsdLBMTBXz7rKH6xJ2skpyxpBxyHkDdBs4lf69yRqYpkqCdfhnwS8YULGOmg==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/b4a": { + "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", + "peer": true, + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "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/bare-events": { + "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", + "peer": true, + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, + "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==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-version": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/binary-version/-/binary-version-7.1.0.tgz", + "integrity": "sha512-Iy//vPc3ANPNlIWd242Npqc8MK0a/i4kVcHDlDA6HNMv5zMxz4ulIFhOSYJVKw/8AbHdHy0CnGYEt1QqSXxPsw==", + "license": "MIT", + "peer": true, + "dependencies": { + "execa": "^8.0.1", + "find-versions": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version-check": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/binary-version-check/-/binary-version-check-6.1.0.tgz", + "integrity": "sha512-REKdLKmuViV2WrtWXvNSiPX04KbIjfUV3Cy8batUeOg+FtmowavzJorfFhWq95cVJzINnL/44ixP26TrdJZACA==", + "license": "MIT", + "peer": true, + "dependencies": { + "binary-version": "^7.1.0", + "semver": "^7.6.0", + "semver-truncate": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version-check/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", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/binary-version/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "license": "MIT", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/binary-version/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/binary-version/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", + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version/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", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-version/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", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", + "cli-boxes": "^3.0.0", + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/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==", + "license": "MIT" + }, + "node_modules/boxen/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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/boxen/node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "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": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "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" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/builtin-modules": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", + "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==", + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/byte-counter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/byte-counter/-/byte-counter-0.1.0.tgz", + "integrity": "sha512-jheRLVMeUKrDBjVw2O5+k4EvR4t9wtxHL+bo/LxfkxsVeuGMy3a5SEGgXdAFA4FSzTrU8rQXQIrsZ3oBq5a0pQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz", + "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==", + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "confbox": "^0.2.4", + "defu": "^6.1.6", + "dotenv": "^17.3.1", + "exsolve": "^1.0.8", + "giget": "^3.2.0", + "jiti": "^2.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.0", + "rc9": "^3.0.1" + }, + "peerDependencies": { + "magicast": "*" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "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": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "13.0.19", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-13.0.19.tgz", + "integrity": "sha512-SVXGH037+Mo1aIMO5B2UcleR43FGjFdN+M8JObSyEoQ2Mn4CODRWx28gN5jiTF0n5ItsgtIZfyargMNs8GX4kg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/http-cache-semantics": "^4.2.0", + "get-stream": "^9.0.1", + "http-cache-semantics": "^4.2.0", + "keyv": "^5.6.0", + "mimic-response": "^4.0.0", + "normalize-url": "^8.1.1", + "responselike": "^4.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacheable-request/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "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==", + "dev": true, + "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/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/cbor-extract": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.2.tgz", + "integrity": "sha512-hlSxxI9XO2yQfe9g6msd3g4xCfDqK5T5P0fRMLuaLHhxn4ViPrm+a+MUfhrvH2W962RGxcBwEGzLQyjbDG1gng==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.1.1" + }, + "bin": { + "download-cbor-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@cbor-extract/cbor-extract-darwin-arm64": "2.2.2", + "@cbor-extract/cbor-extract-darwin-x64": "2.2.2", + "@cbor-extract/cbor-extract-linux-arm": "2.2.2", + "@cbor-extract/cbor-extract-linux-arm64": "2.2.2", + "@cbor-extract/cbor-extract-linux-x64": "2.2.2", + "@cbor-extract/cbor-extract-win32-x64": "2.2.2" + } + }, + "node_modules/cbor-x": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.0.tgz", + "integrity": "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==", + "license": "MIT", + "optionalDependencies": { + "cbor-extract": "^2.2.0" + } + }, + "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" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "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/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "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": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "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" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz", + "integrity": "sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "mimic-response": "^4.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "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==", + "dev": true, + "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", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "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==", + "dev": true, + "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.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "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", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", + "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dotenv": { + "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" + }, + "funding": { + "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/easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.365", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.365.tgz", + "integrity": "sha512-xfip4u1QF1s+URFqpA6N+OeFpDGpN7VJz1f3MO3bVL0QYBjpGiZ5/Of7kugvM+o8TTqmanUlviHN3c8M9vYWCw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/errx": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/errx/-/errx-0.1.0.tgz", + "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==", + "dev": true, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.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", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/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==", + "dev": true, + "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==", + "dev": true, + "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.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "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/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "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.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", + "ajv": "^6.14.0", + "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.5", + "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 + } + } + }, + "node_modules/eslint-config-next": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.7.tgz", + "integrity": "sha512-CQ2aNXkrsjaGA2oJBE1LYnlRdphIAQE9ZQfX9hSv1PNGPyiOMSaVeBfTIO29QxYz+ij/hZudK0cfpCG1HXWstg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "16.2.7", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.13.0.tgz", + "integrity": "sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/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==", + "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/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/esquery": { + "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": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "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/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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", + "peer": true, + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "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": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT", + "peer": true + }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, + "node_modules/fast-xml-builder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.7", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "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", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-type": { + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/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/filelist/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": ">=10" + } + }, + "node_modules/filename-reserved-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.0.tgz", + "integrity": "sha512-9ZT504KxEQDamsOogZImAWGEN24R1uFAxU3ZS4AZqn2ooidmN68Olh7n4/RcA4lLatZztjA0ZSuxeLHVoCc8JA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filenamify": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.1.tgz", + "integrity": "sha512-9b4rfnaX2MkJCgp27wypV6DAMvj4WMOSgJ+TdcpJIO84Dql+Cv6iJjdG4XDTLubOWkfNiBv3joO59sau/TXw+Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "filename-reserved-regex": "^4.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "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/find-versions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", + "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", + "license": "MIT", + "peer": true, + "dependencies": { + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data-encoder": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz", + "integrity": "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-timeout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", + "integrity": "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "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-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "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": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "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==", + "dev": true, + "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.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": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz", + "integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==", + "license": "MIT", + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "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/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "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/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/got": { + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", + "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@sindresorhus/is": "^7.0.1", + "byte-counter": "^0.1.0", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^13.0.12", + "decompress-response": "^10.0.0", + "form-data-encoder": "^4.0.2", + "http2-wrapper": "^2.2.1", + "keyv": "^5.5.3", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^4.0.1", + "responselike": "^4.0.2", + "type-fest": "^4.26.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/got/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)", + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "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==", + "dev": true, + "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", + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, + "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/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inspect-with-kind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz", + "integrity": "sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==", + "license": "ISC", + "peer": true, + "dependencies": { + "kind-of": "^6.0.2" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "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==", + "dev": true, + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "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==", + "dev": true, + "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", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "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==", + "dev": true, + "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-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", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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": "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/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "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" + }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "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" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "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" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "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/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/knitwork": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.3.0.tgz", + "integrity": "sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==", + "license": "MIT" + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/load-esm": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz", + "integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + }, + { + "type": "buymeacoffee", + "url": "https://buymeacoffee.com/borewit" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=13.2.0" + } + }, + "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/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/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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/make-asynchronous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/make-asynchronous/-/make-asynchronous-1.1.0.tgz", + "integrity": "sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==", + "license": "MIT", + "peer": true, + "dependencies": { + "p-event": "^6.0.0", + "type-fest": "^4.6.0", + "web-worker": "^1.5.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-asynchronous/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)", + "peer": true, + "engines": { + "node": ">=16" + }, + "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/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "peer": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mixpart": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/mixpart/-/mixpart-0.0.4.tgz", + "integrity": "sha512-RAoaOSXnMLrfUfmFbNynRYjeMru/bhgAYRy/GQVI8gmRq7vm9V9c2gGVYnYoQ008X6YTmRIu5b0397U7vb0bIA==", + "license": "MIT", + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/mlly": { + "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.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.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/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "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": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "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": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.7.tgz", + "integrity": "sha512-eMJxgjRzBaj3olkP4cBamHDXL79A8FC6u1GcsO1D1Tsx8bw/LLXUJCaoajVxtnhD3A1IJqIT8IcRJjgBIPJq4w==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.7", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.7", + "@next/swc-darwin-x64": "16.2.7", + "@next/swc-linux-arm64-gnu": "16.2.7", + "@next/swc-linux-arm64-musl": "16.2.7", + "@next/swc-linux-x64-gnu": "16.2.7", + "@next/swc-linux-x64-musl": "16.2.7", + "@next/swc-win32-arm64-msvc": "16.2.7", + "@next/swc-win32-x64-msvc": "16.2.7", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "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", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "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", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/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==", + "license": "MIT" + }, + "node_modules/ora/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-paths": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz", + "integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==", + "license": "MIT", + "engines": { + "node": ">= 6.0" + } + }, + "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==", + "dev": true, + "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/p-cancelable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/p-event": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", + "license": "MIT", + "peer": true, + "dependencies": { + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "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/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/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", + "peer": true + }, + "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/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": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/piscina": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.9.2.tgz", + "integrity": "sha512-Fq0FERJWFEUpB4eSY59wSNwXD4RYqR+nR/WiEVcZW8IWfVBxJJafcgTEZDQo8k3w0sUarJ8RyVbbUF4GQ2LGbQ==", + "license": "MIT", + "peer": true, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.1" + } + }, + "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", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postal-mime": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/postal-mime/-/postal-mime-2.7.4.tgz", + "integrity": "sha512-0WdnFQYUrPGGTFu1uOqD2s7omwua8xaeYGdO6rb88oD5yJ/4pPHDA4sdWqfD8wQVfCny563n/HQS7zTFft+f/g==", + "license": "MIT-0" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "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": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "github", + "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/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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": { + "defu": "^6.1.6", + "destr": "^2.0.5" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "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", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0", + "peer": 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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resend": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.12.4.tgz", + "integrity": "sha512-lRpJ2Hxd+ht+JPDm97juRcUp9HOMuZyxaRFRFmc9Tx8iNWiei94Dx9v6SWufgKk2667C/uCeKKspMotOHSpCSg==", + "license": "MIT", + "dependencies": { + "postal-mime": "2.7.4", + "standardwebhooks": "1.0.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@react-email/render": "*" + }, + "peerDependenciesMeta": { + "@react-email/render": { + "optional": true + } + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT", + "peer": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=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, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/responselike": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz", + "integrity": "sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==", + "license": "MIT", + "peer": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "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==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "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==", + "dev": true, + "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", + "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/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "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/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "license": "MIT" + }, + "node_modules/seek-bzip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-2.0.0.tgz", + "integrity": "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==", + "license": "MIT", + "peer": true, + "dependencies": { + "commander": "^6.0.0" + }, + "bin": { + "seek-bunzip": "bin/seek-bunzip", + "seek-table": "bin/seek-bzip-table" + } + }, + "node_modules/seek-bzip/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "license": "MIT", + "peer": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate/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", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "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", + "optional": true, + "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/sharp/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", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/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": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "license": "MIT", + "peer": true, + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys/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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "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/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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", + "peer": true, + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "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/string-width/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/string-width/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-3.0.0.tgz", + "integrity": "sha512-I0sdgcFTfKQlUPZyAqPJmSG3HLO9rWDFnxonnIbskYNM3DwFOeTNB5KzVq3dA1GdRAc/25b5Y7UO2TQfKWw4aQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "inspect-with-kind": "^1.0.5", + "is-plain-obj": "^1.1.0" + } + }, + "node_modules/strip-dirs/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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/super-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.1.0.tgz", + "integrity": "sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "function-timeout": "^1.0.1", + "make-asynchronous": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/supports-hyperlinks": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz", + "integrity": "sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==", + "license": "MIT", + "dependencies": { + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-hyperlinks/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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/system-architecture": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-1.0.0.tgz", + "integrity": "sha512-0OJWD12D7XX3KUg1DYkMaTTjSTo2k/mhIYI3HlBlceXSMcJhW/1qO735fPKS5prcyjvn57Ub151vvASYXpQrEw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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==", + "license": "MIT", + "peer": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/terminal-link": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-5.0.0.tgz", + "integrity": "sha512-qFAy10MTMwjzjU8U16YS4YoZD+NQLHzLssFMNqgravjbvIPNiqkGFR4yjhJfmY9R5OFU7+yHxc6y+uGHkKwLRA==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^4.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link/node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "peer": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT", + "peer": true + }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "license": "MIT", + "peer": true, + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=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==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "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/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": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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.60.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", + "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", + "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" + }, + "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 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "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/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ulid": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/ulid/-/ulid-3.0.2.tgz", + "integrity": "sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w==", + "license": "MIT", + "bin": { + "ulid": "dist/cli.js" + } + }, + "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==", + "dev": true, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "license": "MIT", + "peer": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/unctx": { + "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.15.0", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21", + "unplugin": "^2.3.11" + } + }, + "node_modules/undici": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "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" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "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", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin/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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unrs-resolver": { + "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.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@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/untyped": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/untyped/-/untyped-2.0.0.tgz", + "integrity": "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "defu": "^6.1.4", + "jiti": "^2.4.2", + "knitwork": "^1.2.0", + "scule": "^1.3.0" + }, + "bin": { + "untyped": "dist/cli.mjs" + } + }, + "node_modules/update-browserslist-db": { + "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": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "optional": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-worker": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", + "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", + "license": "Apache-2.0", + "peer": true + }, + "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/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" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/workflow": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workflow/-/workflow-4.3.1.tgz", + "integrity": "sha512-G2NxBf9BVerh0/AA14Ona0zamjCjCFvYQ9+k3pMzRnet0A/qzXiRL6t29iLjfau9jEIvR9oaU+i+DXTvCj9JQQ==", + "license": "Apache-2.0", + "dependencies": { + "@workflow/astro": "4.0.8", + "@workflow/cli": "4.2.8", + "@workflow/core": "4.3.1", + "@workflow/errors": "4.1.3", + "@workflow/nest": "0.0.8", + "@workflow/next": "4.0.9", + "@workflow/nitro": "4.0.9", + "@workflow/nuxt": "4.0.9", + "@workflow/rollup": "4.0.8", + "@workflow/sveltekit": "4.0.8", + "@workflow/typescript-plugin": "4.0.2", + "@workflow/utils": "4.1.2", + "ms": "2.1.3" + }, + "bin": { + "wf": "bin/run.js", + "workflow": "bin/run.js" + }, + "peerDependencies": { + "@opentelemetry/api": "1" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/workflow/node_modules/@swc/cli": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.8.1.tgz", + "integrity": "sha512-L+ACCGHCiS0VqHVep/INLVnvRvJ2XooQFLZq4L8snhxw1jsqz+XRcY313UsyPVturPPE1shW3jic7rt3qEQTSQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "@xhmikosr/bin-wrapper": "^14.0.0", + "commander": "^8.3.0", + "minimatch": "^9.0.3", + "piscina": "^4.3.1", + "semver": "^7.3.8", + "slash": "3.0.0", + "source-map": "^0.7.3", + "tinyglobby": "^0.2.13" + }, + "bin": { + "spack": "bin/spack.js", + "swc": "bin/swc.js", + "swcx": "bin/swcx.js" + }, + "engines": { + "node": ">= 20.19.0" + }, + "peerDependencies": { + "@swc/core": "^1.2.66", + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/workflow/node_modules/@swc/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", + "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.3", + "@swc/core-darwin-x64": "1.15.3", + "@swc/core-linux-arm-gnueabihf": "1.15.3", + "@swc/core-linux-arm64-gnu": "1.15.3", + "@swc/core-linux-arm64-musl": "1.15.3", + "@swc/core-linux-x64-gnu": "1.15.3", + "@swc/core-linux-x64-musl": "1.15.3", + "@swc/core-win32-arm64-msvc": "1.15.3", + "@swc/core-win32-ia32-msvc": "1.15.3", + "@swc/core-win32-x64-msvc": "1.15.3" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/workflow/node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/workflow/node_modules/@workflow/nest": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@workflow/nest/-/nest-0.0.8.tgz", + "integrity": "sha512-3F7qb5KA7pm9tWiCqaBCY0Z736AvPq+t/8vhwrtg7VQ57M/6JPQdo21PBacQfUXpf6N36I0TPKH/tFrPYefHxA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/core": "1.15.3", + "@workflow/builders": "4.0.9", + "@workflow/swc-plugin": "4.1.1", + "pathe": "2.0.3" + }, + "bin": { + "workflow-nest": "dist/cli.js" + }, + "peerDependencies": { + "@nestjs/common": ">=10.0.0", + "@nestjs/core": ">=10.0.0", + "@swc/cli": ">=0.4.0", + "@swc/core": ">=1.5.0" + }, + "peerDependenciesMeta": { + "@nestjs/common": { + "optional": false + }, + "@nestjs/core": { + "optional": false + }, + "@swc/cli": { + "optional": false + }, + "@swc/core": { + "optional": false + } + } + }, + "node_modules/workflow/node_modules/@workflow/swc-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@workflow/swc-plugin/-/swc-plugin-4.1.1.tgz", + "integrity": "sha512-Bi1K/z7Fjxzf5DY9BCBZHMd6Y4SvuCPOAyslydcDD9m38Suz3xCcfrEDvXo8R5mnEnTuLIB4GEJyB54CkMuuiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@swc/core": "1.15.3" + } + }, + "node_modules/workflow/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", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/workflow/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/workflow/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", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/workflow/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/workflow/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", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/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==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-app-paths": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.1.0.tgz", + "integrity": "sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==", + "license": "MIT", + "dependencies": { + "xdg-portable": "^7.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/xdg-portable": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz", + "integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==", + "license": "MIT", + "dependencies": { + "os-paths": "^4.0.1" + }, + "engines": { + "node": ">= 6.0" + } + }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "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/yauzl": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.3.2.tgz", + "integrity": "sha512-Md9ankxxN23wncAN8s7+Tn3Co52zLUPMtnrLAbVCnfG5d2tKBFfmygYSgXlqFgXObtzIgqkx7aNgDBpso9+4qA==", + "license": "MIT", + "peer": true, + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "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/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/examples/workflow-email-onboarding/package.json b/examples/workflow-email-onboarding/package.json new file mode 100644 index 0000000000..e5741e4b88 --- /dev/null +++ b/examples/workflow-email-onboarding/package.json @@ -0,0 +1,26 @@ +{ + "name": "workflow-email-onboarding", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "next": "16.2.7", + "react": "19.2.4", + "react-dom": "19.2.4", + "resend": "^6.12.4", + "workflow": "^4.3.1" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.7", + "typescript": "^5" + } +} diff --git a/examples/workflow-email-onboarding/public/file.svg b/examples/workflow-email-onboarding/public/file.svg new file mode 100644 index 0000000000..004145cddf --- /dev/null +++ b/examples/workflow-email-onboarding/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/workflow-email-onboarding/public/globe.svg b/examples/workflow-email-onboarding/public/globe.svg new file mode 100644 index 0000000000..567f17b0d7 --- /dev/null +++ b/examples/workflow-email-onboarding/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/workflow-email-onboarding/public/next.svg b/examples/workflow-email-onboarding/public/next.svg new file mode 100644 index 0000000000..5174b28c56 --- /dev/null +++ b/examples/workflow-email-onboarding/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/workflow-email-onboarding/public/vercel.svg b/examples/workflow-email-onboarding/public/vercel.svg new file mode 100644 index 0000000000..7705396033 --- /dev/null +++ b/examples/workflow-email-onboarding/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/workflow-email-onboarding/public/window.svg b/examples/workflow-email-onboarding/public/window.svg new file mode 100644 index 0000000000..b2b2a44f6e --- /dev/null +++ b/examples/workflow-email-onboarding/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/workflow-email-onboarding/src/app/api/signup/route.ts b/examples/workflow-email-onboarding/src/app/api/signup/route.ts new file mode 100644 index 0000000000..1cf8ca3976 --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/api/signup/route.ts @@ -0,0 +1,18 @@ +import { start } from "workflow/api"; +import { NextResponse } from "next/server"; +import { userSignup } from "@/workflows/user-signup"; + +export async function POST(request: Request) { + const { email } = await request.json(); + + if (typeof email !== "string" || !email.includes("@")) { + return NextResponse.json({ error: "Valid email is required" }, { status: 400 }); + } + + const run = await start(userSignup, [email]); + + return NextResponse.json({ + message: "User signup workflow started", + runId: run.runId, + }); +} diff --git a/examples/workflow-email-onboarding/src/app/api/welcome/route.ts b/examples/workflow-email-onboarding/src/app/api/welcome/route.ts new file mode 100644 index 0000000000..ccd6e63357 --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/api/welcome/route.ts @@ -0,0 +1,18 @@ +import { start } from "workflow/api"; +import { NextResponse } from "next/server"; +import { welcome } from "@/workflows/welcome"; + +export async function POST(request: Request) { + const { userId } = await request.json(); + + if (typeof userId !== "string" || userId.length === 0) { + return NextResponse.json({ error: "userId is required" }, { status: 400 }); + } + + const run = await start(welcome, [userId]); + + return NextResponse.json({ + message: "Welcome workflow started", + runId: run.runId, + }); +} diff --git a/examples/workflow-email-onboarding/src/app/favicon.ico b/examples/workflow-email-onboarding/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/examples/workflow-email-onboarding/src/app/globals.css b/examples/workflow-email-onboarding/src/app/globals.css new file mode 100644 index 0000000000..4c18fb3b42 --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/globals.css @@ -0,0 +1,49 @@ +:root { + --background: #ffffff; + --foreground: #171717; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +html { + height: 100%; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + min-height: 100%; + display: flex; + flex-direction: column; + color: var(--foreground); + background: var(--background); + font-family: Arial, Helvetica, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +a { + color: inherit; + text-decoration: none; +} + +@media (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } +} diff --git a/examples/workflow-email-onboarding/src/app/layout.tsx b/examples/workflow-email-onboarding/src/app/layout.tsx new file mode 100644 index 0000000000..1da6a2fa9f --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/layout.tsx @@ -0,0 +1,30 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} diff --git a/examples/workflow-email-onboarding/src/app/page.module.css b/examples/workflow-email-onboarding/src/app/page.module.css new file mode 100644 index 0000000000..643fe27de0 --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/page.module.css @@ -0,0 +1,142 @@ +.page { + --background: #fafafa; + --foreground: #fff; + + --text-primary: #000; + --text-secondary: #666; + + --button-primary-hover: #383838; + --button-secondary-hover: #f2f2f2; + --button-secondary-border: #ebebeb; + + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + font-family: var(--font-geist-sans); + background-color: var(--background); +} + +.main { + display: flex; + flex: 1; + width: 100%; + max-width: 800px; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; + background-color: var(--foreground); + padding: 120px 60px; +} + +.intro { + display: flex; + flex-direction: column; + align-items: flex-start; + text-align: left; + gap: 24px; +} + +.intro h1 { + max-width: 320px; + font-size: 40px; + font-weight: 600; + line-height: 48px; + letter-spacing: -2.4px; + text-wrap: balance; + color: var(--text-primary); +} + +.intro p { + max-width: 440px; + font-size: 18px; + line-height: 32px; + text-wrap: balance; + color: var(--text-secondary); +} + +.intro a { + font-weight: 500; + color: var(--text-primary); +} + +.ctas { + display: flex; + flex-direction: row; + width: 100%; + max-width: 440px; + gap: 16px; + font-size: 14px; +} + +.ctas a { + display: flex; + justify-content: center; + align-items: center; + height: 40px; + padding: 0 16px; + border-radius: 128px; + border: 1px solid transparent; + transition: 0.2s; + cursor: pointer; + width: fit-content; + font-weight: 500; +} + +a.primary { + background: var(--text-primary); + color: var(--background); + gap: 8px; +} + +a.secondary { + border-color: var(--button-secondary-border); +} + +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + a.primary:hover { + background: var(--button-primary-hover); + border-color: transparent; + } + + a.secondary:hover { + background: var(--button-secondary-hover); + border-color: transparent; + } +} + +@media (max-width: 600px) { + .main { + padding: 48px 24px; + } + + .intro { + gap: 16px; + } + + .intro h1 { + font-size: 32px; + line-height: 40px; + letter-spacing: -1.92px; + } +} + +@media (prefers-color-scheme: dark) { + .logo { + filter: invert(); + } + + .page { + --background: #000; + --foreground: #000; + + --text-primary: #ededed; + --text-secondary: #999; + + --button-primary-hover: #ccc; + --button-secondary-hover: #1a1a1a; + --button-secondary-border: #1a1a1a; + } +} diff --git a/examples/workflow-email-onboarding/src/app/page.tsx b/examples/workflow-email-onboarding/src/app/page.tsx new file mode 100644 index 0000000000..7b947a2d9e --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/page.tsx @@ -0,0 +1,66 @@ +import Image from "next/image"; +import styles from "./page.module.css"; + +export default function Home() { + return ( +
+
+ Next.js logo +
+

To get started, edit the page.tsx file.

+

+ Looking for a starting point or more instructions? Head over to{" "} + + Templates + {" "} + or the{" "} + + Learning + {" "} + center. +

+
+ +
+
+ ); +} diff --git a/examples/workflow-email-onboarding/src/workflows/steps.ts b/examples/workflow-email-onboarding/src/workflows/steps.ts new file mode 100644 index 0000000000..ad950cd81f --- /dev/null +++ b/examples/workflow-email-onboarding/src/workflows/steps.ts @@ -0,0 +1,120 @@ +import { FatalError } from "workflow"; +import { Resend } from "resend"; + +export type User = { + id: string; + email: string; + name: string; + plan: string; +}; + +function getResendClient() { + const apiKey = process.env.RESEND_API_KEY; + if (!apiKey) { + throw new FatalError("RESEND_API_KEY is not configured"); + } + + return new Resend(apiKey); +} + +export async function createUser(email: string) { + "use step"; + + console.log(`Creating user with email: ${email}`); + + return { + id: crypto.randomUUID(), + email, + name: email.split("@")[0] ?? "friend", + plan: "free", + } satisfies User; +} + +export async function getUser(userId: string) { + "use step"; + + console.log(`Fetching user: ${userId}`); + + // Replace with your database lookup. + return { + id: userId, + email: "hello@example.com", + name: "Alex", + plan: "pro", + } satisfies User; +} + +export async function generateEmail(input: { name: string; plan: string }) { + "use step"; + + console.log(`Generating email for ${input.name} (${input.plan})`); + + return { + subject: `Welcome to Acme, ${input.name}!`, + body: `

Thanks for joining Acme on the ${input.plan} plan.

`, + }; +} + +export async function sendEmail(input: { + to: string; + subject: string; + body: string; +}) { + "use step"; + + console.log(`Sending email to ${input.to}: ${input.subject}`); + + const resend = getResendClient(); + const resp = await resend.emails.send({ + from: process.env.RESEND_FROM ?? "Acme ", + to: [input.to], + subject: input.subject, + html: input.body, + }); + + if (resp.error) { + throw new FatalError(resp.error.message); + } + + return { status: "sent" as const, id: resp.data?.id }; +} + +export async function sendWelcomeEmail(email: string) { + "use step"; + + console.log(`Sending welcome email to ${email}`); + + const resend = getResendClient(); + const resp = await resend.emails.send({ + from: process.env.RESEND_FROM ?? "Acme ", + to: [email], + subject: "Welcome!", + html: "Thanks for joining Acme.", + }); + + if (resp.error) { + throw new FatalError(resp.error.message); + } + + return { status: "sent" as const, id: resp.data?.id }; +} + +export async function sendOneWeekCheckInEmail(email: string) { + "use step"; + + console.log(`Sending one-week check-in email to ${email}`); + + const resend = getResendClient(); + const resp = await resend.emails.send({ + from: process.env.RESEND_FROM ?? "Acme ", + to: [email], + subject: "How is your first week going?", + html: "We hope Acme is working well for you. Reply if you need help.", + }); + + if (resp.error) { + throw new FatalError(resp.error.message); + } + + return { status: "sent" as const, id: resp.data?.id }; +} diff --git a/examples/workflow-email-onboarding/src/workflows/user-signup.ts b/examples/workflow-email-onboarding/src/workflows/user-signup.ts new file mode 100644 index 0000000000..484ad6ca9b --- /dev/null +++ b/examples/workflow-email-onboarding/src/workflows/user-signup.ts @@ -0,0 +1,23 @@ +import { sleep } from "workflow"; +import { + createUser, + sendOneWeekCheckInEmail, + sendWelcomeEmail, +} from "@/workflows/steps"; + +export async function userSignup(email: string) { + "use workflow"; + + console.log(`Starting signup workflow for ${email}`); + + const user = await createUser(email); + await sendWelcomeEmail(email); + + // Pause for 7 days without consuming compute resources. + await sleep("7 days"); + await sendOneWeekCheckInEmail(email); + + console.log(`Signup workflow complete for ${user.id}`); + + return { userId: user.id, status: "done" as const }; +} diff --git a/examples/workflow-email-onboarding/src/workflows/welcome.ts b/examples/workflow-email-onboarding/src/workflows/welcome.ts new file mode 100644 index 0000000000..c3fe63491e --- /dev/null +++ b/examples/workflow-email-onboarding/src/workflows/welcome.ts @@ -0,0 +1,22 @@ +import { + generateEmail, + getUser, + sendEmail, +} from "@/workflows/steps"; + +export async function welcome(userId: string) { + "use workflow"; + + const user = await getUser(userId); + const { subject, body } = await generateEmail({ + name: user.name, + plan: user.plan, + }); + const { status } = await sendEmail({ + to: user.email, + subject, + body, + }); + + return { status, subject, body }; +} diff --git a/examples/workflow-email-onboarding/tsconfig.json b/examples/workflow-email-onboarding/tsconfig.json new file mode 100644 index 0000000000..7303717a7f --- /dev/null +++ b/examples/workflow-email-onboarding/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + }, + { + "name": "workflow" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} From 7836e3941833e721982152ea9930c901a98a7ef4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Jun 2026 14:36:52 +0000 Subject: [PATCH 05/15] Align workflow signup example with official handleUserSignup pattern Update the email onboarding example to match the Workflow DevKit getting-started guide: rename userSignup to handleUserSignup, use a 5s sleep delay, pass the user object to email steps, and rename the follow-up step to sendOnboardingEmail. Co-authored-by: Mohamed --- examples/workflow-email-onboarding/README.md | 6 +++--- .../src/app/api/signup/route.ts | 4 ++-- .../src/workflows/steps.ts | 20 +++++++++++-------- .../src/workflows/user-signup.ts | 16 +++++++-------- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/examples/workflow-email-onboarding/README.md b/examples/workflow-email-onboarding/README.md index cb24a76289..eed4359a79 100644 --- a/examples/workflow-email-onboarding/README.md +++ b/examples/workflow-email-onboarding/README.md @@ -36,7 +36,7 @@ Optional: npm run dev ``` -Trigger the signup workflow (welcome email now, check-in after 7 days): +Trigger the signup workflow (welcome email now, onboarding email after 5 seconds): ```bash curl -X POST --json '{"email":"hello@example.com"}' http://localhost:3000/api/signup @@ -59,7 +59,7 @@ npx workflow inspect runs ### Workflow orchestration -`src/workflows/user-signup.ts` creates a user, sends a welcome email, sleeps for 7 days without holding a server open, then sends a follow-up email. +`src/workflows/user-signup.ts` creates a user, sends a welcome email, sleeps for 5 seconds without holding a server open, then sends an onboarding email. ### Step functions with Resend @@ -82,6 +82,6 @@ src/ welcome/route.ts # POST /api/welcome workflows/ steps.ts # "use step" functions (Resend, user lookup) - user-signup.ts # 7-day onboarding workflow + user-signup.ts # signup onboarding workflow (5s delay) welcome.ts # personalized welcome workflow ``` diff --git a/examples/workflow-email-onboarding/src/app/api/signup/route.ts b/examples/workflow-email-onboarding/src/app/api/signup/route.ts index 1cf8ca3976..a67b5d1810 100644 --- a/examples/workflow-email-onboarding/src/app/api/signup/route.ts +++ b/examples/workflow-email-onboarding/src/app/api/signup/route.ts @@ -1,6 +1,6 @@ import { start } from "workflow/api"; import { NextResponse } from "next/server"; -import { userSignup } from "@/workflows/user-signup"; +import { handleUserSignup } from "@/workflows/user-signup"; export async function POST(request: Request) { const { email } = await request.json(); @@ -9,7 +9,7 @@ export async function POST(request: Request) { return NextResponse.json({ error: "Valid email is required" }, { status: 400 }); } - const run = await start(userSignup, [email]); + const run = await start(handleUserSignup, [email]); return NextResponse.json({ message: "User signup workflow started", diff --git a/examples/workflow-email-onboarding/src/workflows/steps.ts b/examples/workflow-email-onboarding/src/workflows/steps.ts index ad950cd81f..b4bc180486 100644 --- a/examples/workflow-email-onboarding/src/workflows/steps.ts +++ b/examples/workflow-email-onboarding/src/workflows/steps.ts @@ -79,15 +79,15 @@ export async function sendEmail(input: { return { status: "sent" as const, id: resp.data?.id }; } -export async function sendWelcomeEmail(email: string) { +export async function sendWelcomeEmail(user: Pick) { "use step"; - console.log(`Sending welcome email to ${email}`); + console.log(`Sending welcome email to user: ${user.id}`); const resend = getResendClient(); const resp = await resend.emails.send({ from: process.env.RESEND_FROM ?? "Acme ", - to: [email], + to: [user.email], subject: "Welcome!", html: "Thanks for joining Acme.", }); @@ -99,17 +99,21 @@ export async function sendWelcomeEmail(email: string) { return { status: "sent" as const, id: resp.data?.id }; } -export async function sendOneWeekCheckInEmail(email: string) { +export async function sendOnboardingEmail(user: Pick) { "use step"; - console.log(`Sending one-week check-in email to ${email}`); + if (!user.email.includes("@")) { + throw new FatalError("Invalid email"); + } + + console.log(`Sending onboarding email to user: ${user.id}`); const resend = getResendClient(); const resp = await resend.emails.send({ from: process.env.RESEND_FROM ?? "Acme ", - to: [email], - subject: "How is your first week going?", - html: "We hope Acme is working well for you. Reply if you need help.", + to: [user.email], + subject: "Get started with Acme", + html: "Here are a few tips to help you get the most out of Acme.", }); if (resp.error) { diff --git a/examples/workflow-email-onboarding/src/workflows/user-signup.ts b/examples/workflow-email-onboarding/src/workflows/user-signup.ts index 484ad6ca9b..3ade241bf9 100644 --- a/examples/workflow-email-onboarding/src/workflows/user-signup.ts +++ b/examples/workflow-email-onboarding/src/workflows/user-signup.ts @@ -1,23 +1,23 @@ import { sleep } from "workflow"; import { createUser, - sendOneWeekCheckInEmail, + sendOnboardingEmail, sendWelcomeEmail, } from "@/workflows/steps"; -export async function userSignup(email: string) { +export async function handleUserSignup(email: string) { "use workflow"; console.log(`Starting signup workflow for ${email}`); const user = await createUser(email); - await sendWelcomeEmail(email); + await sendWelcomeEmail(user); - // Pause for 7 days without consuming compute resources. - await sleep("7 days"); - await sendOneWeekCheckInEmail(email); + await sleep("5s"); - console.log(`Signup workflow complete for ${user.id}`); + await sendOnboardingEmail(user); - return { userId: user.id, status: "done" as const }; + console.log("Workflow is complete! Run 'npx workflow web' to inspect your run"); + + return { userId: user.id, status: "onboarded" as const }; } From ed1f474bdcc5edd84acf22bb0c466a64ead96a73 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 3 Jun 2026 00:57:42 +0000 Subject: [PATCH 06/15] Fix Cloud Agent startup by adding environment config Cursor Cloud Agents were failing with 'Failed to fetch branch/tag ref Blueprint' because no Blueprint branch existed on GitHub. The Blueprint branch has been created separately to track main. Add .cursor/environment.json so agents resolve environment config from the repository and pre-install Go module dependencies on startup. Co-authored-by: Mohamed --- .cursor/environment.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .cursor/environment.json diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 0000000000..299d049a07 --- /dev/null +++ b/.cursor/environment.json @@ -0,0 +1,3 @@ +{ + "install": "go mod download" +} From ddc988fd6f0f85ece708c64882ae065bf074c604 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 3 Jun 2026 00:59:47 +0000 Subject: [PATCH 07/15] Document Cloud Agent branch naming to prevent ref resolution errors Use blueprint/-ee50 for feature branches and Blueprint or main as the base branch. Ambiguous Th_Blueprint-prefixed names without a slash can be misread as ref Blueprint during Cloud Agent startup. Co-authored-by: Mohamed --- AGENTS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 140d876cb9..d51afe060c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,3 +22,10 @@ See `.github/copilot-instructions.md` for full contributor workflow, project str - `script/lint` auto-downloads `golangci-lint` v2.5.0 to `bin/` on first run. This is cached across runs. - The `github-mcp-server` binary is gitignored. Build it fresh with `go build ./cmd/github-mcp-server`. - All lint/test/build commands are fast (~1-2s each when cached). + +### Cloud Agent git branches + +Cursor Cloud Agents must use an existing ref for checkout and PR base: + +- **Base branch:** `Blueprint` (tracks `main`) or `main` directly. Do not use a bare `Blueprint` prefix parsed from feature branch names. +- **Feature branches:** use `blueprint/-ee50` (slash-separated). Avoid `Th_Blueprint` names without a separator — they can be misread as ref `Blueprint` and cause startup failures. From 46b3a9a895333f9ce234973dfbf312c61fdb9b6b Mon Sep 17 00:00:00 2001 From: Vercel Date: Thu, 4 Jun 2026 18:52:17 +0000 Subject: [PATCH 08/15] Install and Configure Vercel Speed Insights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Vercel Speed Insights Installation Report ## Summary Successfully installed and configured Vercel Speed Insights for the Next.js application in the examples/workflow-email-onboarding directory. ## Changes Made ### 1. Package Installation - **File Modified**: `examples/workflow-email-onboarding/package.json` - **Change**: Added `@vercel/speed-insights` version ^2.0.0 to dependencies - **Lock File Updated**: `examples/workflow-email-onboarding/package-lock.json` (801 packages installed) ### 2. SpeedInsights Component Integration - **File Modified**: `examples/workflow-email-onboarding/src/app/layout.tsx` - **Changes**: - Added import: `import { SpeedInsights } from "@vercel/speed-insights/next";` - Added `` component inside the `` tag after children - Followed Next.js App Router conventions as specified in the official Vercel documentation ## Implementation Details The implementation follows the official Vercel Speed Insights quickstart guide for Next.js v13.5+: - Used the Next.js-specific package import path: `@vercel/speed-insights/next` - Placed the component in the root layout file for application-wide coverage - Component is rendered after children as recommended in the documentation ## Verification Steps Completed ✅ **Build Test**: Successfully built the Next.js application with no errors ✅ **Linter Check**: Ran ESLint - no new errors introduced (only pre-existing warnings unrelated to our changes) ✅ **Dependencies**: All dependencies installed correctly via npm ✅ **Lock File**: package-lock.json updated and included in the changes ## Technical Specifications - **Framework**: Next.js 16.2.7 (App Router) - **Package Manager**: npm - **Speed Insights Version**: 2.0.0 - **Package Type**: @vercel/speed-insights/next (Next.js-specific implementation) ## Notes - The Speed Insights component will automatically track Core Web Vitals and other performance metrics when the application is deployed to Vercel - No additional configuration is required - the component works out of the box - The implementation preserves all existing code structure and functionality - No breaking changes were introduced ## Next Steps To enable Speed Insights on Vercel: 1. Deploy the application to Vercel 2. Navigate to the Vercel dashboard 3. Select "Speed Insights" from the sidebar 4. Choose the project and click "Enable" 5. After user visits, performance metrics will be visible in the dashboard Co-authored-by: Vercel --- .../package-lock.json | 39 +++++++++++++++++++ .../workflow-email-onboarding/package.json | 1 + .../src/app/layout.tsx | 6 ++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/examples/workflow-email-onboarding/package-lock.json b/examples/workflow-email-onboarding/package-lock.json index 8bff259be5..25d65068d7 100644 --- a/examples/workflow-email-onboarding/package-lock.json +++ b/examples/workflow-email-onboarding/package-lock.json @@ -8,6 +8,7 @@ "name": "workflow-email-onboarding", "version": "0.1.0", "dependencies": { + "@vercel/speed-insights": "^2.0.0", "next": "16.2.7", "react": "19.2.4", "react-dom": "19.2.4", @@ -3726,6 +3727,44 @@ "node": ">=20.0.0" } }, + "node_modules/@vercel/speed-insights": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-2.0.0.tgz", + "integrity": "sha512-jwkNcrTeafWxjmWq4AHBaptSqZiJkYU5adLC9QBSqeim0GcqDMgN5Ievh8OG1rJ6W3A4l1oiP7qr9CWxGuzu3w==", + "license": "Apache-2.0", + "peerDependencies": { + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "nuxt": ">= 3", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "nuxt": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } + } + }, "node_modules/@workflow/astro": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/@workflow/astro/-/astro-4.0.8.tgz", diff --git a/examples/workflow-email-onboarding/package.json b/examples/workflow-email-onboarding/package.json index e5741e4b88..fc1c68d4b7 100644 --- a/examples/workflow-email-onboarding/package.json +++ b/examples/workflow-email-onboarding/package.json @@ -9,6 +9,7 @@ "lint": "eslint" }, "dependencies": { + "@vercel/speed-insights": "^2.0.0", "next": "16.2.7", "react": "19.2.4", "react-dom": "19.2.4", diff --git a/examples/workflow-email-onboarding/src/app/layout.tsx b/examples/workflow-email-onboarding/src/app/layout.tsx index 1da6a2fa9f..0809044664 100644 --- a/examples/workflow-email-onboarding/src/app/layout.tsx +++ b/examples/workflow-email-onboarding/src/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; +import { SpeedInsights } from "@vercel/speed-insights/next"; import "./globals.css"; const geistSans = Geist({ @@ -24,7 +25,10 @@ export default function RootLayout({ }>) { return ( - {children} + + {children} + + ); } From 688095e4018371b9f67d2293241d8e6957c3b2b3 Mon Sep 17 00:00:00 2001 From: v0agent Date: Thu, 4 Jun 2026 19:07:00 +0000 Subject: [PATCH 09/15] feat: add new fix guide and index pages with metadata and icons Co-authored-by: Mohamed <134189886+garlobrian52@users.noreply.github.com> --- app/fixes/[slug]/page.tsx | 108 +++ app/fixes/page.tsx | 88 ++ app/globals.css | 44 + app/layout.tsx | 30 + app/page.tsx | 147 ++++ lib/fixes.ts | 107 +++ next-env.d.ts | 6 + next.config.ts | 5 + package-lock.json | 1745 +++++++++++++++++++++++++++++++++++++ package.json | 25 + pnpm-lock.yaml | 989 +++++++++++++++++++++ postcss.config.mjs | 7 + tsconfig.json | 27 + 13 files changed, 3328 insertions(+) create mode 100644 app/fixes/[slug]/page.tsx create mode 100644 app/fixes/page.tsx create mode 100644 app/globals.css create mode 100644 app/layout.tsx create mode 100644 app/page.tsx create mode 100644 lib/fixes.ts create mode 100644 next-env.d.ts create mode 100644 next.config.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 postcss.config.mjs create mode 100644 tsconfig.json diff --git a/app/fixes/[slug]/page.tsx b/app/fixes/[slug]/page.tsx new file mode 100644 index 0000000000..6368f6b98e --- /dev/null +++ b/app/fixes/[slug]/page.tsx @@ -0,0 +1,108 @@ +import Link from "next/link" +import { notFound } from "next/navigation" +import { FIXES, getFixBySlug } from "@/lib/fixes" +import { ArrowLeft, CheckCircle2 } from "lucide-react" + +type Props = { params: Promise<{ slug: string }> } + +export async function generateStaticParams() { + return FIXES.map((f) => ({ slug: f.slug })) +} + +export async function generateMetadata({ params }: Props) { + const { slug } = await params + const fix = getFixBySlug(slug) + if (!fix) return { title: "Fix not found — FixNow" } + return { + title: `${fix.title} — FixNow`, + description: fix.description, + } +} + +export default async function FixGuidePage({ params }: Props) { + const { slug } = await params + const fix = getFixBySlug(slug) + if (!fix) notFound() + + return ( +
+
+
+ + FixNow + + +
+
+ +
+
+ + + All fixes + + +
+ + {fix.duration} + +

+ {fix.title} +

+

+ {fix.description} +

+
+ +
    + {fix.steps.map((step, i) => ( +
  1. +
    + {i + 1} +
    +

    {step}

    +
  2. + ))} +
+ +
+
+ +
+

{"That's it!"}

+

+ If you followed these steps, your issue should be resolved. Still stuck?{" "} + + Try another fix + + . +

+
+
+
+
+
+ +
+ + FixNow + + {" · "} + {new Date().getFullYear()} +
+
+ ) +} diff --git a/app/fixes/page.tsx b/app/fixes/page.tsx new file mode 100644 index 0000000000..8e6ecb5006 --- /dev/null +++ b/app/fixes/page.tsx @@ -0,0 +1,88 @@ +import Link from "next/link" +import { FIXES, fixHref } from "@/lib/fixes" +import { Wifi, Monitor, Smartphone, Printer, KeyRound, Tv } from "lucide-react" + +const categoryIcons = { + wifi: Wifi, + computer: Monitor, + phone: Smartphone, + printer: Printer, + account: KeyRound, + streaming: Tv, +} + +export const metadata = { + title: "All fixes — FixNow", + description: "Browse step-by-step guides for everyday tech problems.", +} + +export default function FixesIndexPage() { + return ( +
+
+
+ + FixNow + + +
+
+ +
+
+

+ All fixes +

+

+ Pick a problem and follow clear steps written for normal humans. +

+
    + {FIXES.map((fix) => { + const Icon = categoryIcons[fix.category] + return ( +
  • + +
    + +
    +
    +
    + + {fix.title} + + + {fix.duration} + +
    +

    + {fix.description} +

    +
    + +
  • + ) + })} +
+
+
+ +
+ + FixNow + + {" · "} + {new Date().getFullYear()} +
+
+ ) +} diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000000..c570643910 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,44 @@ +@import "tailwindcss"; + +:root { + --background: oklch(0.99 0 0); + --foreground: oklch(0.15 0 0); + --muted: oklch(0.95 0 0); + --muted-foreground: oklch(0.45 0 0); + --border: oklch(0.90 0 0); + --primary: oklch(0.55 0.25 145); + --primary-foreground: oklch(1 0 0); + --secondary: oklch(0.96 0 0); + --secondary-foreground: oklch(0.15 0 0); + --accent: oklch(0.55 0.25 145); + --accent-foreground: oklch(1 0 0); + --destructive: oklch(0.55 0.2 25); + --destructive-foreground: oklch(1 0 0); + --radius: 0.625rem; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: oklch(0.12 0 0); + --foreground: oklch(0.95 0 0); + --muted: oklch(0.20 0 0); + --muted-foreground: oklch(0.65 0 0); + --border: oklch(0.25 0 0); + --primary: oklch(0.65 0.25 145); + --primary-foreground: oklch(0.12 0 0); + --secondary: oklch(0.18 0 0); + --secondary-foreground: oklch(0.95 0 0); + --accent: oklch(0.65 0.25 145); + --accent-foreground: oklch(0.12 0 0); + } +} + +* { + border-color: var(--border); +} + +body { + background: var(--background); + color: var(--foreground); + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000000..006b7556c6 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,30 @@ +import type { Metadata, Viewport } from "next" +import "./globals.css" + +export const metadata: Metadata = { + title: "FixNow — Quick fixes for everyday tech problems", + description: + "Step-by-step guides to fix Wi-Fi, slow computers, phone issues, printers, and more. No jargon, just solutions.", +} + +export const viewport: Viewport = { + width: "device-width", + initialScale: 1, + maximumScale: 1, + themeColor: [ + { media: "(prefers-color-scheme: light)", color: "#ffffff" }, + { media: "(prefers-color-scheme: dark)", color: "#1a1a1a" }, + ], +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000000..5bd68cc418 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,147 @@ +import Link from "next/link" +import { FIXES, fixHref, FOOTER_FIX_LINKS } from "@/lib/fixes" +import { Wifi, Monitor, Smartphone, Printer, KeyRound, Tv } from "lucide-react" + +const categoryIcons = { + wifi: Wifi, + computer: Monitor, + phone: Smartphone, + printer: Printer, + account: KeyRound, + streaming: Tv, +} + +export default function HomePage() { + return ( +
+
+
+ + FixNow + + +
+
+ +
+ {/* Hero */} +
+
+

+ Fix your tech in minutes +

+

+ Step-by-step guides for everyday problems. No jargon, no phone trees, just solutions. +

+
+ + Fix something now + +
+
+
+ + {/* Fix Grid */} +
+
+

+ Common fixes +

+
+ {FIXES.map((fix) => { + const Icon = categoryIcons[fix.category] + return ( + +
+
+ +
+ + {fix.duration} + +
+
+

+ {fix.title} +

+

+ {fix.description} +

+
+ + ) + })} +
+
+ + See all fixes + +
+
+
+
+ + {/* Footer */} +
+
+
+
+

FixNow

+

+ Quick fixes for everyday tech problems. +

+
+
+

Popular Fixes

+
    + {FOOTER_FIX_LINKS.map((link) => ( +
  • + + {link.label} + +
  • + ))} +
+
+
+

Resources

+
    +
  • + + All Fixes + +
  • +
+
+
+
+ {new Date().getFullYear()} FixNow +
+
+
+
+ ) +} diff --git a/lib/fixes.ts b/lib/fixes.ts new file mode 100644 index 0000000000..36e0721e80 --- /dev/null +++ b/lib/fixes.ts @@ -0,0 +1,107 @@ +export type FixGuide = { + slug: string + title: string + description: string + duration: string + category: "wifi" | "computer" | "phone" | "printer" | "account" | "streaming" + steps: string[] +} + +export const FIXES: FixGuide[] = [ + { + slug: "slow-wifi", + title: "Slow or dropping Wi-Fi", + description: + "Reset the right way, find dead zones, and stop buffering for good.", + duration: "3 min fix", + category: "wifi", + steps: [ + "Restart your router and modem (unplug both, wait 30 seconds, plug modem first).", + "Move closer to the router or reduce interference from microwaves and baby monitors.", + "Forget and reconnect to your network on the device that drops.", + "If speeds are still low, run a speed test and contact your ISP if you're far below your plan.", + ], + }, + { + slug: "sluggish-computer", + title: "Sluggish computer", + description: "Free up storage, kill background hogs, and bring back the speed.", + duration: "5 min fix", + category: "computer", + steps: [ + "Close apps you're not using and check Task Manager / Activity Monitor for high CPU or memory.", + "Free at least 10-15% of disk space by emptying trash and removing large downloads.", + "Disable unnecessary startup programs.", + "Install pending OS and browser updates, then restart once.", + ], + }, + { + slug: "phone-acting-up", + title: "Phone acting up", + description: "Battery drain, full storage, crashing apps - sorted step by step.", + duration: "4 min fix", + category: "phone", + steps: [ + "Restart your phone.", + "Check storage - delete old photos/videos or offload to cloud if you're above 90% full.", + "Update iOS/Android and your most-used apps.", + "Reset network settings only if Wi-Fi or cellular is broken (you'll re-enter Wi-Fi passwords).", + ], + }, + { + slug: "printer-offline", + title: "Printer stuck offline", + description: + "Get it printing again without reinstalling everything from scratch.", + duration: "2 min fix", + category: "printer", + steps: [ + "Confirm the printer is on and connected to the same Wi-Fi as your computer.", + "Set the printer as default in system print settings.", + "Clear the print queue and cancel stuck jobs.", + "Remove and re-add the printer if it still shows offline.", + ], + }, + { + slug: "locked-out-account", + title: "Locked out of an account", + description: "Safely reset passwords and set up 2FA so it never happens again.", + duration: "3 min fix", + category: "account", + steps: [ + "Use the service's official \"Forgot password\" flow - never click links from email unless you're sure.", + "Check spam for reset messages and try a different browser if the page won't load.", + "Use a password manager to generate and store a new unique password.", + "Enable two-factor authentication (authenticator app preferred over SMS).", + ], + }, + { + slug: "streaming-tv-glitches", + title: "Streaming & smart TV glitches", + description: "Fix freezing, sign-in loops, and apps that refuse to load.", + duration: "4 min fix", + category: "streaming", + steps: [ + "Sign out and back into the streaming app on your TV or stick.", + "Check for app and TV firmware updates.", + "Power-cycle the TV and streaming device (unplug 60 seconds).", + "If one app fails, try another network (phone hotspot) to rule out router issues.", + ], + }, +] + +export function fixHref(slug: string): string { + return `/fixes/${slug}` +} + +export function getFixBySlug(slug: string): FixGuide | undefined { + return FIXES.find((f) => f.slug === slug) +} + +export const FOOTER_FIX_LINKS = [ + { label: "Wi-Fi & internet", slug: "slow-wifi" }, + { label: "Slow computer", slug: "sluggish-computer" }, + { label: "Phone issues", slug: "phone-acting-up" }, + { label: "Printers", slug: "printer-offline" }, + { label: "Passwords", slug: "locked-out-account" }, +] as const diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000000..830fb594ca --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000000..f62ca4272c --- /dev/null +++ b/next.config.ts @@ -0,0 +1,5 @@ +import type { NextConfig } from "next" + +const nextConfig: NextConfig = {} + +export default nextConfig diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..3c8dcd9c5c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1745 @@ +{ + "name": "nowfix-pro", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nowfix-pro", + "version": "0.1.0", + "dependencies": { + "lucide-react": "^0.513.0", + "next": "^15.3.3", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^22", + "@types/react": "^19", + "@types/react-dom": "^19", + "tailwindcss": "^4", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/runtime": { + "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": { + "tslib": "^2.4.0" + } + }, + "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", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "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" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "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" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "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" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "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": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "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": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "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.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@next/env": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.19.tgz", + "integrity": "sha512-sWWluFvcv5v3Fxznmf2ZfjyoVQt/64oCnYqS90inQWGzMPK1VjvekPiz3OPHKmFT30EnHrjlbyaHLt3M0vWabw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.19.tgz", + "integrity": "sha512-jx9wWlTKueHKPvVOndyr7WuaevWCkuYqsQ8gC0TMPKAVWG3MhcdMrjfo9tvIZNXd0QOUYXXvAcZ325y8Uq7uzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.19.tgz", + "integrity": "sha512-291KFcsIQ3OenRdiUDFOR6W3wezzH4auENXm1gbm1Bjd4ANMMRgxPrWTUztQN43BnVoVuMnHCrLeECIMwgFKbA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.19.tgz", + "integrity": "sha512-WeH+nelQyyMeE2f8FxBRZNrGipya5zHZV2vjzfCOAYyiI6am+NbnWAAldOBFQBB2w0DjJcsvrKqoFT2b7+5YoA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.19.tgz", + "integrity": "sha512-5xTOE0lDlDCSSfp+BAif7j17VRRCjWp//ZPZy6NI0QpdrhxtQnsZguSx0xAAZ0c9XZLrLLwCe/XVe5YPrRilKw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.19.tgz", + "integrity": "sha512-LTxRmMgqqMv05Had879W00Fm53quiJd3Zuz8h1JSNJ3nGSlbZ/7Tjs1tKyScgN3Au3t3MyPsjPlq60fMmSHLsg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.19.tgz", + "integrity": "sha512-eoNQSpA5PQfB9wBO4RA47MTDXWz1fizy9Y3Z6e4DetYIF3dvjuu8sj7aIGn/bFCU6lnFzTK34NtCaffP4NsQ7Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.19.tgz", + "integrity": "sha512-6UNt2dFuCHOe446sm/Kp69nUe8/wIhnh9bm6Xcqw4qEWCOppLMOvhTBVgvM7invVUNr4SPpP6NOQsACtn2IN9Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.19.tgz", + "integrity": "sha512-PhmojAHyqMne56HBLGu9dhDnHPuFmEjrXSQMM/nW0J6j849lk3ESrVtqNJcCk8CKOV7brpTTbaYAjwKPzKM69w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz", + "integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "postcss": "^8.5.10", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", + "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/csstype": { + "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" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lucide-react": { + "version": "0.513.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.513.0.tgz", + "integrity": "sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "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": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.19.tgz", + "integrity": "sha512-xNOW6tYshGX1/Oi3F8uuk4gpDeWsSUE/1Z0G5uUMekIxaQ0xc03UXd9II0VQHYMWviMeA0OHpJFAKsHf8bTYVg==", + "license": "MIT", + "dependencies": { + "@next/env": "15.5.19", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.5.19", + "@next/swc-darwin-x64": "15.5.19", + "@next/swc-linux-arm64-gnu": "15.5.19", + "@next/swc-linux-arm64-musl": "15.5.19", + "@next/swc-linux-x64-gnu": "15.5.19", + "@next/swc-linux-x64-musl": "15.5.19", + "@next/swc-win32-arm64-msvc": "15.5.19", + "@next/swc-win32-x64-msvc": "15.5.19", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "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": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "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": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "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==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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", + "optional": true, + "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/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/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "dev": true, + "license": "MIT" + }, + "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": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "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" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..30df932da6 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "nowfix-pro", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "next": "^15.3.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "lucide-react": "^0.513.0" + }, + "devDependencies": { + "@types/node": "^22", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5", + "tailwindcss": "^4", + "@tailwindcss/postcss": "^4" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000000..e7d928ed56 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,989 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + lucide-react: + specifier: ^0.513.0 + version: 0.513.0(react@19.2.7) + next: + specifier: ^15.3.3 + version: 15.5.19(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: + specifier: ^19.0.0 + version: 19.2.7 + react-dom: + specifier: ^19.0.0 + version: 19.2.7(react@19.2.7) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4 + version: 4.3.0 + '@types/node': + specifier: ^22 + version: 22.19.19 + '@types/react': + specifier: ^19 + version: 19.2.16 + '@types/react-dom': + specifier: ^19 + version: 19.2.3(@types/react@19.2.16) + tailwindcss: + specifier: ^4 + version: 4.3.0 + typescript: + specifier: ^5 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@next/env@15.5.19': + resolution: {integrity: sha512-sWWluFvcv5v3Fxznmf2ZfjyoVQt/64oCnYqS90inQWGzMPK1VjvekPiz3OPHKmFT30EnHrjlbyaHLt3M0vWabw==} + + '@next/swc-darwin-arm64@15.5.19': + resolution: {integrity: sha512-jx9wWlTKueHKPvVOndyr7WuaevWCkuYqsQ8gC0TMPKAVWG3MhcdMrjfo9tvIZNXd0QOUYXXvAcZ325y8Uq7uzg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.19': + resolution: {integrity: sha512-291KFcsIQ3OenRdiUDFOR6W3wezzH4auENXm1gbm1Bjd4ANMMRgxPrWTUztQN43BnVoVuMnHCrLeECIMwgFKbA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.19': + resolution: {integrity: sha512-WeH+nelQyyMeE2f8FxBRZNrGipya5zHZV2vjzfCOAYyiI6am+NbnWAAldOBFQBB2w0DjJcsvrKqoFT2b7+5YoA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@15.5.19': + resolution: {integrity: sha512-5xTOE0lDlDCSSfp+BAif7j17VRRCjWp//ZPZy6NI0QpdrhxtQnsZguSx0xAAZ0c9XZLrLLwCe/XVe5YPrRilKw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@15.5.19': + resolution: {integrity: sha512-LTxRmMgqqMv05Had879W00Fm53quiJd3Zuz8h1JSNJ3nGSlbZ/7Tjs1tKyScgN3Au3t3MyPsjPlq60fMmSHLsg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@15.5.19': + resolution: {integrity: sha512-eoNQSpA5PQfB9wBO4RA47MTDXWz1fizy9Y3Z6e4DetYIF3dvjuu8sj7aIGn/bFCU6lnFzTK34NtCaffP4NsQ7Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@15.5.19': + resolution: {integrity: sha512-6UNt2dFuCHOe446sm/Kp69nUe8/wIhnh9bm6Xcqw4qEWCOppLMOvhTBVgvM7invVUNr4SPpP6NOQsACtn2IN9Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.19': + resolution: {integrity: sha512-PhmojAHyqMne56HBLGu9dhDnHPuFmEjrXSQMM/nW0J6j849lk3ESrVtqNJcCk8CKOV7brpTTbaYAjwKPzKM69w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.0': + resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} + + '@types/node@22.19.19': + resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.16': + resolution: {integrity: sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==} + + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + enhanced-resolve@5.22.2: + resolution: {integrity: sha512-0rxICaFZ7NQho/sHely2bvOPRP0Eu2B0NZ9zM54YvRvWMn7jfz3DmnOZDR9LlXDdDcqntAVc6Hfy4gr/tdH/Ag==} + engines: {node: '>=10.13.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lucide-react@0.513.0: + resolution: {integrity: sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + next@15.5.19: + resolution: {integrity: sha512-xNOW6tYshGX1/Oi3F8uuk4gpDeWsSUE/1Z0G5uUMekIxaQ0xc03UXd9II0VQHYMWviMeA0OHpJFAKsHf8bTYVg==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + react-dom@19.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} + peerDependencies: + react: ^19.2.7 + + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} + engines: {node: '>=0.10.0'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@7.8.2: + resolution: {integrity: sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@next/env@15.5.19': {} + + '@next/swc-darwin-arm64@15.5.19': + optional: true + + '@next/swc-darwin-x64@15.5.19': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.19': + optional: true + + '@next/swc-linux-arm64-musl@15.5.19': + optional: true + + '@next/swc-linux-x64-gnu@15.5.19': + optional: true + + '@next/swc-linux-x64-musl@15.5.19': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.19': + optional: true + + '@next/swc-win32-x64-msvc@15.5.19': + optional: true + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.22.2 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/postcss@4.3.0': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + postcss: 8.5.15 + tailwindcss: 4.3.0 + + '@types/node@22.19.19': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.16)': + dependencies: + '@types/react': 19.2.16 + + '@types/react@19.2.16': + dependencies: + csstype: 3.2.3 + + caniuse-lite@1.0.30001793: {} + + client-only@0.0.1: {} + + csstype@3.2.3: {} + + detect-libc@2.1.2: {} + + enhanced-resolve@5.22.2: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + graceful-fs@4.2.11: {} + + jiti@2.7.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lucide-react@0.513.0(react@19.2.7): + dependencies: + react: 19.2.7 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + nanoid@3.3.12: {} + + next@15.5.19(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@next/env': 15.5.19 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001793 + postcss: 8.4.31 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + styled-jsx: 5.1.6(react@19.2.7) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.19 + '@next/swc-darwin-x64': 15.5.19 + '@next/swc-linux-arm64-gnu': 15.5.19 + '@next/swc-linux-arm64-musl': 15.5.19 + '@next/swc-linux-x64-gnu': 15.5.19 + '@next/swc-linux-x64-musl': 15.5.19 + '@next/swc-win32-arm64-msvc': 15.5.19 + '@next/swc-win32-x64-msvc': 15.5.19 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + picocolors@1.1.1: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + react-dom@19.2.7(react@19.2.7): + dependencies: + react: 19.2.7 + scheduler: 0.27.0 + + react@19.2.7: {} + + scheduler@0.27.0: {} + + semver@7.8.2: + optional: true + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.2 + 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 + optional: true + + source-map-js@1.2.1: {} + + styled-jsx@5.1.6(react@19.2.7): + dependencies: + client-only: 0.0.1 + react: 19.2.7 + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tslib@2.8.1: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000000..2f8795a936 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +} + +export default config diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..d8b93235f2 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} From e549f8130fa1de4612348505a42e4140bf64fad7 Mon Sep 17 00:00:00 2001 From: v0agent Date: Thu, 4 Jun 2026 19:10:24 +0000 Subject: [PATCH 10/15] feat: add Vercel config and update tsconfig.json exclusions Added Vercel configuration file and updated tsconfig.json to exclude docs and examples. Co-authored-by: Mohamed <134189886+garlobrian52@users.noreply.github.com> --- tsconfig.json | 2 +- vercel.json | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 vercel.json diff --git a/tsconfig.json b/tsconfig.json index d8b93235f2..737830f969 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,5 +23,5 @@ } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "docs", "examples"] } diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000000..40d724074b --- /dev/null +++ b/vercel.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": "nextjs", + "buildCommand": "npm run build", + "installCommand": "npm install", + "outputDirectory": ".next" +} From d7495f8127187154bb2c6121ac041dbc43ec1cca Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 4 Jun 2026 19:16:41 +0000 Subject: [PATCH 11/15] Fix Vercel config and viewport zoom --- app/layout.tsx | 1 - vercel.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/layout.tsx b/app/layout.tsx index 006b7556c6..e0b31f557b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -10,7 +10,6 @@ export const metadata: Metadata = { export const viewport: Viewport = { width: "device-width", initialScale: 1, - maximumScale: 1, themeColor: [ { media: "(prefers-color-scheme: light)", color: "#ffffff" }, { media: "(prefers-color-scheme: dark)", color: "#1a1a1a" }, diff --git a/vercel.json b/vercel.json index 40d724074b..db2dc4288e 100644 --- a/vercel.json +++ b/vercel.json @@ -2,6 +2,5 @@ "$schema": "https://openapi.vercel.sh/vercel.json", "framework": "nextjs", "buildCommand": "npm run build", - "installCommand": "npm install", - "outputDirectory": ".next" + "installCommand": "npm install" } From 704cfb1be1fea809a3106bf454c31b9062a6d19f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 4 Jun 2026 19:18:37 +0000 Subject: [PATCH 12/15] Allow mobile viewport scaling Co-authored-by: Mohamed --- app/layout.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/layout.tsx b/app/layout.tsx index e0b31f557b..316ed48406 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -10,6 +10,7 @@ export const metadata: Metadata = { export const viewport: Viewport = { width: "device-width", initialScale: 1, + userScalable: true, themeColor: [ { media: "(prefers-color-scheme: light)", color: "#ffffff" }, { media: "(prefers-color-scheme: dark)", color: "#1a1a1a" }, From f3b31b42666795c3d653cf480257bc22320c3259 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 8 Jun 2026 20:00:56 +0000 Subject: [PATCH 13/15] Add RFC 9148 bis update fragment derived from cBRSKI -31 Document paste-ready replacement text for EST-coaps updates specified in draft-ietf-anima-constrained-voucher-31, including DTLS requirements, /crts content-formats, CA renewal, and re-enrollment procedures. Co-authored-by: Mohamed --- docs/rfc9148-bis-source/README.md | 31 + ...raft-ietf-anima-constrained-voucher-31.txt | 5376 +++++++++++++++++ .../rfc9148-bis-patch-map.md | 31 + .../rfc9148-bis-update-fragment.mkd | 479 ++ .../rfc9148-bis-update-fragment.txt | 309 + 5 files changed, 6226 insertions(+) create mode 100644 docs/rfc9148-bis-source/README.md create mode 100644 docs/rfc9148-bis-source/draft-ietf-anima-constrained-voucher-31.txt create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-patch-map.md create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-update-fragment.mkd create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-update-fragment.txt diff --git a/docs/rfc9148-bis-source/README.md b/docs/rfc9148-bis-source/README.md new file mode 100644 index 0000000000..a547aa1019 --- /dev/null +++ b/docs/rfc9148-bis-source/README.md @@ -0,0 +1,31 @@ +# RFC 9148 bis update fragment (from cBRSKI) + +This directory holds source material for normative updates to [RFC 9148](https://www.rfc-editor.org/rfc/rfc9148) (EST-coaps), extracted and rewritten from: + +- **Title:** Constrained Bootstrapping Remote Secure Key Infrastructure (cBRSKI) +- **Name:** `draft-ietf-anima-constrained-voucher-31.txt` +- **WG:** [ANIMA](https://datatracker.ietf.org/wg/anima/about/) +- **Date:** 2026-06-08 +- **Authors:** Michael Richardson, Peter van der Stok, Panos Kampanakis, Esko Dijk + +## Files + +| File | Purpose | +|------|---------| +| `draft-ietf-anima-constrained-voucher-31.txt` | Upstream cBRSKI Internet-Draft (reference copy) | +| `rfc9148-bis-update-fragment.mkd` | Paste-ready replacement/insert text for an RFC 9148 bis, with `
` tags aligned to RFC 9148 numbering | +| `rfc9148-bis-patch-map.md` | Section-by-section map: RFC 9148 location → action → cBRSKI source | + +## Usage + +1. Open `rfc9148-bis-update-fragment.mkd`. +2. For each `
` block, apply the indicated **REPLACE**, **INSERT**, or **ADD** action at that location in the RFC 9148 bis source. +3. Cross-check against `rfc9148-bis-patch-map.md` and the live cBRSKI draft before submitting to the ANIMA WG or RFC Editor. + +## Scope + +The fragment generalizes cBRSKI text into EST-coaps terminology (`EST-coaps client/server`) wherever the update applies to all EST-coaps implementations. Bootstrap-only procedures that depend on BRSKI vouchers remain in cBRSKI and are marked **informative / out of scope** in the fragment. + +## Provenance + +Generated from analysis of cBRSKI -31 Section 5 (Updates to RFC 9148) and the corresponding normative sections 6.1, 6.7, 6.8, and 15.1. diff --git a/docs/rfc9148-bis-source/draft-ietf-anima-constrained-voucher-31.txt b/docs/rfc9148-bis-source/draft-ietf-anima-constrained-voucher-31.txt new file mode 100644 index 0000000000..dd6142be31 --- /dev/null +++ b/docs/rfc9148-bis-source/draft-ietf-anima-constrained-voucher-31.txt @@ -0,0 +1,5376 @@ + + + + +anima Working Group M. Richardson +Internet-Draft Sandelman Software Works +Updates: 8995, 9148 (if approved) P. van der Stok +Intended status: Standards Track vanderstok consultancy +Expires: 10 December 2026 P. Kampanakis + Cisco Systems + E. Dijk + IoTconsultancy.nl + 8 June 2026 + + + Constrained Bootstrapping Remote Secure Key Infrastructure (cBRSKI) + draft-ietf-anima-constrained-voucher-31 + +Abstract + + This document defines the Constrained Bootstrapping Remote Secure Key + Infrastructure (cBRSKI) protocol, which provides a solution for + secure zero-touch onboarding of resource-constrained (IoT) devices + into the network of a domain owner. This protocol is designed for + constrained networks, which may have limited data throughput or may + experience frequent packet loss. cBRSKI is a variant of the BRSKI + protocol, which uses an artifact signed by the device manufacturer + called the "voucher" which enables a new device and the owner's + network to mutually authenticate. While the BRSKI voucher data is + encoded in JSON, cBRSKI uses a compact CBOR-encoded voucher. The + BRSKI voucher data definition is extended with new data types that + allow for smaller voucher sizes. The Enrollment over Secure + Transport (EST) protocol, used in BRSKI, is replaced with EST-over- + CoAPS; and HTTPS used in BRSKI is replaced with DTLS-secured CoAP + (CoAPS). This document Updates RFC 8995 and RFC 9148. + +About This Document + + This note is to be removed before publishing as an RFC. + + Status information for this document may be found at + https://datatracker.ietf.org/doc/draft-ietf-anima-constrained- + voucher/. + + Discussion of this document takes place on the anima Working Group + mailing list (mailto:anima@ietf.org), which is archived at + https://mailarchive.ietf.org/arch/browse/anima/. Subscribe at + https://www.ietf.org/mailman/listinfo/anima/. + + Source for this draft and an issue tracker can be found at + https://github.com/anima-wg/constrained-voucher. + + + + +Richardson, et al. Expires 10 December 2026 [Page 1] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on 10 December 2026. + +Copyright Notice + + Copyright (c) 2026 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents (https://trustee.ietf.org/ + license-info) in effect on the date of publication of this document. + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. Code Components + extracted from this document must include Revised BSD License text as + described in Section 4.e of the Trust Legal Provisions and are + provided without warranty as described in the Revised BSD License. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 5 + 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 6 + 3. Requirements Language . . . . . . . . . . . . . . . . . . . . 7 + 4. Overview of Protocol . . . . . . . . . . . . . . . . . . . . 7 + 5. Updates to RFC 8995 and RFC 9148 . . . . . . . . . . . . . . 9 + 6. BRSKI-EST Protocol . . . . . . . . . . . . . . . . . . . . . 10 + 6.1. DTLS Connection . . . . . . . . . . . . . . . . . . . . . 10 + 6.1.1. DTLS Version . . . . . . . . . . . . . . . . . . . . 10 + 6.1.2. DTLS Cipher Suites . . . . . . . . . . . . . . . . . 11 + 6.1.3. DTLS Client Certificates: IDevID authentication . . . 12 + 6.1.4. DTLS Handshake Fragmentation Considerations . . . . . 12 + 6.2. Registrar Server Certificate Requirements . . . . . . . . 13 + 6.3. Registrar and the Server Name Indicator (SNI) . . . . . . 13 + 6.4. cBRSKI Join Proxy . . . . . . . . . . . . . . . . . . . . 14 + 6.5. Request URIs, Resource Discovery and Content-Formats . . 14 + + + +Richardson, et al. Expires 10 December 2026 [Page 2] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 6.5.1. Status Telemetry Returns . . . . . . . . . . . . . . 16 + 6.5.2. CoAP Resources Table . . . . . . . . . . . . . . . . 16 + 6.5.3. CoAP Uri-Path Abbreviation . . . . . . . . . . . . . 17 + 6.6. CoAP Responses . . . . . . . . . . . . . . . . . . . . . 17 + 6.7. Extensions to EST-coaps . . . . . . . . . . . . . . . . . 18 + 6.7.1. Pledge Enrollment Procedure . . . . . . . . . . . . . 18 + 6.7.2. Renewal of CA certificates . . . . . . . . . . . . . 19 + 6.7.3. Change of Domain Trust Anchor(s) . . . . . . . . . . 19 + 6.7.4. Re-enrollment Procedure . . . . . . . . . . . . . . . 20 + 6.7.5. Multipart Content-Format for CA certificates (/crts) + Resource . . . . . . . . . . . . . . . . . . . . . . 21 + 6.8. Registrar Extensions . . . . . . . . . . . . . . . . . . 22 + 7. BRSKI-MASA Protocol . . . . . . . . . . . . . . . . . . . . . 23 + 7.1. Protocol and Formats . . . . . . . . . . . . . . . . . . 23 + 7.2. Registrar Voucher Request . . . . . . . . . . . . . . . . 24 + 7.3. MASA and the Server Name Indicator (SNI) . . . . . . . . 24 + 7.4. Registrar Client Certificate Requirements . . . . . . . . 25 + 8. Pinning in Voucher Artifacts . . . . . . . . . . . . . . . . 25 + 8.1. Registrar Identity Selection and Encoding . . . . . . . . 25 + 8.2. MASA Pinning Policy . . . . . . . . . . . . . . . . . . . 26 + 8.3. Pinning of Raw Public Keys (RPK) . . . . . . . . . . . . 27 + 9. Artifacts . . . . . . . . . . . . . . . . . . . . . . . . . . 28 + 9.1. Example Artifacts . . . . . . . . . . . . . . . . . . . . 29 + 9.1.1. Example Pledge Voucher Request (PVR) Artifact . . . . 29 + 9.1.2. Example Registrar Voucher Request (RVR) Artifact . . 29 + 9.1.3. Example Voucher Artifacts . . . . . . . . . . . . . . 30 + 9.2. Signing Voucher and Voucher Request Artifacts with + COSE . . . . . . . . . . . . . . . . . . . . . . . . . . 31 + 9.2.1. Signing of Registrar Voucher Request (RVR) . . . . . 32 + 9.2.2. Signing of Pledge Voucher Request (PVR) . . . . . . . 33 + 9.2.3. Signing of Voucher by MASA . . . . . . . . . . . . . 34 + 9.2.4. Optional Validation of Voucher by Registrar . . . . . 36 + 9.2.5. Additional Information in the COSE Header . . . . . . 36 + 10. Extensions to Discovery . . . . . . . . . . . . . . . . . . . 37 + 10.1. Discovery Operations by a Pledge . . . . . . . . . . . . 38 + 10.1.1. Examples . . . . . . . . . . . . . . . . . . . . . . 39 + 10.2. Discovery Operations by a Join Proxy . . . . . . . . . . 40 + 11. Deployment-specific Discovery Considerations . . . . . . . . 41 + 11.1. 6TiSCH Deployments . . . . . . . . . . . . . . . . . . . 41 + 11.2. IP networks using GRASP . . . . . . . . . . . . . . . . 41 + 11.3. IP networks using mDNS . . . . . . . . . . . . . . . . . 41 + 11.4. Thread Networks using Mesh Link Establishment (MLE) . . 42 + 12. Design and Implementation Considerations . . . . . . . . . . 42 + 12.1. Voucher Format and Encoding . . . . . . . . . . . . . . 42 + 12.2. CoAP Usage . . . . . . . . . . . . . . . . . . . . . . . 43 + 12.3. Use of cBRSKI with HTTPS . . . . . . . . . . . . . . . . 43 + 13. Raw Public Key Variant . . . . . . . . . . . . . . . . . . . 44 + 13.1. Introduction and Scope . . . . . . . . . . . . . . . . . 44 + + + +Richardson, et al. Expires 10 December 2026 [Page 3] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 13.2. DTLS Connection and Registrar Trust Anchor . . . . . . . 44 + 13.3. The Pledge Voucher Request . . . . . . . . . . . . . . . 45 + 13.4. The Voucher Response . . . . . . . . . . . . . . . . . . 45 + 13.5. The Enrollment Phase . . . . . . . . . . . . . . . . . . 46 + 14. Security Considerations . . . . . . . . . . . . . . . . . . . 46 + 14.1. Duplicate Serial Numbers . . . . . . . . . . . . . . . . 46 + 14.2. IDevID Security in the Pledge . . . . . . . . . . . . . 47 + 14.3. Security of the BRSKI-MASA Protocol . . . . . . . . . . 48 + 14.4. Registrar Certificate May Be Self-signed . . . . . . . . 49 + 14.5. Use of RPK Alternatives to 'proximity-registrar-cert' . 49 + 15. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 49 + 15.1. Resource Type Link Target Attribute Values Registry . . 49 + 15.2. Media Types Registry . . . . . . . . . . . . . . . . . . 50 + 15.2.1. application/voucher+cose . . . . . . . . . . . . . . 50 + 15.2.2. Interoperability Considerations for application/ + voucher+cose . . . . . . . . . . . . . . . . . . . . 51 + 15.3. CoAP Content-Formats Registry . . . . . . . . . . . . . 52 + 15.4. Update to BRSKI Well-Known URIs Registry . . . . . . . . 52 + 15.5. Structured Syntax Suffixes Registry . . . . . . . . . . 53 + 16. References . . . . . . . . . . . . . . . . . . . . . . . . . 54 + 16.1. Normative References . . . . . . . . . . . . . . . . . . 54 + 16.2. Informative References . . . . . . . . . . . . . . . . . 58 + Appendix A. Software and Library Support for cBRSKI . . . . . . 60 + A.1. Open Source cBRSKI Implementations . . . . . . . . . . . 61 + A.2. Security Library Support . . . . . . . . . . . . . . . . 61 + A.2.1. OpensSSL Example Code . . . . . . . . . . . . . . . . 62 + A.2.2. mbedTLS Example Code . . . . . . . . . . . . . . . . 63 + A.3. Generating Certificates with OpenSSL . . . . . . . . . . 64 + Appendix B. cBRSKI Message Examples . . . . . . . . . . . . . . 68 + B.1. enrollstatus . . . . . . . . . . . . . . . . . . . . . . 68 + B.2. voucher_status . . . . . . . . . . . . . . . . . . . . . 70 + Appendix C. COSE-signed Voucher (Request) Examples . . . . . . . 71 + C.1. Pledge, Registrar and MASA Keys . . . . . . . . . . . . . 71 + C.1.1. Pledge IDevID Private Key . . . . . . . . . . . . . . 71 + C.1.2. Registrar Private Key . . . . . . . . . . . . . . . . 71 + C.1.3. MASA Private Key . . . . . . . . . . . . . . . . . . 72 + C.2. Pledge, Registrar, Domain CA and MASA Certificates . . . 72 + C.2.1. Pledge IDevID Certificate . . . . . . . . . . . . . . 72 + C.2.2. Registrar Certificate . . . . . . . . . . . . . . . . 74 + C.2.3. Domain CA Certificate . . . . . . . . . . . . . . . . 76 + C.2.4. MASA Certificate . . . . . . . . . . . . . . . . . . 78 + C.3. COSE-signed Pledge Voucher Request (PVR) . . . . . . . . 80 + C.4. COSE-signed Registrar Voucher Request (RVR) . . . . . . . 81 + C.5. COSE-signed Voucher from MASA . . . . . . . . . . . . . . 84 + Appendix D. Pledge Device Class Profiles . . . . . . . . . . . . 86 + D.1. Minimal Pledge . . . . . . . . . . . . . . . . . . . . . 86 + D.2. Typical Pledge . . . . . . . . . . . . . . . . . . . . . 86 + D.3. Full-featured Pledge . . . . . . . . . . . . . . . . . . 87 + + + +Richardson, et al. Expires 10 December 2026 [Page 4] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + D.4. Comparison Chart of Pledge Classes . . . . . . . . . . . 87 + Appendix E. Pledge Discovery of Onboarding and Enrollment + Options . . . . . . . . . . . . . . . . . . . . . . . . . 89 + E.1. Pledge Discovery Query for All cBRSKI Resources . . . . . 89 + E.2. Pledge Discovery Query for the cBRSKI Base Resource . . . 91 + E.3. Usage of ct Attribute . . . . . . . . . . . . . . . . . . 91 + E.4. EST-coaps Resource Discovery . . . . . . . . . . . . . . 92 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 93 + Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 96 + +1. Introduction + + Secure enrollment of new nodes into constrained networks with + constrained nodes presents unique challenges. As explained in + [RFC7228], such networks may have limited data throughput or may + experience frequent packet loss. In addition, its nodes may be + constrained by energy availability, memory space, and code size. + + The Bootstrapping Remote Secure Key Infrastructure (BRSKI) protocol + described in [RFC8995] provides a solution for secure zero-touch + (automated) onboarding of new (unconfigured) devices. These new + devices are called "Pledges", equipped with a factory-installed + Initial Device Identifier (IDevID) (see [ieee802-1AR]). Using the + IDevID, a Pledge is securely enrolled into a network. + + The BRSKI solution described in [RFC8995] was designed to be modular, + and this document describes a version scaled to the constraints of + IoT deployments. This document uses the constrained voucher and + voucher request artifacts defined in [RFC8366bis] for a constrained + version of the BRSKI protocol: cBRSKI. The cBRSKI protocol uses the + CoAP-based version of EST (EST-coaps from [RFC9148]) rather than the + EST over HTTPS [RFC7030]. cBRSKI is itself scalable to multiple + resource levels through the definition of optional functions. + Appendix D illustrates this. + + In BRSKI, the [RFC8366bis] voucher data is by default serialized to + JSON with a signature in CMS [RFC5652]. cBRSKI uses the CBOR + [RFC8949] voucher data serialization defined by [RFC8366bis], and + applies a new COSE [RFC9052] signature format as defined in + Section 9. + + This COSE-signed CBOR-encoded voucher is transported using both + secured CoAP [RFC7252] and HTTPS. The CoAP connection (between + Pledge and Registrar) is to be protected by DTLS (CoAPS). The HTTP + connection (between Registrar and MASA) is to be protected using TLS + (HTTPS). + + + + +Richardson, et al. Expires 10 December 2026 [Page 5] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Section 4 to Section 10 define the default cBRSKI protocol, by means + of additions to and modifications of regular BRSKI. Section 11 + considers some variations of the protocol, specific to particular + deployments or IoT networking technologies. Next in Section 12, some + considerations for the design and implementation of cBRSKI components + are provided. + + Section 13 introduces a variant of cBRSKI for the most-constrained + Pledges, using Raw Public Keys (RPK). This variant achieves smaller + sizes of data objects and avoids doing certain costly PKIX + verification operations on the Pledge. + + Appendix E provides more details on how a Pledge may discover the + various onboarding/enrollment options that a Registrar provides. + Implementing these methods is optional for a Pledge. + +2. Terminology + + The following terms are defined in [RFC8366bis], and are used + identically as in that document: Artifact, Attribute, Domain, Join + Registrar and Coordinator (JRC), Malicious Registrar, Manufacturer + Authorized Signing Authority (MASA), Pledge, Registrar, Onboarding, + Owner, Voucher Data, Voucher Request and Voucher. + + The protocol described in this document is referred to as cBRSKI, the + constrained version of BRSKI [RFC8995]. + + The following terms from [RFC8995] are used identically as in that + document: Domain CA, enrollment, IDevID, Join Proxy, LDevID, + manufacturer, nonced, nonceless, PKIX. + + The following terms from [RFC7030] are used identically as in that + document: Explicit Trust Anchor (TA), Explicit TA database, Third- + party TA. + + The following terms from [RFC7252] are used identically as in that + document: Confirmable (CON), Acknowledgement (ACK), Endpoint, ETag, + Client, Server, Piggybacked Response, resource, Resource Discovery, + Content-Format. + + The term Pledge Voucher Request, or acronym PVR, is introduced to + refer to the voucher request between the Pledge and the Registrar. + + The term Registrar Voucher Request, or acronym RVR, is introduced to + refer to the voucher request between the Registrar and the MASA. + + The terms "PKIX Certificate" and "certificate" both refer to the + X.509v3 profile described in [RFC5280]. + + + +Richardson, et al. Expires 10 December 2026 [Page 6] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The term "base resource" is defined as a CoAP resource that can be + used as a base to append an additional path segment to, where this + segment is a short resource name ('short-name') as defined in + Section 6.5 and Table 1. + + In code examples, the string "" denotes the start of a + code example and "" the end of the code example. "lf + added" means that extra linefeed characters were added to an example + to make lines fit in this document. + + The ellipsis ("...") in a CBOR diagnostic notation byte string + denotes a further sequence of bytes that is not shown for brevity. + This notation is defined in [I-D.ietf-cbor-edn-literals]. + +3. Requirements Language + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + +4. Overview of Protocol + + [RFC8366bis] defines a voucher that can assert proximity, + authenticates the Registrar, and can offer varying levels of anti- + replay protection. The proximity proof provided by a voucher is an + assertion that the Pledge and the Registrar are believed to be close + together, from a network topology point of view. Similar to BRSKI + [RFC8995], proximity is proven by making a DTLS connection between a + Pledge and a Registrar. The Pledge initiates this connection using a + link-local source address. + + The secure DTLS connection is then used by the Pledge to send a + Pledge Voucher Request (PVR). The Registrar then includes the PVR + into its own Registrar Voucher Request (RVR), which is sent to an + agent (MASA) of the Pledge's manufacturer. The MASA verifies the PVR + and RVR and issues a signed voucher. The voucher provides an + authorization statement from the manufacturer indicating that the + Registrar is the intended owner of the Pledge. The voucher refers to + the Registrar through pinning of the Registrar's identity. + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 7] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + After verification of the voucher, the Pledge enrolls into the + Registrar's domain by obtaining a certificate using the EST-coaps + [RFC9148] protocol, suitable for constrained devices. Once the + Pledge has obtained its domain identity (LDevID) in this manner, it + can use this identity to obtain network access credentials, which are + used to join the local IP network. The method to obtain such + credentials depends on the particular network technology used and is + outside the scope of this document. + + The two main parts of the BRSKI protocol are named separately in this + document: BRSKI-EST (Section 6) for the protocol between Pledge and + Registrar, and BRSKI-MASA (Section 7) for the protocol between the + Registrar and the MASA. + + Time-based vouchers are supported, but given that constrained devices + are unlikely to have accurate time, their use will be uncommon. Most + Pledges using constrained vouchers will be online during enrollment + and will use live nonces to provide anti-replay protection rather + than expiry times. + + [RFC8366bis] defines the CBOR voucher data encoding for the + constrained voucher and the constrained voucher request, which are + used by cBRSKI. + + The constrained voucher request MUST be signed by the Pledge. COSE + [RFC9052] is used for signing as defined in Section 9.2. It signs + using the private key of its IDevID. The constrained voucher MUST be + signed by the MASA. Also in this case, COSE is used for signing. + + For the constrained voucher request (PVR) the default method for the + Pledge to identify the Registrar is using the Registrar's full PKIX + certificate. But when operating PKIX-less as described in + Section 13, the Registrar's Raw Public Key (RPK) is used for this. + + For the constrained voucher the default method to indicate ("pin") a + trusted domain identity is the domain's PKIX CA certificate, but when + operating PKIX-less instead the RPK of the Registrar is pinned. + + For certificates, cBRSKI currently uses the X.509 format, like BRSKI. + The protocol and data formats are defined such that future extension + to other certificate formats is enabled. For example, CBOR-encoded + and COSE-signed C509 certificates ([I-D.ietf-cose-cbor-encoded-cert]) + may provide data size savings as well as code sharing benefits with + CBOR/COSE libraries, when applied to cBRSKI. + + The BRSKI architecture mandates that the MASA be aware of the + capabilities of the Pledge. This is not a drawback as a Pledge is + constructed by a manufacturer which also arranges for the MASA to be + + + +Richardson, et al. Expires 10 December 2026 [Page 8] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + aware of the inventory of devices. The MASA therefore knows if the + Pledge supports PKIX operations, or if it is limited to RPK + operations only. Based upon this, the MASA can select which + attributes to use in the voucher for certain operations, like the + pinning of the Registrar or domain identity. + +5. Updates to RFC 8995 and RFC 9148 + + This section details the ways in which this document updates other + RFCs. + + This document Updates [RFC8995] because it adds normative + requirements on: + + * how pinning in vouchers is done (Section 8), + + * the use of TLS Server Name Indicator (SNI) (Section 6.3, + Section 7.3), + + * when new trust anchors should be retrieved by a Pledge + (Section 6.7.1), + + * what Extended Key Usage attributes are required for each + certificate (Section 6.2, Section 7.4), + + * extending BRSKI with CoAP support, + + * reducing the BRSKI/EST data traffic size and post-onboarding (EST) + certificate maintenance (Section 6.7), + + * extending the BRSKI-EST/BRSKI-MASA protocols (Section 6, + Section 7, Section 9.2) to carry the new application/voucher+cose + format. + + This document Updates [RFC9148] because it: + + * defines stricter DTLS requirements (Section 6.1)), including + mandatory DTLS 1.3 cipher suites (Section 6.1.2), + + * normatively details how an EST-coaps client handles certificate + renewal and re-enrollment (Section 6.7), + + * normatively details how an EST-coaps server processes a "CA + certificates" request for content-format 287 (application/pkix- + cert) (Section 6.8). + + * defines enrollment status telemetry for the certificate renewal + procedure (Section 6.7.4), + + + +Richardson, et al. Expires 10 December 2026 [Page 9] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + * adds support for the media type application/multipart-core for the + EST-CoAPS CA certificates (/crts) resource (Section 6.7.5), + + * defines a resource type ('rt') attribute value "ace.est" for the + EST-coaps base resource (Section 15.1). + +6. BRSKI-EST Protocol + + This section describes the extensions to both BRSKI [RFC8995] and + EST-coaps [RFC9148] operations between Pledge and Registrar. + +6.1. DTLS Connection + + A DTLS connection is established between the Pledge and the + Registrar, similar to the TLS connection described in Section 5.1 of + [RFC8995]. This may occur via a Join Proxy as described in + Section 6.4. Regardless of the Join Proxy presence or particular + mechanism used, the DTLS connection should operate identically. The + cBRSKI and EST-coaps CoAP requests and responses for onboarding are + carried over this DTLS connection. + +6.1.1. DTLS Version + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An exception case where DTLS 1.2 [RFC6347] MAY + be used is in a Pledge that uses a software platform where a DTLS 1.3 + client is not available (yet). This may occur for example if a + legacy device gets software-upgraded to support cBRSKI. For this + reason, a Registrar MUST by default support both DTLS 1.3 and DTLS + 1.2 client connections. However, for security reasons the Registrar + MAY be administratively configured to support only a particular DTLS + version or higher. + + A Pledge that implements DTLS 1.3 MUST NOT additionally support DTLS + 1.2. This prevents a rogue Registrar from forcing the Pledge onto + DTLS 1.2, reduces the DTLS code's attack surface on the constrained + Pledge, and keeps more handshake metadata encrypted. + + An EST-coaps server [RFC9148], if present as a separate CoAP endpoint + from above Registrar, that implements this specification also MUST + support both DTLS 1.3 and DTLS 1.2 client connections by default. + Again, for security reasons the EST-coaps server MAY be + administratively configured to support only a particular DTLS version + or higher. + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 10] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +6.1.2. DTLS Cipher Suites + +6.1.2.1. DTLS 1.2 Cipher Suites + + The DTLS 1.2 cipher suite requirements of Section 3 of [RFC9148] MUST + be applied to a Registrar and, if present, an EST-coaps server hosted + at a separate endpoint. These requirements include mandatory support + for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8. This is the default CoAPS + cipher suite as specified in Section 9.1.3.3 of [RFC7252]. + + A Pledge using DTLS 1.2 MUST implement the above cipher suite and MAY + implement others. + +6.1.2.2. DTLS 1.3 Cipher Suites + + The DTLS 1.3 requirements of Section 3 of [RFC9148] MUST be applied + to a Registrar and, if present, an EST-coaps server hosted at a + separate endpoint. However, these do not include a specific cipher + suite requirement. + + This document updates [RFC9148] by defining the DTLS 1.3 mandatory + cipher suites for an EST-coaps server. A Registrar and, if present, + a separate EST-coaps server, MUST support the following cipher + suites: + + * mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there) + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms) + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms) + + A Pledge whose IDevID certificate contains an Ed25519 public key (as + recommended for new designs in Section 9.2) uses the same Ed25519 + IDevID private key to sign the DTLS handshake CertificateVerify and + to sign its PVR; only one cryptographic implementation of Ed25519 is + therefore needed on the Pledge. To enable such Pledges to + authenticate, a Registrar MUST support digital signature algorithm + Ed25519 and elliptic curve group X25519 (see [RFC8446]). + + Note that per Section 4.5.3 of [RFC9147] the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. See Section 20 of + [I-D.ietf-uta-tls13-iot-profile] for a more detailed explanation of + this topic. These measures are needed on both the DTLS 1.3 client + + + +Richardson, et al. Expires 10 December 2026 [Page 11] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + and server. In the context of the cBRSKI protocol, the RECOMMENDED + safeguard measure is to limit the number of records that can fail + authentication to at most 2^7, as defined in Appendix B.3 of + [RFC9147]. If this measure is applied and the limit is reached, the + DTLS connection is closed. This is a suitable measure because all + cBRSKI and EST-coaps operations are relatively short-lived sessions + that only require a few, or a few 10s of, DTLS records. + + A Pledge using DTLS 1.3 MUST implement at least one of the above + cipher suites supported by the Registrar and MAY implement multiple + of these. + +6.1.3. DTLS Client Certificates: IDevID authentication + + As described in Section 5.1 of [RFC8995], the Pledge makes a + connection to the Registrar using a TLS Client Certificate for + authentication. This is the Pledge's IDevID certificate, which is + now used for DTLS. + + Subsequently the Pledge will send a Pledge Voucher Request (PVR). + Further elements of Pledge authentication may be present in the PVR, + as detailed in Section 9.2. + +6.1.4. DTLS Handshake Fragmentation Considerations + + DTLS includes a mechanism to fragment handshake messages. This is + described in Section 4.4 of [RFC9147]. cBRSKI will often be used with + a Join Proxy, described in Section 6.4, which relays each DTLS + message to the Registrar. A stateless Join Proxy will need some + additional space to wrap each DTLS message inside a Join Proxy UDP + message, while the wrapped result needs to fit in the maximum IPv6 + MTU guaranteed on 6LoWPAN [RFC6282] networks, which is 1280 bytes. + + For this reason it is RECOMMENDED that a PMTU of 1024 bytes be + assumed for the DTLS handshake and appropriate DTLS fragmentation is + used. It is unlikely that any ICMPv6 Packet Too Big indications + ([RFC4443]) will be relayed by the Join Proxy back to the Pledge. + + During the operation of the EST-coaps protocol, the CoAP Block-wise + transfer mechanism [RFC7959] will be automatically used when message + sizes exceed the PMTU. A Pledge/EST-client on a constrained network + MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066] with the + maximum fragment length set to a value of either 2^9 or 2^10, when + operating as a DTLS 1.2 client. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 12] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + A Pledge/EST-client operating as DTLS 1.3 client, MUST use the (D)TLS + record size limit extensions ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). + +6.2. Registrar Server Certificate Requirements + + As per Section 3.6.1 of [RFC7030], the Registrar certificate MUST + have the Extended Key Usage (EKU) id-kp-cmcRA. This certificate is + also used as a TLS Server Certificate (BRSKI) or DTLS Server + Certificate (cBRSKI), so it MUST also have the EKU id-kp-serverAuth. + This requirement is an update to [RFC8995], which does not mention + this EKU. + + See Appendix C.2.2 for an example of a Registrar certificate with + these EKUs set. See Section 7.4 for Registrar client certificate + requirements. + +6.3. Registrar and the Server Name Indicator (SNI) + + As the Pledge discovers the Registrar by (link-local) IP address, and + the Registrar is typically connected via a Join Proxy, the hostname + of the Registrar is not known to the Pledge. Therefore, it cannot do + DNS-ID validation ([RFC9525]) on the Registrar's certificate. + Instead, it must do validation using the voucher. + + Without knowing the hostname, the Pledge cannot put any reasonable + value into the [RFC6066] Server Name Indicator (SNI) extension. + Therefore the Pledge SHOULD omit the SNI extension as per Section 9.2 + of [RFC8446]. + + In some cases, particularly while testing BRSKI, a Pledge may be + given the hostname of a particular Registrar to connect to directly. + Such a bypass of the discovery process may result in the Pledge + taking a different code branch to establish a (D)TLS connection, and + may result in the SNI being inserted by a library. For this reason + and other possible situations where the SNI can not be turned off, + the Registrar MUST ignore any SNI it receives from a Pledge. + + A primary motivation for making the SNI ubiquitous in the public web + is because it allows for multi-tenant hosting of HTTPS sites on a + single (scarce) IPv4 address. This consideration does not apply to + the server function in the Registrar because: + + * it typically uses IPv6, often [RFC4193] Unique Local Address, + which are plentiful; + + + + + +Richardson, et al. Expires 10 December 2026 [Page 13] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + * the server port number is either discovered or configured, so + multiple tenants can be accommodated via unique UDP port numbers. + + The SNI issue described above also affects [RFC8995] as well, and is + reported in errata: https://www.rfc-editor.org/errata/eid6648 + (https://www.rfc-editor.org/errata/eid6648) The advice to omit the + SNI (if practical) in the Pledge applies, as the SNI bytes are not + useful. The advice for the Registrar to ignore the SNI above applies + to [RFC8995] as well, and this is an Update to that document. + +6.4. cBRSKI Join Proxy + + [I-D.ietf-anima-constrained-join-proxy] specifies the details for a + stateful or stateless constrained Join Proxy which is equivalent to + the BRSKI Proxy defined in [RFC8995], Section 4. See also Section 10 + for more details on discovery of a Join Proxy by a Pledge, and + discovery of a Registrar by a Join Proxy. + +6.5. Request URIs, Resource Discovery and Content-Formats + + cBRSKI operates using CoAP over DTLS, with request URIs using the + coaps scheme. The Pledge operates in CoAP client role. To keep the + protocol messages small the EST-coaps and cBRSKI request URIs are + shorter than the respective EST and BRSKI URIs. + + During the cBRSKI onboarding on an IPv6 network these request URIs + have the following form: + + coaps://[]:/.well-known/brski/ + coaps://[]:/.well-known/est/ + + where is the discovered link-local IPv6 address of + a Join Proxy, and is the discovered port of the Join Proxy + that is used to offer the cBRSKI proxy functionality. + + is the short resource name for the cBRSKI and EST-coaps + resources. For EST-coaps, Section 5.1 of [RFC9148] defines the CoAP + resource names. For cBRSKI, this document defines the + short resource names based on the [RFC8995] long HTTP resource names. + See Table 1 for a summary of these resource names. + + Section 11 details how the Pledge discovers a Join Proxy link-local + address and port in different deployment scenarios. + + The request URI formats defined here enable the Pledge to perform + onboarding/enrollment without requiring discovery of the available + onboarding options, voucher formats, BRSKI/EST resources, enrollment + protocols, and so on. This is helpful for the majority of + + + +Richardson, et al. Expires 10 December 2026 [Page 14] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + constrained Pledges that would support only a single set of these + options. However, for Pledges that do support multiple options, + [I-D.ietf-anima-brski-discovery] will define discovery methods so + that a Pledge can select the optimal set of options for the current + onboarding operation. + + Alternatively, a Pledge could also send CoAP discovery queries + (Section 7 of [RFC7252]) to the Registrar to discover detailed + options for onboarding and/or enrollment functions. Supporting these + queries is OPTIONAL for both the Pledge and the Registrar. To + clarify which options in particular can be discovered, Appendix E + provides an informative overview of what can be discovered and how to + discover it. + + Because a Pledge only has indirect access to the Registrar via a + single port on the Join Proxy, the Registrar MUST host all cBRSKI/ + EST-coaps resources on the same (UDP) server IP address and port. + This is the address and port where a Join Proxy would relay DTLS + records from the Pledge to. + + Although the request URI templates include IP address, scheme and + port, in practice the CoAP request message sent over the secure DTLS + connection only encodes the URI path explicitly. For example, a + Pledge that skips resource discovery operations just sends the + initial CoAP voucher request as follows: + + REQ: POST /.well-known/brski/rv + Content-Format: 836 (application/voucher+cose) + Payload : (COSE-signed Pledge Voucher Request, PVR) + + Note that only content-format 836 (application/voucher+cose) is + defined in this document for the payload sent to the voucher request + resource (/rv). Content-format 836 MUST be supported by the + Registrar for the /rv resource and it MAY support additional formats. + The Pledge MAY also indicate in the request the desired format of the + (voucher) response, using the Accept Option. An example of using + this option in the request is as follows: + + REQ: POST /.well-known/brski/rv + Content-Format: 836 (application/voucher+cose) + Accept : 836 (application/voucher+cose) + Payload : (COSE-signed Pledge Voucher Request, PVR) + + If the Accept Option is omitted in the request, the response format + follows from the request payload format (which is 836). + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 15] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Note that this specification allows for application/voucher+cose + format requests and vouchers to be transported over HTTPS, as well as + for application/voucher-cms+json and other formats yet to be defined + over CoAP. The burden for this flexibility is placed upon the + Registrar. A Pledge on constrained hardware is expected to support a + single format only. + + The Pledge and MASA need to support one or more formats (at least + format 836) for the voucher and for the voucher request. The MASA + needs to support all formats that the Pledge supports. + +6.5.1. Status Telemetry Returns + + [RFC8995] defines two telemetry returns from the Pledge which are + sent to the Registrar. These are the BRSKI Status Telemetry + [RFC8995], Section 5.7 and the Enrollment Status Telemetry [RFC8995], + Section 5.9.4. These are two CoAP POST requests made the by Pledge + at two key steps in the process. + + [RFC8995] defines the content of these POST operations in CDDL, which + are serialized as JSON. This document extends this with an + additional CBOR format, derived using the CDDL rules in [RFC8610]. + + The new CBOR telemetry format has CoAP content-format 60 + (application/cbor) and MUST be supported by the Registrar for both + the /vs and /es resources. The existing JSON format has CoAP + content-format 50 (application/json) and MAY also be supported by the + Registrar. A Pledge MUST use the new CBOR format to send telemetry + messages. + +6.5.2. CoAP Resources Table + + cBRSKI inherits EST-coaps [RFC9148] functions: specifically, the + mandatory Simple (Re-)Enrollment (/sen and /sren) and Certification + Authority certificates request (/crts). Support for CSR Attributes + Request (/att) and server-side key generation (/skg, /skc) remains + optional for the EST-coaps server. + + Table 1 summarizes the resources used in cBRSKI. It includes both + the short-name cBRSKI resources and the EST-coaps resources. + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 16] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + +=================+====================+===============+============+ + | BRSKI + EST | cBRSKI + EST-coaps | Well-known | Required | + | name | | URI | for | + | | | namespace | Registrar? | + +=================+====================+===============+============+ + | /enrollstatus | /es | brski | MUST | + +-----------------+--------------------+---------------+------------+ + | /requestvoucher | /rv | brski | MUST | + +-----------------+--------------------+---------------+------------+ + | /voucher_status | /vs | brski | MUST | + +-----------------+--------------------+---------------+------------+ + | /cacerts | /crts | est | MUST | + +-----------------+--------------------+---------------+------------+ + | /csrattrs | /att | est | MAY | + +-----------------+--------------------+---------------+------------+ + | /simpleenroll | /sen | est | MUST | + +-----------------+--------------------+---------------+------------+ + | /simplereenroll | /sren | est | MUST | + +-----------------+--------------------+---------------+------------+ + | /serverkeygen | /skg | est | MAY | + +-----------------+--------------------+---------------+------------+ + | /serverkeygen | /skc | est | MAY | + +-----------------+--------------------+---------------+------------+ + + Table 1: BRSKI/EST resource name mapping to cBRSKI/EST-coaps + short resource name + +6.5.3. CoAP Uri-Path Abbreviation + + To minimize the size of CoAP request packets on constrained networks, + the CoAP Uri-Path-Abbrev Option defined in + [I-D.ietf-core-uri-path-abbrev] MUST be supported by the Registrar. + +6.6. CoAP Responses + + [RFC8995], Section 5 defines a number of HTTP response codes that the + Registrar is to return when certain conditions occur. + + The 401, 403, 404, 406 and 415 response codes map directly to CoAP + codes 4.01, 4.03, 4.04, 4.06 and 4.15 respectively. + + The 202 Retry process which may occur in the voucher request, is to + be handled in the same way as the Section 5.7 of [RFC9148] process + for Delayed Responses. + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 17] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +6.7. Extensions to EST-coaps + + This section defines extensions to EST-coaps for Pledges (during + initial onboarding), EST-coaps clients (after initial onboarding) and + Registrars (that implement an EST-coaps server). Note that a device + that is already onboarded is not called "Pledge" in this section: it + now acts in the role of an EST-coaps client. + +6.7.1. Pledge Enrollment Procedure + + This section defines optimizations for the EST-coaps protocol as used + by a Pledge. These aim to reduce payload sizes and the number of + messages (round-trips) required for the initial EST enrollment. + + A Pledge SHOULD NOT perform the optional EST-coaps "CSR attributes + request" (/att). Instead, the Pledge selects the attributes to + include in the CSR as specified below. + + One or more Subject Distinguished Name fields MUST be included in the + CSR. If the Pledge has no specific information on what attributes/ + fields are desired in the CSR, which is the common case, it MUST use + the Subject Distinguished Name fields from its IDevID unmodified. + Note that a Pledge MAY receive such specific information via the + voucher data (encoded in a vendor-specific way, or as defined by a + future specification) or via some other, out-of-band means. + + A Pledge uses the following optimized EST-coaps procedure: + + 1. If the voucher, that validates the current Registrar, contains a + single pinned domain CA certificate, the Pledge provisionally + considers this certificate as the EST trust anchor, as if it were + the result of a "CA certificates request" (/crts) to the + Registrar. + + 2. Using this CA certificate as trust anchor it proceeds with EST + simple enrollment (/sen) to obtain a provisionally trusted LDevID + certificate. + + 3. If the Pledge determines that the pinned domain CA is (1) a root + CA certificate and (2) signer of the LDevID certificate, the + Pledge accepts the pinned domain CA certificate as the legitimate + trust anchor root CA for the Registrar's domain. It also accepts + the LDevID certificate as its new LDevID identity. And steps 4 + and 5 are skipped. + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 18] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 4. Otherwise, if the step 3 condition was not met, the Pledge MUST + perform a "CA certificates request" (/crts) to the EST server to + obtain the full set of EST CA trust anchors. It then MUST + attempt to chain the LDevID certificate to one of the CAs in the + set. + + 5. If the Pledge cannot obtain the set of CA certificates, or it is + unable to create the chain as defined in step 4, the Pledge MUST + abort the enrollment process and report the error using the + enrollment status telemetry (/es). + +6.7.2. Renewal of CA certificates + + An EST-coaps client that has an idea of the current time (internally, + or via Network Time Protocol) SHOULD consider the validity time of + the trust anchor CA(s), and MAY begin requesting new trust anchor + certificates(s) using the /crts request when the CA has 50% of it's + validity time (notAfter - notBefore) left. A client without access + to the current time cannot decide if trust anchor CA(s) have expired, + and SHOULD poll periodically for a new trust anchor certificate(s) + using the /crts request at an interval of approximately 1 month. An + EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6)in every response to a /crts request, to enable + clients to perform low-overhead validation whether their trust anchor + CA is still valid. The EST-coaps client SHOULD store the ETag + resulting from a /crts response in memory and SHOULD use this value + in an ETag Option in its next GET /crts request. + +6.7.3. Change of Domain Trust Anchor(s) + + The domain trust anchor(s) may change over time. Such a change may + happen due to relocation of the client device to a new domain, a new + subdomain, or due to a key update of a trust anchor as described in + [RFC4210], Section 4.4. + + From the client's viewpoint, a trust anchor change happens during + EST-coaps re-enrollment: since a change of domain CA requires all + devices operating under the old domain CA to acquire a new LDevID + certificate issued by the new domain CA. A client's re-enrollment + may be triggered by various events, such as an instruction to re- + enroll sent by a domain entity, or an imminent expiry of its LDevID + certificate, or other. How the re-enrollment is explicitly triggered + on the client by a domain entity, such as a commissioner or a + Registrar, is out of scope of this specification. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. Of these four, + + + +Richardson, et al. Expires 10 December 2026 [Page 19] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + the OldWithOld certificate is already stored in the client's Explicit + TA database. The other certificates will be provided to the client + in a /crts response, during the EST-coaps re-enrollment procedure. + +6.7.4. Re-enrollment Procedure + + For re-enrollment, the EST-coaps client MUST support the following + EST-coaps procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server, and + authenticates with its present domain certificate (LDevID) as + usual. The EST-coaps server authenticates itself with its domain + RA certificate that is currently trusted by the client, i.e. it + chains to a trust anchor CA that the client has stored in its + Explicit TA database. This is the OldWithOld trust anchor. The + client checks that the server is a Registration Authority (RA) of + the domain as required by Section 3.6.1 of [RFC7030] before + proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and + upon success it obtains a new LDevID certificate. + + 3. The client verifies the new LDevID certificate against its + Explicit TA database. If the new LDevID chains successfully to a + TA, this means trust anchors did not significantly change and the + client MAY skip retrieving the current CA certificates using the + "CA certificates request" (/crts). If it does not chain + successfully, it means trust anchor(s) were changed significantly + and the client MUST retrieve the new domain trust anchors using + the "CA certificates request" (/crts). + + 4. If the client retrieved new trust anchor(s) in step 3, then it + MUST verify that the new LDevID certificate it obtained in step 2 + chains with the new trust anchor(s). If it chains successfully, + the client stores the new trust anchor(s) in its Explicit TA + database, accepts the new LDevID certificate and stops using its + prior LDevID certificate. If it does not chain successfully, the + client MUST NOT update its LDevID certificate, and it MUST NOT + update its Explicit TA database, and the client MUST abort the + enrollment process and MUST attempt to report the error to the + EST-coaps server using enrollment status telemetry (/es). + + Note that even though the EST-coaps client may skip the /crts request + in step 3 at this time, it SHOULD still support renewal of the trust + anchors as detailed in Section 6.7.2. + + + + +Richardson, et al. Expires 10 December 2026 [Page 20] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Note that an EST-coaps server that is also a Registrar will already + support the enrollment status telemetry resource (/es) in step 4, + while an EST-coaps server that purely implements [RFC9148], and not + the present specification, will not support this resource. + +6.7.5. Multipart Content-Format for CA certificates (/crts) Resource + + In EST-coaps [RFC9148] the PKCS#7 container format is used for CA + certificates distribution. Because the PKCS#7 format is only used as + a certificate container and no additional security is applied on the + container, it becomes attractive to replace this format by something + simpler, on a constrained Pledge: so that additional PKCS#7 code is + avoided. Therefore, this document defines a container format using + the [RFC8710] application/multipart-core media type (CoAP content- + format 62). This is beneficial since a Pledge necessarily already + supports CBOR parsing, so there is little code overhead to support + this CBOR-based container format. + + A Registrar or EST-coaps server MUST support content-format 62 for + the /crts resource. The multipart collection MUST contain the + individual CA certificates, each encoded as an application/pkix-cert + (287) representation. Future documents may define other certificate + formats: the multipart collection can handle any future types. The + order of CA certificates MUST be in the CA hierarchy order starting + from the issuer of the client's LDevID first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy. These further CA certificates + may be Third-party TAs as defined in [RFC7030]. The highest-level + domain CA may or may not be a root CA certificate. + + As an example, for the two-level CA domain PKI of Figure 1 the + multipart container will contain two representations: + + [ , ] + + Encoded as an application/multipart-core CBOR array this is (shown in + CBOR diagnostic notation): + + [ 287, h'3082' ... 'd713', 287, h'3082' ... 'a034' ] + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 21] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The total number of CA certificates SHOULD be 1, 2 or 3 and not + higher to prevent constrained Pledges from running out of memory for + the trust anchor storage (Explicit TA database). However if a domain + operator can guarantee that any Pledges enrolled in its network can + support larger sets of CA certificates, the total number MAY be + configured as higher than 3. To facilitate a reliable transfer of + large payloads over constrained networks, the server MUST support + CoAP Block-wise transfer for the /crts response. The server MUST + also support the Size2 Option [RFC7959] to provide the total resource + length in bytes, when requested by a client. + + Implementation notes: a client that receives the first block of + payload data from the server, can already inspect the total number of + CA certificates by decoding the first byte of the payload. In CBOR + encoding, the respective first bytes 0x81-0x97 represent an array + with length 1-23, respectively. Furthermore, the length in bytes of + the first CA certificate can be already determined by decoding the + first bytes of the second element, because the CBOR encoding for + binary string includes the length of this string. A client that + requires an estimate of the total resource size (to be returned as + part of the first Block2 response from the server) can use a Size2 + Option with value 0 in its request. Knowing the overall progress of + the data transfer may be helpful in certain cases, e.g. when a Pledge + provides visual progress information on the onboarding progress. + +6.8. Registrar Extensions + + Before a Registrar forwards a COSE-signed voucher from MASA to the + Pledge, it MUST remove any 'x5bag' or 'x5chain' unprotected COSE + header attributes (which are defined in [RFC9360]). The contents of + these unprotected attributes are solely for validation/logging use by + the Registrar. Removing these attributes reduces the voucher size on + the constrained network path to the Pledge. + + The content-format 60 (application/cbor) MUST be supported by the + Registrar for the /vs and /es resources. + + Content-format 836 (application/voucher+cose) MUST be supported by + the Registrar for the /rv resource for CoAP POST requests, both as + request payload and as response payload. + + Content-format 287 (application/pkix-cert) MUST be supported by the + Registrar as a response payload for the /sen and /sren resources. + + When a Registrar receives a "CA certificates request" (/crts) request + with a CoAP Accept Option with value 287 (application/pkix-cert) it + MUST return only the single CA certificate that is the envisioned or + actual CA authority for the current, authenticated Pledge making the + + + +Richardson, et al. Expires 10 December 2026 [Page 22] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + request. An exception to this rule is when the domain has been + configured to operate with multiple CA trust anchors exclusively: + then the Registrar returns a 4.06 Not Acceptable error to signal to + the client that it needs to request another content-format that + supports retrieval of multiple CA certificates. + +7. BRSKI-MASA Protocol + + This section describes extensions to and clarifications of the BRSKI- + MASA protocol between Registrar and MASA. + +7.1. Protocol and Formats + + Section 5.4 of [RFC8995] describes a connection between the Registrar + and the MASA as being a normal TLS connection using HTTPS. This + document does not change that. + + The MASA only needs to support formats for which it has constructed + Pledges that use that format. + + The Registrar MUST use the same format for the RVR as the Pledge used + for its PVR. Specifically, the Registrar MUST use the media type + application/voucher+cose for its voucher request to MASA, when the + Pledge used content-format 836 in the payload of its request to the + Registrar. + + The Registrar indicates the voucher format (by media type) it wants + to receive from MASA using the HTTP Accept header. This format MUST + be the same as the format of the PVR, so that the Pledge can parse + the resulting voucher. + + At the moment of writing the creation of CoAPS based MASAs is deemed + unrealistic and unnecessary. The use of CoAP for the BRSKI-MASA + connection is out of scope but can be the subject of another + document. Some consideration was made to specify CoAP support for + consistency, but: + + * the Registrar is not expected to be so constrained that it cannot + support HTTPS client connections. + + * the technology and experience to build Internet-scale HTTPS + responders (which the MASA is) is common, while the experience + doing the same for CoAP is much less common. + + * a Registrar is likely to provide onboarding services to both + constrained and non-constrained devices. Such a Registrar would + need to speak HTTPS anyway. + + + + +Richardson, et al. Expires 10 December 2026 [Page 23] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + * a manufacturer is likely to offer both constrained and non- + constrained devices, so there may in practice be no situation in + which the MASA could be CoAP-only. Additionally, as the MASA is + intended to be a function that can easily be outsourced to a + third-party service provider, reducing the complexity would also + seem to reduce the cost of that function. + + * security-related considerations: see Section 14.3. + +7.2. Registrar Voucher Request + + If the PVR contains a proximity assertion, the Registrar MUST + propagate this assertion into the RVR by including the 'assertion' + attribute with the value "proximity". This conforms to the example + in Section 3.3 of [RFC8995] of carrying the assertion forward. + +7.3. MASA and the Server Name Indicator (SNI) + + A TLS/HTTPS connection is established between the Registrar and MASA. + + Section 5.4 of [RFC8995] explains this process, and there are no + externally visible changes made by this document. A MASA that + supports the unconstrained voucher formats should be able to support + constrained voucher formats equally well. + + There is no requirement that a single MASA be used for both + constrained and unconstrained voucher requests: the choice of MASA is + determined by the id-mod-MASAURLExtn2016 extension contained in the + IDevID, so it can be determined by the manufacturer. + + The Registrar MUST do DNS-ID checks ([RFC9525]) on the contents of + the certificate provided by the MASA during the TLS handshake. + + In contrast to the Pledge/Registrar situation, the Registrar always + knows the name of the MASA, and MUST always include an [RFC6066] + Server Name Indicator. The SNI is optional in TLS 1.2, but common. + The SNI is considered mandatory with TLS 1.3. + + The presence of the SNI extension is required by the MASA, in order + for the MASA's server to host multiple tenants (for different + customers). + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 24] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +7.4. Registrar Client Certificate Requirements + + The Registrar SHOULD use a TLS Client Certificate to authenticate to + the MASA per Section 5.4.1 of [RFC8995]. If the certificate that the + Registrar uses is marked as a id-kp-cmcRA certificate, via Extended + Key Usage, then it MUST also have the id-kp-clientAuth EKU attribute + set. + + In summary, for typical Registrar use, where a single Registrar + certificate is used for both client and server roles, the certificate + MUST have an EKU set with at least all of id-kp-cmcRA, id-kp- + serverAuth, and id-kp-clientAuth. + + These requirements update (and clarify) [RFC8995]. + +8. Pinning in Voucher Artifacts + + The voucher is a statement by the MASA for use by the Pledge that + provides the identity of the Pledge's owner. This section describes + how the owner's identity is determined and how it is specified within + the voucher. + +8.1. Registrar Identity Selection and Encoding + + Section 5.5 of [RFC8995] describes BRSKI policies for selection of + the owner identity. It indicates some of the flexibility enabled for + the Registrar, and recommends the Registrar to include only + certificates in the voucher request (CMS) signing structure that + participate in the certificate chain that is to be pinned. + + The MASA is expected to evaluate the certificates included in an RVR, + forming them into a chain with the Registrar's (signing) identity on + one end. Then, it pins a certificate selected from this chain + according to its pinning policy (Section 8.2). + + For instance, for a domain with a two-level certification authority + (see Figure 1), where the RVR has been signed by "domain Registrar", + the RVR includes the chain formed by the domain Registrar EE + certificate, the domain Sub-CA certificate, and the domain CA trust + anchor certificate. The arrows in the figure indicate the issuing of + a certificate, i.e. author of (1) issued (2) and author of (2) issued + (3). + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 25] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + .------------------. + | domain CA (1) | + | trust anchor | + '------------------' + | + v + .------------. + | domain (2) | + | Sub-CA | + '------------' + | + v + .----------------. + | domain | + | Registrar (3) | + | EE certificate | + '----------------' + + Figure 1: Two-Level CA PKI + + When the Registrar is using a COSE-signed RVR, the COSE_Sign1 object + contains a protected and an unprotected header. The Registrar MUST + place all the certificates needed by MASA to validate the signature + chain for its RVR in an 'x5bag' attribute in either the protected or + the unprotected header as defined in Section 2 of [RFC9360]. + +8.2. MASA Pinning Policy + + The MASA, having assembled and verified the certificate chain that + signed the RVR then needs to select a certificate to pin. (For the + case that only the Registrar's End-Entity certificate is included, + only this certificate can be selected and this section does not + apply.) The BRSKI policy for pinning by the MASA as described in + Section 5.5.2 of [RFC8995] leaves much flexibility to the + manufacturer. + + The present document adds the following rules to the MASA pinning + policy to reduce the network load on the constrained network side: + + 1. for a voucher containing a nonce, it SHOULD pin the most specific + (lowest-level) CA certificate in the chain. + + 2. for a nonceless voucher, it SHOULD pin the least-specific + (highest-level) CA certificate in the chain that is allowed under + the MASA's policy for this specific domain. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 26] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The rationale for 1. is that in case of a voucher with nonce, the + voucher is valid only in scope of the present DTLS connection between + Pledge and Registrar anyway, so there is no benefit to pin a higher- + level CA. By pinning the most specific CA the constrained Pledge can + validate its DTLS connection using less crypto operations. The + rationale for pinning a CA instead of the Registrar's End-Entity + certificate directly is based on the following benefit on constrained + networks: the pinned certificate in the voucher can in common cases + be re-used as a Domain CA trust anchor during the EST enrollment and + during the operational phase that follows after EST enrollment, as + explained in Section 6.7.1. + + The rationale for 2. follows from the flexible BRSKI trust model for, + and purpose of, nonceless vouchers (Sections 5.5.* and 7.4.1 of + [RFC8995]). + + Referring to the example of Figure 1 of a domain with a two-level + certification authority, the most specific CA ("Sub-CA") is the + identity that is pinned by MASA in a nonced voucher. + + In case of a nonceless voucher, depending on the trust level, the + MASA pins the "Registrar" certificate (low trust in customer), or the + "Sub-CA" certificate (in case of medium trust, implying that any + Registrar of that sub-domain is acceptable), or even the "domain CA" + certificate (in case of high trust in the customer, and possibly a + pre-agreed need of the customer to obtain flexible long-lived + vouchers). + +8.3. Pinning of Raw Public Keys (RPK) + + Specifically for the most-constrained use cases, the pinning of the + raw public key (RPK) of the Registrar is also supported in the + constrained voucher, instead of a PKIX certificate. This is used by + the RPK variant of cBRSKI described in Section 13, but it can also be + used in the default cBRSKI flow as a means to reduce voucher size. + + For both cases, if an RPK is pinned, it MUST be the RPK of the + Registrar, which equals the public key of the Registrar's EE + certificate. + + When the Pledge is known by MASA to support the RPK variant only, the + voucher produced by the MASA pins the RPK of the Registrar in either + the 'pinned-domain-pubk' or 'pinned-domain-pubk-sha256' attribute of + the voucher data. This is described in more detail in [RFC8366bis] + and Section 13. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 27] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + When the Pledge is known by MASA to support PKIX operations, the + 'pinned-domain-cert' attribute present in a voucher normally pins a + domain certificate. That can be either the End-Entity certificate of + the Registrar, or the certificate of a domain CA, as specified in + Section 8.2. However, if the Pledge is known by MASA to also support + RPK pinning and the MASA policy intends to pin the Registrar in the + voucher (and not a CA), then MASA SHOULD pin the RPK (RPK3 in + Figure 2) of the Registrar instead of the Registrar's End-Entity + certificate to save space in the voucher. + + .-------------. + .------------. | private | + | pub-CA (1) | | root-CA (1) | + '------------' '-------------' + | | + v .-------------. v + .------------. | private | .------------. + | sub-CA (2) | | root-CA (1) | | sub-CA (2) | + '------------' '-------------' '------------' + | | | + v v v + .--------------. .--------------. .--------------. + | Registrar(3) | | Registrar(3) | | Registrar(3) | + | RPK3 | | RPK3 | | RPK3 | + '--------------' '--------------' '--------------' + + Figure 2: Raw Public Key (RPK) pinning examples + +9. Artifacts + + The YANG ([RFC7950]) module and CBOR serialization for the + constrained voucher as used by cBRSKI are described in [RFC8366bis]. + That document also assigns SID values to YANG elements in accordance + with [RFC9254] and [RFC9595]. The present section provides some + examples of these artifacts and defines a new signature format for + these, using COSE. + + Compared to the first voucher request definition done in [RFC8995], + the constrained voucher request adds the attributes 'proximity- + registrar-pubk' and 'proximity-registrar-pubk-sha256'. One of these + is optionally used to replace the 'proximity-registrar-cert' + attribute, for a smaller voucher request data size - useful for the + most constrained cases. + + The constrained voucher adds the attributes 'pinned-domain-pubk' and + 'pinned-domain-pubk-sha256' to pin an RPK. One of these is + optionally used instead of the 'pinned-domain-cert' attribute, for a + smaller voucher data size. + + + +Richardson, et al. Expires 10 December 2026 [Page 28] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +9.1. Example Artifacts + +9.1.1. Example Pledge Voucher Request (PVR) Artifact + + Below, example voucher data from a constrained voucher request (PVR) + from a Pledge to a Registrar is shown in CBOR diagnostic notation. + Long CBOR byte strings have been shortened for readability, using the + ellipsis ("...") to indicate elided bytes. This notation is defined + in [I-D.ietf-cbor-edn-literals]. The enum value of the assertion + attribute is 2 for the 'proximity' assertion as defined in + Section 8.3 of [RFC8366bis]. + + { + 2501: { / SID=2501, ietf-voucher-request:voucher|voucher / + 1: 2, / SID=2502, assertion 2 = "proximity"/ + 7: h'831D5198A6CA2C7F', / SID=2508, nonce / + 12: h'30593013' ... '9A54', / SID=2513, proximity-registrar-pubk / + 13: "JADA123456789" / SID=2514, serial-number / + } + } + + The Pledge has included the attribute 'proximity-registrar-pubk' + which carries the public key of the Registrar, instead of including + the full Registrar certificate in a 'proximity-registrar-cert' + attribute. This is done to reduce the size of the PVR. Also note + that the Pledge did not include the 'created-on' attribute since it + lacks an internal real-time clock and has no knowledge of the current + time at the moment of performing the onboarding. + +9.1.2. Example Registrar Voucher Request (RVR) Artifact + + Next, example voucher data from a constrained voucher request (RVR) + from a Registrar to a MASA is shown in CBOR diagnostic notation. The + Registrar has created this request triggered by the reception of the + Pledge voucher request (PVR) of the previous example. Again, long + CBOR byte strings have been shortened for readability. + + { + "ietf-voucher-request:voucher": { + "assertion": 2, + "created-on": "2022-12-05T19:19:19.536Z", + "nonce": h'831D5198A6CA2C7F', + "idevid-issuer": h'04183016' ... '1736C3E0', + "serial-number": "JADA123456789", + "prior-signed-voucher-request": h'A11909' ... '373839' + } + } + + + + +Richardson, et al. Expires 10 December 2026 [Page 29] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Note that the Registrar uses here the string data type for all key + names, instead of the more compact SID integer keys. This is fine + for any use cases where the network between Registrar and MASA is an + unconstrained network where data size is not critical. The + constrained voucher request format supports both the string and SID + key types, for PVR as well as RVR. + +9.1.3. Example Voucher Artifacts + + Below, an example of constrained voucher data is shown in CBOR + diagnostic notation. It was created by a MASA in response to + receiving the Registrar Voucher Request (RVR) shown in Section 9.1.2. + The enum value of the 'assertion' attribute is set to "proximity" + (2), to acknowledge to both the Pledge and the Registrar that the + proximity of the Pledge to the Registrar is considered proven. + + { + 2451: { / SID = 2451, ietf-voucher:voucher|voucher / + 1: 2, / SID = 2452, assertion "proximity" / + 2: "2022-12-05T19:19:23Z", / SID = 2453, created-on / + 3: false, / SID = 2454, domain-cert-revocation-checks / + 7: h'831D5198A6CA2C7F', / SID = 2508, nonce / + 8: h'308201' ... '8CFF', / SID = 2459, pinned-domain-cert / + 11: "JADA123456789" / SID = 2462, serial-number / + } + } + + While the above example voucher data includes the nonce from the PVR, + the next example is for a nonce-less voucher. Instead of a nonce, it + includes an 'expires-on' attribute with the date and time on which + the voucher expires. Because the MASA did not verify the proximity + of the Pledge and Registrar in this case, the 'assertion' attribute + contains a weaker assertion of "verified" (0). This indicates that + the MASA verified the domain's ownership of the Pledge via some other + means. + + { + 2451: { / SID = 2451, ietf-voucher:voucher|voucher / + 1: 0, / SID = 2452, assertion "verified" / + 2: "2022-12-06T10:15:32Z", / SID = 2453, created-on / + 3: false, / SID = 2454, domain-cert-revocation-checks / + 4: "2022-12-13T10:15:32Z", / SID = 2455, expires-on / + 8: h'308201F8' ... 'FF', / SID = 2459, pinned-domain-cert / + 11: "JADA123456789" / SID = 2462, serial-number / + } + } + + + + + +Richardson, et al. Expires 10 December 2026 [Page 30] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The voucher is valid for one week. To verify the voucher's validity, + the Pledge would either need an internal real-time clock or some + external means of obtaining the current time, such as Network Time + Protocol (NTP) or a radio time signal receiver. + +9.2. Signing Voucher and Voucher Request Artifacts with COSE + + The COSE_Sign1 structure is discussed in Section 4.2 of [RFC9052]. + The CBOR object that carries the body, the signature, and the + information about the body and signature is called the COSE_Sign1 + structure. It is used when only one signature is used on the body. + + Support for ECDSA with SHA2-256 using curve secp256r1 (aka + prime256k1) is RECOMMENDED. Most current low power hardware has + support for acceleration of this algorithm. Future hardware designs + could omit this in favour of a newer algorithms. This is the ES256 + (-7) keytype from Table 1 of [RFC9053]. Support for curve secp256k1 + is OPTIONAL. + + Support for EdDSA using Curve 25519 is RECOMMENDED in new designs if + hardware support is available. This is keytype EDDSA (-8) from + Table 2 of [RFC9053]. A 'crv' parameter is necessary to specify the + Curve, for example value Ed25519 (6) from Table 18 of [RFC9053]. The + 'kty' field MUST be present, and it MUST be "OKP" (Table 17 of + [RFC9053]). + + A transition towards EdDSA is occurring in the industry. Some + hardware can accelerate only some algorithms with specific curves, + other hardware can accelerate any curve, and still other kinds of + hardware provide a tool kit for acceleration of any elliptic curve + algorithm. + + In general, the Pledge is expected to support only a single + algorithm, while the Registrar, usually not constrained, is expected + to support a wide variety of algorithms: both legacy ones and up-and- + coming ones via regular software updates. + + An example of the supported COSE_Sign1 object structure containing a + Pledge Voucher Request (PVR) is shown below. + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 31] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 18( / tag for COSE_Sign1 / + [ + h'A10126', / protected COSE header encoding: {1: -7} / + / which means { "alg": ES256 } / + {}, / unprotected COSE header parameters / + h'A119' ... '3839', / PVR payload wrapped in CBOR byte string / + h'4567' ... '1234' / PVR binary Sign1 signature / + ] + ) + + The [COSE-registry] specifies the integers/encoding for the 'alg' + field. The 'alg' field restricts the key usage for verification of + this COSE object to a particular cryptographic algorithm. + +9.2.1. Signing of Registrar Voucher Request (RVR) + + A Registrar MUST include a COSE 'x5bag' structure in the RVR as + explained in Section 8.1. Below, an example Registrar Voucher + Request (RVR) is shown that includes the 'x5bag' unprotected header + parameter (32). The bag contains two certificates in this case. + + 18( / tag for COSE_Sign1 / + [ + h'A10126', / protected COSE header encoding: {1: -7} / + / which means { "alg": ES256 } / + { / unprotected COSE header/ + 32: [h'308202' ... '20AE', h'308201' ... '8CFF'] / x5bag / + }, + h'A178' ... '7FED', / RVR payload wrapped in CBOR byte string / + h'E1B7' ... '2925' / RVR binary Sign1 signature / + ] + ) + + Besides storing the Registrar's own RVR-signing certificate chain + (per Section 8.1), the Registrar MUST include in the same 'x5bag' + structure all the certificates that the Pledge used to identify + itself in the Pledge/Registrar DTLS handshake, including the End- + Entity (IDevID) certificate and all CAs up to the root CA. This + serves two purposes: + + 1. A MASA that does not store the IDevIDs for all Pledges and their + related sub-CAs is still able to reconstruct the certificate + chain for a given Pledge and validate the Pledge's signature on + the PVR based purely on the root CA of the Pledge's manufacturer + that the MASA is storing. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 32] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 2. Diagnostic/debugging purposes: since the PVR's COSE signature + does not store any certificates related to the signer, but only + the signature itself, it can be useful for the MASA to log or + inspect the Pledge's certificate chain in case the onboarding + attempt fails. Having the complete signing certificate chain at + hand facilitates finding the root cause of the problem and helps + in the communication with the customer. + + A 'kid' (key ID) field is OPTIONAL in the unprotected COSE header + parameters map of a COSE object. If present, it identifies the + public key of the key pair that was used to sign the COSE message. + The value of the key identifier 'kid' parameter may be in any format + agreed between signer and verifier. Usually a hash of the public key + is used to identify the public key; but the choice of key identifier + method is vendor-specific. + + By default, a Registrar does not include a 'kid' parameter in the RVR + since the signing key is already identified by the signing + certificates chain included in the COSE 'x5bag' structure. A + Registrar nevertheless MAY use a 'kid' parameter in its RVR to + identify its signing key/identity. + + The method of generating such 'kid' value is vendor-specific and + SHOULD be configurable in the Registrar to support commonly used + methods. In order to support future business cases and supply chain + integrations, a Registrar using the 'kid' field MUST be configurable, + on a per-manufacturer basis, to select a particular method for + generating the 'kid' value such that it is compatible with the method + that the manufacturer expects. Note that the 'kid' field always has + a CBOR byte string (bstr) format. + + In Appendix C.4 a further example of a signed RVR is shown. + +9.2.2. Signing of Pledge Voucher Request (PVR) + + Like in the RVR, a 'kid' (key ID) field is also OPTIONAL in the PVR. + It can be used to identify the signing key/identity to the MASA. + + A Pledge by default SHOULD NOT use a 'kid' parameter in its PVR, + because its signing key is already identified by the Pledge's unique + serial number that is included in the PVR and (by the Registrar) in + the RVR. This achieves the smallest possible PVR data size while + still enabling the MASA to fully verify the PVR. Still, when + required the Pledge MAY use a 'kid' parameter in its PVR to help the + MASA identify the right public key to verify against. This can occur + for example if a Pledge has multiple IDevID identities. The 'kid' + parameter in this case may be an integer byte identifying one out of + N identities present, or it may be a hash of the public key, or + + + +Richardson, et al. Expires 10 December 2026 [Page 33] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + anything else the Pledge vendor decides. A Registrar normally SHOULD + ignore a 'kid' parameter used in a received PVR, as this information + is intended for the MASA. In other words, there is no need for the + Registrar to verify the contents of this field, but it may include it + in an audit log. + + The example below shows a PVR with 'kid' present as an unprotected + header parameter. + + 18( / tag for COSE_Sign1 / + [ + h'A10126', / protected COSE header encoding: {1: -7} / + / which means { "alg": ES256 } / + { + 4: h'59AB3E' / COSE "kid" header parameter / + }, + h'A119' ... '3839', / PVR payload wrapped in CBOR byte string / + h'5678' ... '7890' / PVR binary Sign1 signature / + ] + ) + + The Pledge SHOULD NOT use the 'x5bag' or 'x5chain' COSE header + parameters in the PVR. A Registrar that processes a PVR with such a + structure MUST ignore it, and MUST use only the TLS Client + Certificate extension for authentication of the Pledge. + + A situation where the Pledge MAY use the 'x5bag' or 'x5chain' + structure is for communication of certificate chains to the MASA. + This would arise in some vendor- specific situations involving + outsourcing of MASA functionality, or rekeying of the IDevID + certification authority. + + In Appendix C.3 a further example of a signed PVR is shown. + +9.2.3. Signing of Voucher by MASA + + The MASA SHOULD NOT use a 'kid' parameter in the voucher response, + because the MASA's signing key is already known to the Pledge. + Still, where needed the MASA MAY use a 'kid' parameter in the voucher + response to help the Pledge identify the right MASA public key to + verify against. This can occur for example if a Pledge has multiple + IDevID identities. + + The MASA SHOULD NOT include an 'x5bag' or 'x5chain' attribute in the + protected header of the voucher response, because normally a Pledge + already stores the required public key for validation of the signed + voucher. The exception case is if the MASA knows that the Pledge + doesn't pre-store the MASA's public key used for signing, and thus + + + +Richardson, et al. Expires 10 December 2026 [Page 34] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + the MASA needs to provide a certificate or certificate chain that + will enable linking the signing identity to a pre-stored Trust Anchor + (CA) in the Pledge. This approach is not recommended, because + including certificates in the protected 'x5bag' or 'x5chain' COSE + header parameters will significantly increase the size of the voucher + which impacts cBRSKI operation on constrained networks. + + For example, if the MASA signing key is based upon a PKI (see + [I-D.ietf-anima-masa-considerations] Section 2.3), and the Pledge + only pre-stores a manufacturer (root) CA identity in its Trust Store + which is not the identity that signs the voucher, then a certificate + chain needs to be included with the voucher in order for the Pledge + to validate the MASA signing CA's signature by validating the chain + up to the CA in its Trust Store. In BRSKI CMS signed vouchers + [RFC8995], the CMS structure has a place for such a certificate + chain. In cBRSKI COSE-signed vouchers, the 'x5bag' attribute + [RFC9360] placed in the COSE protected header parameters is used to + contain the needed certificates for the Pledge to form the chain. + + To signal the complete chain of the MASA's signing identity to the + Registrar, the MASA MUST include the complete chain of signing + certificates in an 'x5bag' attribute in the unprotected header of the + voucher. This allows the Registrar to optionally validate the + voucher before forwarding it to the Pledge, or to validate it for + logging purposes. There is no voucher size impact of including this + certificate chain in an unprotected 'x5bag' COSE header parameter for + constrained networks, because the Registrar will remove this + unprotected attribute prior to forwarding the voucher response to the + Pledge, as defined in Section 6.8. + + Note that cBRSKI currently does not support signing the voucher with + an RPK for which there is no corresponding certificate at all. If + the MASA wants to sign a voucher with an RPK that is not part of any + PKIX hierarchy, it creates a single self-signed "placeholder" root CA + certificate that uses the designated RPK as the public key. This + "placeholder" certificate is then included as the sole certificate in + an unprotected 'x5bag' header parameter, as defined in the previous + paragraph. + + Below, an example is shown of a COSE-signed voucher as created by + MASA. This example shows the common case where a protected 'x5bag' + (32) attribute is not used, while an unprotected 'x5bag' (32) + attribute is used to communicate the MASA's signature certificate + chain to the Registrar. The bag contains two certificates in this + example. One of these is the identity of the signer of the + COSE_Sign1 object, whose signature is stored as the last CBOR array + element in the below example. + + + + +Richardson, et al. Expires 10 December 2026 [Page 35] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 18( / tag for COSE_Sign1 / + [ + h'A10126', / protected COSE header encoding: {1: -7} / + / which means { "alg": ES256 } / + { / unprotected COSE header parameters / + 32: [h'308202' ... '20AE', h'308201' ... '8CFF'] / x5bag / + }, + h'A119' ... '3839', / voucher payload wrapped in CBOR byte str / + h'2A2C' ... '7FBF' / voucher binary Sign1 signature by MASA / + ] + ) + + In Appendix C.5 a further example of a signed voucher is shown. + +9.2.4. Optional Validation of Voucher by Registrar + + For a Registrar, validation of the voucher and/or the signature of + the voucher is optional, per Section 5.6 of [RFC8995]. However, if a + Registrar does perform the validation of the signature chain, + communicated in the 'x5bag' unprotected COSE header parameter (see + Section 9.2.3)), it MUST validate that one of the below cases hold: + + 1. The signature chain is a single self-signed root CA certificate + with a correct signature; and the public key in this certificate + is also the public key that signed the voucher. This represents + the case where a voucher has been effectively signed with an RPK. + + 2. The signature chain consists of one or more certificates that can + be chained to a known (preconfigured) trust root in the + Registrar. + + The above validation elements are needed only for cases where + (nonceless) vouchers are communicated over potentially unsecure + channels to the Registrar. Since the 'x5bag' header parameter is not + protected by the voucher's COSE signature, it could have been + modified in transit. + +9.2.5. Additional Information in the COSE Header + + The COSE header of the signed voucher can contain COSE header + parameters with additional information, to be used by the Pledge. + This information is additional to, and separate from, the voucher + data defined by [RFC8366bis]. + + An example of how this additional information can be used is adding a + CBOR Web Token (CWT, [RFC8392]) claim in the COSE header as defined + by [RFC9597], to encode the COSE signing time as an integer value in + an 'iat' (Issued At) CWT claim. This information in an integer + + + +Richardson, et al. Expires 10 December 2026 [Page 36] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + format may be useful for a Pledge that does not have date/time + parsing functions, so it is unable to parse the date/time string + value contained in the voucher. Many other types of CWT claims can + be included in a voucher in the same way, as needed for particular + use cases. + + Such additional information can also be included in a COSE header of + a voucher request by a Pledge, to be used by the MASA. + +10. Extensions to Discovery + + It is assumed that a Join Proxy (Section 6.4) seamlessly provides a + relayed DTLS connection between the Pledge and the Registrar. To use + a Join Proxy, a Pledge needs to discover it. For Pledge discovery of + a Join Proxy, this section extends Section 4.1 of [RFC8995] for the + cBRSKI case. + + In general, the Pledge may be one or more hops away from the + Registrar, where one hop means the Registrar is a direct link-local + neighbor of the Pledge. The case of one hop away can be considered + as a degenerate case, because a Join Proxy is not really needed then. + + The degenerate case would be unusual in constrained wireless network + deployments, because a Registrar would typically not have a wireless + network interface of the type used by constrained devices. Rather, + it would have a high-speed network interface. Nevertheless, the + situation where the Registrar is one hop away from the Pledge could + occur in various cases like wired IoT networks or in wireless + constrained networks where the Pledge is in radio range of a 6LoWPAN + Border Router (6LBR) ([RFC6775])and the 6LBR happens to host a + Registrar. + + In order to support the degenerate case, the Registrar SHOULD + announce itself as if it were a Join Proxy -- though it would + actually announce its real (stateful) Registrar CoAPS endpoint. No + actual Join Proxy functionality is then required on the Registrar. + + That way, a Pledge only needs to discover a Join Proxy, regardless of + whether it is one or more than one hop away from a relevant + Registrar. It first discovers the link-local address and the UDP + join-port of a Join Proxy. The Pledge then follows the cBRSKI + procedure of initiating a DTLS connection using the link-local + address and join-port of the Join Proxy. + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 37] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Once enrolled, a Pledge itself may function as a Join Proxy. The + decision whether or not to provide this functionality depends upon + many factors and is out of scope for this document. Such a decision + might depend upon the amount of energy available to the device, the + network bandwidth available, as well as CPU and memory availability. + + The process by which a Pledge discovers the Join Proxy, and how a + Join Proxy discovers the location of the Registrar, are the subject + of the remainder of this section. Further details on both these + topics are provided in [I-D.ietf-anima-constrained-join-proxy]. + +10.1. Discovery Operations by a Pledge + + The Pledge must discover the address/port and optionally the protocol + with which to communicate. The present document only defines coaps + (CoAP over DTLS) as the default protocol for cBRSKI, therefore + protocol discovery is out of scope. + + For the discovery method, this section only defines unsecured CoAP + discovery per Section 7 of [RFC7252] as the default method. This + uses CoRE Link Format [RFC6690] payloads. + + Section 11 briefly mentions other methods that apply to specific + deployment types or technologies. Details about these deployment- + specific methods, or yet other methods, new payload formats, or more + elaborate CoAP-based methods, may be defined in future documents such + as [I-D.ietf-anima-brski-discovery]. The more elaborate methods for + example may include discovering only Join Proxies that support a + particular desired onboarding protocol, voucher format, or cBRSKI + variant. + + Note that identifying the format of the voucher request and the + voucher is currently not a required part of the Pledge's discovery + operation. It is assumed that all Registrars support all relevant + voucher(-request) formats, while the Pledge only supports a single + format. A Pledge that makes a voucher request to a Registrar that + does not support that format will receive a CoAP 4.06 Not Acceptable + status code and the onboarding attempt will fail. + + Using CoAP discovery, a Pledge can discover a Join Proxy by sending a + link-local multicast discovery message to the All CoAP Nodes address + FF02::FD. Zero, one, or multiple Join Proxies may respond. The + handling of multiple responses and absence of responses cases follow + the guidelines of Section 4 of [RFC8995]. The discovery message is a + CoAP GET request on the URI path /.well-known/core using a URI query + "brski-jp=*". This target attribute ('brski-jp') is defined for the + specific purpose of discovering/advertising the join-port in + Section 8.2 of [I-D.ietf-anima-constrained-join-proxy]. + + + +Richardson, et al. Expires 10 December 2026 [Page 38] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Responding Join Proxies return a CoRE Link Format document with one + or more links. Each link indicates one CoAPS endpoint that offers + cBRSKI Join Proxy functionality. + + In case a Pledge selects a particular Join Proxy for cBRSKI + onboarding, it MUST use the link-local source address of the Join + Proxy's discovery response as the destination IP address for its + subsequent onboarding attempt. + +10.1.1. Examples + + Below, an example shows the Pledge's CoAP request and the Join + Proxy's CoAP response. The Join Proxy responds from its link-local + source address, which is not included in the discovery response + payload. In this example, the Join Proxy has allocated the dedicated + UDP port 8485 for DTLS connections. Traffic on that port from + Pledges is used for cBRSKI: + + REQ: GET coap://[ff02::fd]/.well-known/core?brski-jp=* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + <>;brski-jp=8485 + + In the following example, two Join Proxies respond to the multicast + query. The Join Proxies each use a slightly different CoRE Link + Format target attribute value encoding. While the first encoding is + more compact, both encodings are allowed per [RFC6690]. The Pledge + may now select one of the two Join Proxies for initiating its DTLS + connection. + + REQ: GET coap://[ff02::fd]/.well-known/core?brski-jp=* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + <>;brski-jp=8485 + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + <>;brski-jp="63245" + + In the final example, a single Join Proxy host responds with two + distinct cBRSKI endpoints. The Pledge may now select one of the two + CoAP endpoints for initiating its DTLS connection. + + + + +Richardson, et al. Expires 10 December 2026 [Page 39] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + REQ: GET coap://[ff02::fd]/.well-known/core?brski-jp=* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + <>;brski-jp=61616, + <>;brski-jp=61617;var="c509 v2" + + The first endpoint on port 61616 supports only the cBRSKI protocol as + defined by this document. The second endpoint, on port 61617, + supports the same cBRSKI protocol as well as additional variations or + extensions. In this example, these variations/extensions are encoded + using string values in a single attribute 'var'. This information + may be also encoded using other attributes defined by a future + specification. + + A Pledge not aware of these variations can safely ignore these + values, because the base cBRSKI protocol is supported by both + endpoints, as indicated by the target attribute ('brski-jp'). If + however a Pledge is aware of these variations, it can select the + endpoint with the variation it prefers, in case multiple options are + discovered. The use of attributes with a single base resource type + allows future extensibility of cBRSKI, and enables the Join Proxies + to support (newer) cBRSKI variants that are unknown to them. + +10.2. Discovery Operations by a Join Proxy + + A Join Proxy needs to discover a Registrar, either at the moment it + needs to relay data (of a Pledge) towards the Registrar, or prior to + that moment. For example, it may start Registrar discovery as soon + as it is requested to be enabled in a Join Proxy role. It may + periodically redo this discovery, or periodically or on-demand check + that the Registrar is still available in the network at the + discovered IP address. + + As shown in the final example in Section 10.1.1, a Join Proxy could + discover multiple Registrars in its network and present these options + to the Pledge. Each of these Registrars may support specific + variations/extensions of cBRSKI - which may be defined in future + documents. It is up to the administrator of the network how many + Registrars are enabled. + + Further details on CoAP discovery of the Registrar by a Join Proxy + are provided in Section 5.1 of + [I-D.ietf-anima-constrained-join-proxy]. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 40] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +11. Deployment-specific Discovery Considerations + + This section details how discovery of a Join Proxy is done by the + Pledge in specific deployment scenarios. Future work such as + [I-D.ietf-anima-brski-discovery] may define more details on discovery + operations in the specific deployments listed here. + +11.1. 6TiSCH Deployments + + In 6TiSCH networks, the Constrained Join Protocol (CoJP) is used as + described in [RFC9031]. Such networks are expected to use EDHOC + [RFC9528] for key management, which is out of scope of this document. + The IEEE 802.15.4 Enhanced Beacon has been extended in [RFC9032] to + allow for discovery of a 6TiSCH-compliant Join Proxy. + +11.2. IP networks using GRASP + + In IP networks that support GRASP [RFC8990], a Pledge can discover a + Join Proxy by listening for GRASP messages. GRASP supports mesh + networks, and can also be used over unencrypted Wi-Fi. + + Details of GRASP discovery of constrained Join Proxies are out of + scope of this document and may be defined in future work. + +11.3. IP networks using mDNS + + [RFC8995] defines a mechanism for the Pledge to discover a Join Proxy + by sending mDNS [RFC6762] queries. This mechanism can be used on any + IP network which does not have another recommended mechanism. It can + be used over unencrypted Wi-Fi. This mechanism does support link- + local Join Proxy discovery in mesh networks. However, it does not + support Registrar discovery by Join Proxies in mesh networks, because + the Registrar is typically not reachable by link-local communication + in that case. For this, another mechanism is needed, which is out of + scope of this document and may be defined in future work. + + A Pledge uses an mDNS PTR query for the name "_brski- + proxy._udp.local." to discover link-local constrained Join Proxies. + The label "_udp" here indicates a query for cBRSKI constrained Join + Proxies, as opposed to "_tcp" defined in [RFC8995] which is for + discovering BRSKI Proxies. + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 41] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +11.4. Thread Networks using Mesh Link Establishment (MLE) + + Thread [Thread] is a wireless mesh network protocol based on 6LoWPAN + [RFC6282] and other IETF protocols. In Thread, a new device + discovers potential Thread networks and Thread nodes to join by using + the Mesh Link Establishment (MLE) + [I-D.ietf-6lo-mesh-link-establishment] protocol. MLE uses the UDP + port number 19788. + + The new device sends discovery requests on different IEEE 802.15.4 + radio channels, to which Thread nodes (if any present) respond with a + discovery response containing information about their respective + network. The MLE discovery response message contains UDP port + information to signal the new device which UDP port to use for its + DTLS connection to the Join Proxy function. The link-local IPv6 + source address of the MLE response message indicates the address of + the Join Proxy. + + Once a suitable Thread node is selected as its Join Proxy, the new + device initiates a DTLS transport-layer secured connection to the + network's commissioning application, over a link-local single radio + hop to the selected Join Proxy. This link is not yet secured at the + radio/MAC link layer: link-layer security will be set up once the new + device is approved by the commissioning application to join the + Thread network, and it gets provisioned with network access + credentials. + + A Thread node that is capable to act as a Join Proxy will only enable + this role if the network-wide configuration data indicates that new + device commissioning is allowed. + +12. Design and Implementation Considerations + +12.1. Voucher Format and Encoding + + The design considerations for vouchers from Section 10 of + [RFC8366bis] apply. Specifically for CBOR encoding of voucher data, + one key difference with JSON encoding is that the names of the leaves + in the YANG definition do not affect the size of the resulting CBOR, + if the SID ([RFC9254], [RFC9595]) translation process is used that + assigns integers to the names. + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 42] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + To obtain the lowest code size and RAM use on the Pledge, it is + recommended that a Pledge is designed to only process/generate these + SID integers and not the lengthy strings. The MASA in that case is + required to generate the voucher data for that Pledge using only SID + integers. Yet, this MASA MUST still support both SID integers and + strings, to be able to process attribute (string) names in the RVR + which the Registrar may use. + +12.2. CoAP Usage + + A successful POST request to the Registrar's telemetry resources + (/vs, /es) returns a 2.04 Changed response with empty payload. + + A CoAP client sending a request should be aware that the server, even + in case of an empty payload, may use either a piggybacked CoAP + response (for example ACK with code 2.04) but may also respond with a + separate CoAP response. This is first an ACK message with code 0.0 + that acknowledges the reception of the request. It is followed by a + CON message with a code 2.04 response in a separate CoAP message. + See [RFC7252] for details. + +12.3. Use of cBRSKI with HTTPS + + This specification contains two major extensions to [RFC8995]: a + constrained voucher format (COSE), and a constrained transfer + protocol (CoAP). + + On constrained networks with constrained devices, it make senses to + use both together. However, this document does not mandate that this + be the only way. + + A given constrained device design and software may be re-used for + multiple device models, such as a model having only an IEEE 802.15.4 + radio, or a model having only an IEEE 802.11 (Wi-Fi) radio, or a + model having both these radios. A manufacturer of such device models + may wish to have code only for the use of the constrained voucher + format (COSE), and use it on all supported radios including the IEEE + 802.11 radio. For this radio, the software stack to support HTTP/TLS + may be already integrated into the radio module hence it is + attractive for the manufacturer to reuse this. This type of approach + is supported by this document. In the case that HTTPS is used, the + regular long [RFC8995] resource names are used, together with the new + application/voucher+cose media type described in this document. For + status telemetry requests, the format and requirements defined in + Section 6.5.1 remain unchanged. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 43] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Other combinations are possible, but they are not enumerated here. + New work such as [I-D.ietf-anima-jws-voucher] provides new formats + that may be usable over a number of different transports. In + general, sending larger payloads over constrained networks makes less + sense, while sending smaller payloads over unconstrained networks is + perfectly acceptable. + + The Pledge will in most cases support a single voucher format, which + it uses without negotiation i.e. without discovery of formats + supported. The Registrar, being unconstrained, is expected to + support all voucher formats. There will be cases where a Registrar + does not support a new format that a new Pledge uses, and this is an + unfortunate situation that will result in lack of interoperation. + + The responsibility for supporting new formats is on the Registrar. + +13. Raw Public Key Variant + +13.1. Introduction and Scope + + This section introduces a cBRSKI variant to further reduce the data + volume and complexity of the cBRSKI onboarding. The use of a raw + public key (RPK) in the pinning process can significantly reduce the + number of bytes sent over the wire and the number of round trips, and + reduce the code footprint in a Pledge. But it comes with a few + significant operational limitations. + + One simplification that comes with RPK use is that a Pledge can avoid + doing PKIX operations, such as certificate chain validation. + +13.2. DTLS Connection and Registrar Trust Anchor + + When the Pledge first connects to the Registrar, the connection to + the Registrar is provisional, as explained in Section 5.6.2 of + [RFC8995]. The Registrar normally provides its public key in a + TLSServerCertificate, and the Pledge uses that to validate that + integrity of the DTLS connection, but it does not validate the + identity of the provided certificate. + + As the TLSServerCertificate object is never verified directly by the + Pledge, sending it can be considered superfluous. So instead of + using a (TLSServer)Certificate of type X509 (see Section 4.4.2 of + [RFC8446]), a RawPublicKey object (as defined by [RFC7250]) is used. + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 44] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + A Registrar operating in a mixed environment can determine whether to + send a PKIX certificate chain or a Raw Public Key to the Pledge: this + is signaled by the Pledge. In the case the Pledge needs an RPK, it + includes the server_certificate_type of RawPublicKey. This is shown + in Section 5 of [RFC7250]. + + The Pledge MUST send a client_certificate_type of X509 (not an RPK), + so that the Registrar can properly identify the Pledge and distill + the MASA URI information from its IDevID certificate. + +13.3. The Pledge Voucher Request + + The Pledge puts the Registrar's public key into the 'proximity- + registrar-pubk' attribute of the Pledge Voucher Request (PVR). The + 'proximity-registrar-pubk-sha256' can alternatively be used for + efficiency, if the 32-bytes of a SHA256 hash turns out to be smaller + than a typical ECDSA key. + + As the format of the 'proximity-registrar-pubk' attribute is + identical to the TLS RawPublicKey data object, no manipulation at all + is needed to insert this attribute into the PVR. This approach + reduces the size of the PVR significantly, compared to including the + full certificate. + +13.4. The Voucher Response + + A returned voucher will have a 'pinned-domain-pubk' attribute with + the identical key as was found in the 'proximity-registrar-pubk' + attribute above, as well as being identical to the Registrar's RPK in + the currently active DTLS connection. (Or alternatively the MASA may + include the 'pinned-domain-pubk-sha256' attribute if it knows the + Pledge supports this attribute.) + + Validation of this key by the Pledge is what takes the DTLS + connection out of the provisional state; see Section 5.6.2 of + [RFC8995] for more details. + + The received voucher needs to be validated by the Pledge. The Pledge + needs to have a public key to validate the signature from the MASA on + the voucher. + + The MASA's public key counterpart of the (private) MASA signing key + MUST be already installed in the Pledge at manufacturing time. + Otherwise, the Pledge cannot validate the voucher's signature. + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 45] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +13.5. The Enrollment Phase + + A Pledge that does not support PKIX operations cannot use EST to + enroll; it has to use another method for enrollment without + certificates and the Registrar has to support this method also. For + example, an enrollment process that records an RPK owned by the + Pledge as a legitimate entity that is part of the domain. + + It is possible that the Pledge will not enroll after obtaining a + valid voucher, but instead will do only a network join operation (see + for example [RFC9031]). How the Pledge discovers this method and + details of such enrollment methods are out of scope of this document. + +14. Security Considerations + +14.1. Duplicate Serial Numbers + + If a manufacturer sold products with duplicated serial numbers, that + use the same MASA CA as their root of trust, a customer of one of + these products can potentially perform an attack where it uses a + voucher created for product 1 to onboard product 2. This attack only + works for nonceless vouchers. + + Note that such a situation could only arise due to manufacturer mis- + management or oversight. + + For example, imagine the same manufacturer makes light bulbs as well + as gas centrifuges, and said manufacturer does not uniquely allocate + product serial numbers. The attacker has obtained a light bulb which + happens to have the same serial number as an operational gas + centrifuge which it wishes to obtain access to. The attacker + performs a normal BRSKI onboarding for the light bulb, but then uses + the resulting nonceless voucher to onboard the gas centrifuge. The + attack requires that the gas centrifuge be returned to a state where + it is willing to perform a new onboarding operation. For example, a + factory reset. + + This attack is normally prevented by the mechanisms of using + different trust root CAs for different product lines, and/or using + unique serial numbers within a single MASA CA scope. + + Section 6.2 of [RFC8366bis] discusses cases of duplicated serial + numbers in products across different CAs and the role of the 'idevid- + issuer' attribute in the RVR and in the voucher to disambiguate these + products. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 46] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +14.2. IDevID Security in the Pledge + + The security of this protocol depends upon the Pledge identifying + itself to the Registrar using its manufacturer installed certificate: + the IDevID certificate. Associated with this certificate is the + IDevID private key, known only to the Pledge. Disclosure of this + private key to an attacker would permit the attacker to impersonate + the Pledge towards the Registrar, probably gaining access credentials + to that Registrar's network. + + If the IDevID private key disclosure is known to the manufacturer, + there is little recourse other than recall of the relevant part + numbers. The process for communicating this recall would be within + the BRSKI-MASA protocol. Neither this specification nor [RFC8995] + provides for consultation of a Certification Revocation List (CRL) or + Open Certificate Status Protocol (OCSP) by a Registrar when + evaluating an IDevID certificate. However, the BRSKI-MASA protocol + submits the IDevID from the Registrar to the manufacturer's MASA and + a manufacturer would have an opportunity to decline to issue a + voucher for a device which they believe has become compromised. + + It may be difficult for a manufacturer to determine when an IDevID + private key has been disclosed. Two situations present themselves: + in the first situation a compromised private key might be reused in a + counterfeit device, which is sold to another customer. This would + present itself as an onboarding of the same device in two different + networks. The manufacturer may become suspicious seeing two voucher + requests for the same device from different Registrars. Such + activity could be indistinguishable from a device which has been + resold from one operator to another, or re-deployed by an operator + from one location to another. + + In the second situation, an attacker having compromised the IDevID + private key of a device might then install malware into the same + device and attempt to return it to service. The device, now blank, + would go through a second onboarding process with the original + Registrar. Such a Registrar could notice that the device has been + "factory reset" and alert the operator to this situation. One remedy + against the presence of malware is through the use of Remote + Attestation such as described in [RFC9334]. Future work will need to + specify a background-check Attestation flow as part of the voucher + request/response process. Attestation may still require access to a + private key (e.g. IDevID private key) in order to sign Evidence, so a + primary goal should be to keep any private key safe within the + Pledge. + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 47] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + In larger, more expensive, systems there is budget (power, space, and + bill of materials) to include more specific defenses for a private + key. For instance, this includes putting the IDevID private key in a + Trusted Platform Module (TPM), or use of Trusted Execution + Environments (TEE) for access to the key. On smaller IoT devices, + the cost and power budget for an extra part is often prohibitive. + + It is becoming more and more common for CPUs to have an internal set + of one-time fuses that can be programmed (often they are "burnt" by a + laser) at the factory. This section of memory is only accessible in + some privileged CPU state. The use of this kind of CPU is + appropriate as it provides significant resistance against key + disclosure even when the device can be disassembled by an attacker. + + In a number of industry verticals, there is increasing concern about + counterfeit parts. These may be look-alike parts created in a + different factory, or parts which are created in the same factory + during an illegal night-shift, but which are not subject to the + appropriate level of quality control. The use of a manufacturer- + signed IDevID certificate provides for discovery of the pedigree of + each part, and this often justifies the cost of the security measures + associated with storing the private key. + +14.3. Security of the BRSKI-MASA Protocol + + Section 7.1 explains why no CoAPS version of the BRSKI-MASA protocol + is specified. The connection from the Registrar to the MASA + continues to be HTTPS as in [RFC8995]. + + This choice enables the BRSKI-MASA protocol, which operates over the + open Internet, to be secured using standard solutions that are + commonly used for HTTPS over the Internet. The use of UDP protocols + across the Internet is sometimes fraught with security challenges. + Denial-of-service attacks against UDP based protocols are trivial as + there is no three-way handshake as done for TCP. The three-way + handshake of TCP guarantees that the node sending the connection + request is reachable using the origin IP address. While DTLS + contains an option to do a stateless challenge -- a process actually + stronger than that done by TCP -- it is not yet common for this + mechanism to be available in hardware at multigigabit speeds. + + Also, in many enterprise networks outgoing UDP connections can be + treated as suspicious, which could effectively block CoAP connections + for some firewall configurations. Reducing the complexity of MASA + (i.e. less protocols supported) also reduces its potential attack + surface, which is relevant since the MASA is 24/7 exposed on the + Internet and accepting (untrusted) incoming connections. + + + + +Richardson, et al. Expires 10 December 2026 [Page 48] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +14.4. Registrar Certificate May Be Self-signed + + The provisional (D)TLS connection formed by the Pledge with the + Registrar does not authenticate the Registrar's identity. This + Registrar's identity is validated by the [RFC8366bis] voucher that is + issued by the MASA, signed with a trust anchor that was built-in to + the Pledge. + + The Registrar may therefore use any certificate, including a self- + signed one. The only restrictions on the certificate is that it MUST + have EKU bits set as detailed in Section 6.2 and Section 7.4. + +14.5. Use of RPK Alternatives to 'proximity-registrar-cert' + + In Section 9 of [RFC8366bis] two compact alternative attributes for + 'proximity-registrar-cert' are defined that include an RPK: + 'proximity-registrar-pubk' and 'proximity-registrar-pubk-sha256'. + The Pledge can use these attributes in its PVR to identify the + Registrar based on its public key only. Since the full certificate + of the proximate Registrar is not included, use of these attributes + by a Pledge implies that a Registrar could insert another certificate + with the same public key identity into the RVR. For example, an + older or a newer version of its certificate. The MASA will not be + able to detect such act by the Registrar. But since any certificate + the Registrar could insert in this way still encodes its own identity + the additional risk of using the RPK alternatives is negligible. + + When a Registrar sees a PVR that uses one of 'proximity-registrar- + pubk' or 'proximity-registrar-pubk-sha256' attributes, this implies + the Registrar must include the certificate identified by these + attributes into its RVR. Otherwise, the MASA is unable to verify + proximity. This requirement is already implied by the "MUST" + requirement in Section 8.1. + +15. IANA Considerations + +15.1. Resource Type Link Target Attribute Values Registry + + Additions to the "Resource Type (rt=) Link Target Attribute Values" + IANA registry, within the "CoRE Parameters" registry group are + specified below. + + Reference: [This RFC] + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 49] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + +==========+==============================================+ + | Value | Description | + +==========+==============================================+ + | brski | Base resource of all Bootstrapping Remote | + | | Secure Key Infrastructure (cBRSKI) resources | + +----------+----------------------------------------------+ + | brski.rv | cBRSKI request voucher resource | + +----------+----------------------------------------------+ + | brski.vs | cBRSKI voucher status telemetry resource | + +----------+----------------------------------------------+ + | brski.es | cBRSKI enrollment status telemetry resource | + +----------+----------------------------------------------+ + | ace.est | Base resource of all Enrollment over Secure | + | | Transport CoAPS (EST-coaps) resources | + +----------+----------------------------------------------+ + + Table 2: Resource Type (rt) link target attribute + values for cBRSKI and EST- coaps + + Note that the resource type "brski" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "brski.*" as defined by this + specification. Similarly, the resource type "ace.est" identifies a + base resource in a resource hierarchy, where its sub-resources each + have one of the resource types "ace.est.*" as defined by [RFC9148]. + +15.2. Media Types Registry + + This section registers the media type application/voucher+cose in the + "Media Types" IANA registry. This media type is used to indicate + that the content is a CBOR voucher or voucher request signed with a + COSE_Sign1 structure [RFC9052] as defined in this document. + +15.2.1. application/voucher+cose + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 50] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Type name: application + Subtype name: voucher+cose + Required parameters: N/A + Optional parameters: N/A + Encoding considerations: binary (CBOR) + Security considerations: Section 14 of [This RFC], and Section 12 + of [RFC 9052] for the COSE_Sign1 structured that is used. + Interoperability considerations: Section 15.2.2 of [This RFC] + Published specification: [This RFC] + Applications that use this media type: cBRSKI/ANIMA, 6TiSCH, and + other zero-touch onboarding systems + Fragment identifier considerations: N/A + Additional information: + Deprecated alias names for this type: N/A + Magic number(s): N/A + File extension(s): .vch + Macintosh file type code(s): N/A + Person & email address to contact for further information: IETF + ANIMA Working Group (anima@ietf.org) or IETF Operations and + Management Area Working Group (opsawg@ietf.org) + Intended usage: COMMON + Restrictions on usage: N/A + Author: ANIMA WG + Change controller: IETF + Provisional registration? (standards tree only): NO + +15.2.2. Interoperability Considerations for application/voucher+cose + + The media type defined here does not have any parameter to indicate + whether names are used, or SID integers are used, or both can be + mixed within a voucher data item. In absence of any specific further + knowledge about this, a mixed use of SID integers and names MUST be + assumed, which is equivalent to the application/yang-data+cbor media + type ([RFC9254]) without the optional 'id' parameter. + + Furthermore, + + * a Registrar assumes that mixed SIDs/names MAY be present in a + received PVR or voucher; + + * a MASA assumes that mixed SIDs/names MAY be present in a received + RVR; + + * a Pledge assumes, depending on its implementation, that SIDs are + present only, or names are present only, or mixed SIDs/names are + present in a received voucher. + + + + + +Richardson, et al. Expires 10 December 2026 [Page 51] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Because the MASA and Pledge are under control (either directly or by + contract) of the same manufacturer, they can be co-developed + regarding the type of identifiers produced and identifiers consumed + in order to guarantee interoperability. + +15.3. CoAP Content-Formats Registry + + IANA has allocated ID 836 from the "CoAP Content-Formats" registry as + shown below. + + +==========================+==========+=====+============+ + | Media type | Encoding | ID | Reference | + +==========================+==========+=====+============+ + | application/voucher+cose | - | 836 | [This RFC] | + +--------------------------+----------+-----+------------+ + + Table 3: Additions to the IANA CoAP Content-Formats + Registry + +15.4. Update to BRSKI Well-Known URIs Registry + + This section updates the "BRSKI Well-Known URIs" IANA registry of the + Bootstrapping Remote Secure Key Infrastructures (BRSKI) Parameters + Registry group, by adding a new column "Short Path Segment", + clarifying existing "Description" values, and renaming the column + "URI" to "Path Segment". + + The new "Short Path Segment" entry denotes a shorter alternative to + Path Segment for the resource that can be used by a client in a CoAP + request on a well-known BRSKI resource. A value "N/A" can be + registered to denote that there is no short path segment defined. + + The contents of the registry with these changes applied are as + follows: + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 52] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + +=================+============+=======================+============+ + | Path Segment | Short | Description | Reference | + | | Path | | | + | | Segment | | | + +=================+============+=======================+============+ + | requestvoucher | rv | Request voucher: | [RFC8995], | + | | | Pledge to Registrar, | [This RFC] | + | | | and Registrar to MASA | | + +-----------------+------------+-----------------------+------------+ + | voucher_status | vs | Voucher status | [RFC8995], | + | | | telemetry: Pledge to | [This RFC] | + | | | Registrar | | + +-----------------+------------+-----------------------+------------+ + | requestauditlog | N/A | Request audit log: | [RFC8995] | + | | | Registrar to MASA | | + +-----------------+------------+-----------------------+------------+ + | enrollstatus | es | Enrollment status | [RFC8995], | + | | | telemetry: Pledge to | [This RFC] | + | | | Registrar | | + +-----------------+------------+-----------------------+------------+ + + Table 4: Update of the IANA BRSKI Well-Known URIs Registry + +15.5. Structured Syntax Suffixes Registry + + This section registers the "+cose" suffix in the "Structured Syntax + Suffixes" IANA Registry based on the [RFC6838] procedure. + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 53] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Name: CBOR Object Signing and Encryption (COSE) object + +suffix: +cose + References: the application/cose media type [RFC9052] + Encoding considerations: binary (CBOR) + Interoperability considerations: + the application/cose media type has an optional parameter + "cose-type". Any new media type that uses the +cose suffix + and allows use of this parameter MUST specify this + explicitly, per Section 4.3 of [RFC6838]. If the parameter + "cose-type" is allowed, its usage MUST be identical to the + usage defined for the application/cose media type in + Section 2 of [RFC9052]. + A COSE processor handling a media type foo+cose and which + does not know the specific type "foo" SHOULD use the + cose-type COSE tag, if present, or cose-type parameter, if + present, to determine the specific COSE object type during + processing. If the specific type cannot be determined, + it MUST assume only the generic COSE object structure and + it MUST NOT perform security-critical operations using the + COSE object. + Fragment identifier considerations: N/A + Security considerations: see [RFC9052] + Contact: + IETF COSE Working Group (cose@ietf.org) or + IESG (iesg@ietf.org) + Author/Change controller: + IETF ANIMA Working Group (anima@ietf.org). + IESG has change control over this registration. + +16. References + +16.1. Normative References + + [I-D.ietf-anima-constrained-join-proxy] + Dijk, E., Richardson, M., Van der Stok, P., and P. + Kampanakis, "Join Proxy for Onboarding of Constrained + Network Elements", Work in Progress, Internet-Draft, + draft-ietf-anima-constrained-join-proxy-20, 8 June 2026, + . + + [I-D.ietf-core-uri-path-abbrev] + Amsüss, C. and M. Richardson, "URI-Path abbreviation in + CoAP", Work in Progress, Internet-Draft, draft-ietf-core- + uri-path-abbrev-04, 19 March 2026, + . + + + + +Richardson, et al. Expires 10 December 2026 [Page 54] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + [ieee802-1AR] + "IEEE 802.1AR Secure Device Identity", IEEE Standards + Association, 2018, + . + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC4193] Hinden, R. and B. Haberman, "Unique Local IPv6 Unicast + Addresses", RFC 4193, DOI 10.17487/RFC4193, October 2005, + . + + [RFC4210] Adams, C., Farrell, S., Kause, T., and T. Mononen, + "Internet X.509 Public Key Infrastructure Certificate + Management Protocol (CMP)", RFC 4210, + DOI 10.17487/RFC4210, September 2005, + . + + [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., + Housley, R., and W. Polk, "Internet X.509 Public Key + Infrastructure Certificate and Certificate Revocation List + (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008, + . + + [RFC6066] Eastlake 3rd, D., "Transport Layer Security (TLS) + Extensions: Extension Definitions", RFC 6066, + DOI 10.17487/RFC6066, January 2011, + . + + [RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer + Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347, + January 2012, . + + [RFC6690] Shelby, Z., "Constrained RESTful Environments (CoRE) Link + Format", RFC 6690, DOI 10.17487/RFC6690, August 2012, + . + + [RFC6762] Cheshire, S. and M. Krochmal, "Multicast DNS", RFC 6762, + DOI 10.17487/RFC6762, February 2013, + . + + [RFC7030] Pritikin, M., Ed., Yee, P., Ed., and D. Harkins, Ed., + "Enrollment over Secure Transport", RFC 7030, + DOI 10.17487/RFC7030, October 2013, + . + + + + +Richardson, et al. Expires 10 December 2026 [Page 55] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + [RFC7250] Wouters, P., Ed., Tschofenig, H., Ed., Gilmore, J., + Weiler, S., and T. Kivinen, "Using Raw Public Keys in + Transport Layer Security (TLS) and Datagram Transport + Layer Security (DTLS)", RFC 7250, DOI 10.17487/RFC7250, + June 2014, . + + [RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained + Application Protocol (CoAP)", RFC 7252, + DOI 10.17487/RFC7252, June 2014, + . + + [RFC7959] Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in + the Constrained Application Protocol (CoAP)", RFC 7959, + DOI 10.17487/RFC7959, August 2016, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + + [RFC8366bis] + Watsen, K., Richardson, M., Dijk, E., Eckert, T. T., and + Q. Ma, "A Voucher Artifact for Bootstrapping Protocols", + Work in Progress, Internet-Draft, draft-ietf-anima- + rfc8366bis-31, 14 May 2026, + . + + [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol + Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, + . + + [RFC8449] Thomson, M., "Record Size Limit Extension for TLS", + RFC 8449, DOI 10.17487/RFC8449, August 2018, + . + + [RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data + Definition Language (CDDL): A Notational Convention to + Express Concise Binary Object Representation (CBOR) and + JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, + June 2019, . + + [RFC8710] Fossati, T., Hartke, K., and C. Bormann, "Multipart + Content-Format for the Constrained Application Protocol + (CoAP)", RFC 8710, DOI 10.17487/RFC8710, February 2020, + . + + + + + +Richardson, et al. Expires 10 December 2026 [Page 56] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + [RFC8949] Bormann, C. and P. Hoffman, "Concise Binary Object + Representation (CBOR)", STD 94, RFC 8949, + DOI 10.17487/RFC8949, December 2020, + . + + [RFC8995] Pritikin, M., Richardson, M., Eckert, T., Behringer, M., + and K. Watsen, "Bootstrapping Remote Secure Key + Infrastructure (BRSKI)", RFC 8995, DOI 10.17487/RFC8995, + May 2021, . + + [RFC9031] Vučinić, M., Ed., Simon, J., Pister, K., and M. + Richardson, "Constrained Join Protocol (CoJP) for 6TiSCH", + RFC 9031, DOI 10.17487/RFC9031, May 2021, + . + + [RFC9032] Dujovne, D., Ed. and M. Richardson, "Encapsulation of + 6TiSCH Join and Enrollment Information Elements", + RFC 9032, DOI 10.17487/RFC9032, May 2021, + . + + [RFC9052] Schaad, J., "CBOR Object Signing and Encryption (COSE): + Structures and Process", STD 96, RFC 9052, + DOI 10.17487/RFC9052, August 2022, + . + + [RFC9053] Schaad, J., "CBOR Object Signing and Encryption (COSE): + Initial Algorithms", RFC 9053, DOI 10.17487/RFC9053, + August 2022, . + + [RFC9147] Rescorla, E., Tschofenig, H., and N. Modadugu, "The + Datagram Transport Layer Security (DTLS) Protocol Version + 1.3", RFC 9147, DOI 10.17487/RFC9147, April 2022, + . + + [RFC9148] van der Stok, P., Kampanakis, P., Richardson, M., and S. + Raza, "EST-coaps: Enrollment over Secure Transport with + the Secure Constrained Application Protocol", RFC 9148, + DOI 10.17487/RFC9148, April 2022, + . + + [RFC9254] Veillette, M., Ed., Petrov, I., Ed., Pelov, A., Bormann, + C., and M. Richardson, "Encoding of Data Modeled with YANG + in the Concise Binary Object Representation (CBOR)", + RFC 9254, DOI 10.17487/RFC9254, July 2022, + . + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 57] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + [RFC9360] Schaad, J., "CBOR Object Signing and Encryption (COSE): + Header Parameters for Carrying and Referencing X.509 + Certificates", RFC 9360, DOI 10.17487/RFC9360, February + 2023, . + + [RFC9525] Saint-Andre, P. and R. Salz, "Service Identity in TLS", + RFC 9525, DOI 10.17487/RFC9525, November 2023, + . + +16.2. Informative References + + [COSE-registry] + IANA, "CBOR Object Signing and Encryption (COSE) registry + group", 11 January 2017, + . + + [I-D.ietf-6lo-mesh-link-establishment] + Kelsey, R., "Mesh Link Establishment", Work in Progress, + Internet-Draft, draft-ietf-6lo-mesh-link-establishment-00, + 1 December 2015, . + + [I-D.ietf-anima-brski-discovery] + Eckert, T. T. and E. Dijk, "BRSKI discovery and + variations", Work in Progress, Internet-Draft, draft-ietf- + anima-brski-discovery-11, 18 March 2026, + . + + [I-D.ietf-anima-jws-voucher] + Werner, T. and M. Richardson, "JWS signed Voucher + Artifacts for Bootstrapping Protocols", Work in Progress, + Internet-Draft, draft-ietf-anima-jws-voucher-16, 15 + January 2025, . + + [I-D.ietf-anima-masa-considerations] + Richardson, M., Werner, T., and P. C. Liu, "Operational + Considerations for Voucher infrastructure for BRSKI MASA", + Work in Progress, Internet-Draft, draft-ietf-anima-masa- + considerations-02, 26 March 2026, + . + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 58] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + [I-D.ietf-cbor-edn-literals] + Bormann, C., "Concise Diagnostic Notation (CDN)", Work in + Progress, Internet-Draft, draft-ietf-cbor-edn-literals-25, + 18 May 2026, . + + [I-D.ietf-cose-cbor-encoded-cert] + Mattsson, J. P., Selander, G., Raza, S., Höglund, J., + Furuhed, M., and L. Liao, "CBOR Encoded X.509 Certificates + (C509 Certificates)", Work in Progress, Internet-Draft, + draft-ietf-cose-cbor-encoded-cert-19, 11 May 2026, + . + + [I-D.ietf-uta-tls13-iot-profile] + Tschofenig, H., Fossati, T., Richardson, M., and D. + Migault, "TLS/DTLS 1.3 Profiles for the Internet of + Things", Work in Progress, Internet-Draft, draft-ietf-uta- + tls13-iot-profile-21, 25 May 2026, + . + + [RFC4443] Conta, A., Deering, S., and M. Gupta, Ed., "Internet + Control Message Protocol (ICMPv6) for the Internet + Protocol Version 6 (IPv6) Specification", STD 89, + RFC 4443, DOI 10.17487/RFC4443, March 2006, + . + + [RFC5652] Housley, R., "Cryptographic Message Syntax (CMS)", STD 70, + RFC 5652, DOI 10.17487/RFC5652, September 2009, + . + + [RFC6282] Hui, J., Ed. and P. Thubert, "Compression Format for IPv6 + Datagrams over IEEE 802.15.4-Based Networks", RFC 6282, + DOI 10.17487/RFC6282, September 2011, + . + + [RFC6775] Shelby, Z., Ed., Chakrabarti, S., Nordmark, E., and C. + Bormann, "Neighbor Discovery Optimization for IPv6 over + Low-Power Wireless Personal Area Networks (6LoWPANs)", + RFC 6775, DOI 10.17487/RFC6775, November 2012, + . + + [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type + Specifications and Registration Procedures", BCP 13, + RFC 6838, DOI 10.17487/RFC6838, January 2013, + . + + + + +Richardson, et al. Expires 10 December 2026 [Page 59] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + [RFC7228] Bormann, C., Ersue, M., and A. Keranen, "Terminology for + Constrained-Node Networks", RFC 7228, + DOI 10.17487/RFC7228, May 2014, + . + + [RFC7950] Bjorklund, M., Ed., "The YANG 1.1 Data Modeling Language", + RFC 7950, DOI 10.17487/RFC7950, August 2016, + . + + [RFC8392] Jones, M., Wahlstroem, E., Erdtman, S., and H. Tschofenig, + "CBOR Web Token (CWT)", RFC 8392, DOI 10.17487/RFC8392, + May 2018, . + + [RFC8990] Bormann, C., Carpenter, B., Ed., and B. Liu, Ed., "GeneRic + Autonomic Signaling Protocol (GRASP)", RFC 8990, + DOI 10.17487/RFC8990, May 2021, + . + + [RFC9334] Birkholz, H., Thaler, D., Richardson, M., Smith, N., and + W. Pan, "Remote ATtestation procedureS (RATS) + Architecture", RFC 9334, DOI 10.17487/RFC9334, January + 2023, . + + [RFC9528] Selander, G., Preuß Mattsson, J., and F. Palombini, + "Ephemeral Diffie-Hellman Over COSE (EDHOC)", RFC 9528, + DOI 10.17487/RFC9528, March 2024, + . + + [RFC9595] Veillette, M., Ed., Pelov, A., Ed., Petrov, I., Ed., + Bormann, C., and M. Richardson, "YANG Schema Item + iDentifier (YANG SID)", RFC 9595, DOI 10.17487/RFC9595, + July 2024, . + + [RFC9597] Looker, T. and M.B. Jones, "CBOR Web Token (CWT) Claims in + COSE Headers", RFC 9597, DOI 10.17487/RFC9597, June 2024, + . + + [Thread] Thread Group, Inc, "Thread Group website", June 2026, + . + +Appendix A. Software and Library Support for cBRSKI + + This appendix lists software and security libraries that may be + useful for implementing cBRSKI functionality. + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 60] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +A.1. Open Source cBRSKI Implementations + + There are a few ongoing open source projects to support cBRSKI + development and testing. These include: + + * OpenThread Registrar (OT Registrar) - a cBRSKI Registrar, test + MASA server, and test Pledge written in Java. Link + (https://github.com/EskoDijk/ot-registrar) + + * OpenThread CCM (pre-alpha) - a cBRSKI Pledge and Join Proxy for + OpenThread-based IoT nodes, written in C/C++. OpenThread nodes + implement the [Thread] protocol. Link + (https://github.com/EskoDijk/openthread/pull/7) + + * OpenThread Network Simulator v2 (OTNS2) - a CLI + GUI simulator + for OpenThread IoT nodes in 6LoWPAN [RFC6282] mesh networks, able + to accurately simulate cBRSKI Pledges onboarding (pre-alpha + functionality) to a Thread mesh network via an OT Registrar. Link + (https://github.com/EskoDijk/ot-ns/pull/165) + + * Fountain - a BRSKI/6TiSCH Registrar with support for COSE-signed + vouchers, written in Ruby. Link (https://github.com/AnimaGUS- + minerva/fountain) + +A.2. Security Library Support + + For the implementation of BRSKI/cBRSKI, the use of a software library + to manipulate PKIX certificates, establish secure (D)TLS connections, + and use crypto algorithms is often beneficial. Two C-based examples + are OpenSSL and mbedtls. Others more targeted to specific platforms + or languages exist. It is important to realize that the library + interfaces differ significantly between libraries. + + Libraries do not support all known crypto algorithms. Before + deciding on a library, it is important to look at their supported + crypto algorithms and the roadmap for future support. Apart from + availability, the library footprint, and the required execution + cycles should be investigated beforehand. + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 61] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The handling of certificates usually includes the checking of a + certificate chain. In some libraries, chains are constructed and + verified on the basis of a set of certificates, the trust anchor + (usually a self signed root CA), and the target certificate. In + other libraries, the chain must be constructed beforehand and obey + ordering criteria. Verification always includes the checking of the + signatures. Less frequent is the checking the validity of the dates + or checking the existence of a revoked certificate in the chain + against a set of revoked certificates. Checking the chain on the + consistency of the certificate extensions which specify the use of + the certificate usually needs to be programmed explicitly. + + A library can be used to construct a (D)TLS connection. It is useful + to realize that differences between (D)TLS implementations will occur + due to the differences in the certificate checks supported by the + library. On top of that, checks between client and server + certificates enforced by (D)TLS are not always helpful for a BRSKI + implementation. For example, the certificates of Pledge and + Registrar are usually not related when the BRSKI protocol is started. + It must be verified that checks on the relation between client and + server certificates do not hamper a succeful DTLS connection + establishment. + +A.2.1. OpensSSL Example Code + + From OpenSSL's apps/verify.c : + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 62] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + + X509 *x = NULL; + int i = 0, ret = 0; + X509_STORE_CTX *csc; + STACK_OF(X509) *chain = NULL; + int num_untrusted; + + x = load_cert(file, "certificate file"); + if (x == NULL) + goto end; + + csc = X509_STORE_CTX_new(); + if (csc == NULL) { + BIO_printf(bio_err, "error %s: X.509 store context" + "allocation failed\n", + (file == NULL) ? "stdin" : file); + goto end; + } + + X509_STORE_set_flags(ctx, vflags); + if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) { + X509_STORE_CTX_free(csc); + BIO_printf(bio_err, + "error %s: X.509 store context" + "initialization failed\n", + (file == NULL) ? "stdin" : file); + goto end; + } + if (tchain != NULL) + X509_STORE_CTX_set0_trusted_stack(csc, tchain); + if (crls != NULL) + X509_STORE_CTX_set0_crls(csc, crls); + + i = X509_verify_cert(csc); + X509_STORE_CTX_free(csc); + + + +A.2.2. mbedTLS Example Code + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 63] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + + mbedtls_x509_crt cert; + mbedtls_x509_crt caCert; + uint32_t certVerifyResultFlags; + // ... + int result = mbedtls_x509_crt_verify(&cert, &caCert, NULL, NULL, + &certVerifyResultFlags, NULL, NULL); + + + +A.3. Generating Certificates with OpenSSL + + This informative appendix shows example Bash shell scripts to + generate test PKIX certificates for the Pledge IDevID, the Registrar + and the MASA. The shell scripts cannot be run stand-alone because + they depend on input files which are not all included in this + appendix. Nevertheless, these scripts may provide guidance on how + OpenSSL can be configured for generating cBRSKI certificates. + + The scripts were tested with OpenSSL 3.0.2. Older versions may not + work -- OpenSSL 1.1.1 for example does not support all extensions + used. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 64] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + + #!/bin/bash + # File: create-cert-Pledge.sh + # Create new cert for: Pledge IDevID + + # days certificate is valid - aim for the last day of 9999, near + # the 802.1AR "does not expire" end date 9999-12-31 23:59:59Z. + # notBefore defaults to 'now', and openssl x509 requires whole days, + # notAfter lands on 9999-12-31 at the current time-of-day. Truncating + # day count keeps notAfter at or below the X.509 max date (going past + # it makes OpenSSL silently emit an empty cert). + SECONDS1=`date +%s` # time now (= cert notBefore) + SECONDS2=`date --date="9999-12-31 23:59:59Z" +%s` # target end date + let VALIDITY="(${SECONDS2}-${SECONDS1})/(24*3600)" + echo "Using validity param -days ${VALIDITY}" + + NAME=pledge + + # create csr for device + # conform to 802.1AR guidelines, using only CN + serialNumber when + # manufacturer is already present as CA. + # CN is not even mandatory, but just good practice. + openssl req -new -key keys/privkey_pledge.pem -out $NAME.csr -subj \ + "/CN=Stok IoT sensor Y-42/serialNumber=JADA123456789" + + # sign csr - notBefore defaults to 'now', notAfter = now + VALIDITY + openssl x509 -set_serial 32429 -CAform PEM -CA output/masa_ca.pem \ + -CAkey keys/privkey_masa_ca.pem -extfile x509v3.ext -extensions \ + pledge_ext -req -in $NAME.csr -out output/$NAME.pem \ + -days $VALIDITY -sha256 + + # Note: alternative method using 'ca' command. Currently + # doesn't work without 'country' subject field. + # openssl ca -rand_serial -enddate 99991231235959Z -certform PEM \ + # -cert output/masa_ca.pem -keyfile keys/privkey_masa_ca.pem \ + # -extfile x509v3.ext -extensions pledge_ext -in $NAME.csr \ + # -out $NAME.pem -outdir output + + # delete temp files + rm -f $NAME.csr + + # convert to .der format + openssl x509 -in output/$NAME.pem -inform PEM -out output/$NAME.der \ + -outform DER + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 65] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + + # File: x509v3.ext + # This file contains all X509v3 extension definitions for OpenSSL + # certificate generation. Each certificate has its own _ext + # section below. + + [ req ] + prompt = no + + [ masa_ca_ext ] + subjectAltName=email:info@masa.stok.nl + keyUsage = critical,digitalSignature, keyCertSign, cRLSign + basicConstraints = critical,CA:TRUE,pathlen:3 + subjectKeyIdentifier=hash + authorityKeyIdentifier=keyid + + [ pledge_ext ] + keyUsage = critical,digitalSignature, nonRepudiation, \ + keyEncipherment, dataEncipherment + # basicConstraints for a non-CA cert MAY be marked either + # non-critical or critical. + basicConstraints = CA:FALSE + # Don't include subjectKeyIdentifier (SKI) - see 802.1AR-2018 + subjectKeyIdentifier = none + authorityKeyIdentifier=keyid + # Include the MASA URI + 1.3.6.1.5.5.7.1.32 = ASN1:IA5STRING:masa.stok.nl + + [ domain_ca_ext ] + subjectAltName=email:help@custom-er.example.com + keyUsage = critical, keyCertSign, digitalSignature, cRLSign + basicConstraints=critical,CA:TRUE + # RFC 5280 4.2.1.1 : AKI MAY be omitted, and MUST be non-critical; + # SKI MUST be non-critical + subjectKeyIdentifier=hash + + [ masa_ext ] + keyUsage = critical, digitalSignature, nonRepudiation, \ + keyEncipherment, dataEncipherment + basicConstraints=CA:FALSE + subjectKeyIdentifier=hash + authorityKeyIdentifier=keyid + # Set TLS server (and client) usage for the MASA's TLS endpoint. + # see www.openssl.org/docs/man1.1.1/man5/x509v3_config.html + extendedKeyUsage = critical, serverAuth, clientAuth + + [ registrar_ext ] + keyUsage = critical, digitalSignature, nonRepudiation, \ + + + +Richardson, et al. Expires 10 December 2026 [Page 66] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + keyEncipherment, dataEncipherment + basicConstraints=CA:FALSE + subjectKeyIdentifier=hash + authorityKeyIdentifier=keyid + # Set Registrar 'RA' flag along with TLS client/server usage + # see draft-ietf-anima-constrained-voucher#section-7.3 + # see tools.ietf.org/html/rfc6402#section-2.10 + # see www.openssl.org/docs/man1.1.1/man5/x509v3_config.html + extendedKeyUsage = critical,1.3.6.1.5.5.7.3.28, serverAuth, \ + clientAuth + + + + + #!/bin/bash + # File: create-cert-Registrar.sh + # Create new cert for: Registrar in a company domain + + # days certificate is valid + VALIDITY=1095 + + # cert filename + NAME=registrar + + # create csr + openssl req -new -key keys/privkey_registrar.pem -out $NAME.csr \ + -subj "/CN=Custom-ER Registrar/OU=Office dept/O=Custom-ER, Inc./\ + L=Ottowa/ST=ON/C=CA" + + # sign csr + openssl x509 -set_serial 0xC3F62149B2E30E3E -CAform PEM -CA \ + output/domain_ca.pem -extfile x509v3.ext -extensions registrar_ext \ + -req -in $NAME.csr -CAkey keys/privkey_domain_ca.pem \ + -out output/$NAME.pem -days $VALIDITY -sha256 + + # delete temp files + rm -f $NAME.csr + + # convert to .der format + openssl x509 -in output/$NAME.pem -inform PEM -out output/$NAME.der \ + -outform DER + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 67] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + + #!/bin/bash + # File: create-cert-MASA.sh + # Create new cert for: MASA CA, self-signed CA certificate + + # days certificate is valid + VALIDITY=3650 + + NAME=masa_ca + + # create csr + openssl req -new -key keys/privkey_masa_ca.pem -out $NAME.csr \ + -subj "/CN=masa.stok.nl/O=vanderstok/L=Helmond/C=NL" + + # sign csr + mkdir output >& /dev/null + openssl x509 -set_serial 0xE39CDA17E1386A0A -extfile x509v3.ext \ + -extensions masa_ca_ext -req -in $NAME.csr \ + -signkey keys/privkey_masa_ca.pem -out output/$NAME.pem \ + -days $VALIDITY -sha256 + + # delete temp files + rm -f $NAME.csr + + # convert to .der format + openssl x509 -in output/$NAME.pem -inform PEM -out output/$NAME.der \ + -outform DER + + + +Appendix B. cBRSKI Message Examples + + This appendix extends the EST-coaps message examples from Appendix A + of [RFC9148] with cBRSKI messages. The CoAP headers are only fully + worked out for the first example, enrollstatus. + +B.1. enrollstatus + + A coaps enrollstatus message from Pledge to Registrar can be as + follows: + + REQ: POST /b/es + Content-Format: 60 (application/cbor) + Payload: + + The corresponding CoAP header fields for this request are shown + below. + + + + +Richardson, et al. Expires 10 December 2026 [Page 68] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Ver = 1 + T = 0 (CON) + TKL = 1 + Code = 0x02 (0.02 is POST method) + Message ID = 0xab0f + Token = 0x4d + Options + Option (Uri-Path) + Option Delta = 0xb (option nr = 11) + Option Length = 0x1 + Option Value = "b" + Option (Uri-Path) + Option Delta = 0x0 (option nr = 11) + Option Length = 0x2 + Option Value = "es" + Option (Content-Format) + Option Delta = 0x1 (option nr = 12) + Option Length = 0x1 + Option Value = 60 (application/cbor) + Payload Marker = 0xFF + Payload = A26776657273696F6E0166737461747573F5 (18 bytes binary) + + The Uri-Host and Uri-Port Options are omitted because they coincide + with the transport protocol (UDP) destination address and port + respectively. + + The above binary CBOR enrollstatus payload looks as follows in CBOR + diagnostic notation, for the case of enrollment success: + + { + "version": 1, + "status": true + } + + Alternatively the payload could look as follows in case of enrollment + failure, using the 'reason' map item value to describe the failure: + + Payload = A36776657273696F6E0166737461747573F466726561736F6E782A3C + 496E666F726D61746976652068756D616E207265616461626C652065 + 72726F72206D6573736167653E (69 bytes binary) + + { + "version": 1, + "status": false, + "reason": "" + } + + + + + +Richardson, et al. Expires 10 December 2026 [Page 69] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + To indicate successful reception of the enrollmentstatus telemetry + report, a response from the Registrar may then be: + + 2.04 Changed + + Which in case of a piggybacked response has the following CoAP header + fields: + + Ver=1 + T=2 (ACK) + TKL=1 + Code = 0x44 (2.04 Changed) + Message ID = 0xab0f + Token = 0x4d + +B.2. voucher_status + + A coaps voucher_status message from Pledge to Registrar can be as + follows: + + REQ: POST /.well-known/brski/vs + Content-Format: 60 (application/cbor) + Payload: + A46776657273696F6E0166737461747573F466726561736F6E7828496E66 + 6F726D61746976652068756D616E2D7265616461626C65206572726F7220 + 6D6573736167656E726561736F6E2D636F6E74657874A100764164646974 + 696F6E616C20696E666F726D6174696F6E + + The request payload above is binary CBOR but represented here in + hexadecimal for readability. Below is the equivalent CBOR diagnostic + format. + + { + "version": 1, + "status": false, + "reason": "Informative human-readable error message", + "reason-context": { 0: "Additional information" } + } + + A success response without payload will then be sent by the Registrar + back to the Pledge to indicate reception of the telemetry report: + + RES: 2.04 Changed + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 70] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +Appendix C. COSE-signed Voucher (Request) Examples + + This appendix provides examples of COSE-signed voucher requests and + vouchers. First, the used test keys and PKIX certificates are + described, followed by examples of a constrained PVR, RVR and + voucher. + +C.1. Pledge, Registrar and MASA Keys + + This section documents the public and private keys used for all + examples in this appendix. These keys are not used in any production + system, and must only be used for testing purposes. + +C.1.1. Pledge IDevID Private Key + + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIMv+C4dbzeyrEH20qkpFlWIH2FFACGZv9kW7rNWtSlYtoAoGCCqGSM49 + AwEHoUQDQgAESH6OUiYFRhfIgWl4GG8jHoj8a+8rf6t5s1mZ/4SePlKom39GQ34p + VYryJ9aHmboLLfz69bzICQFKbkoQ5oaiew== + -----END EC PRIVATE KEY----- + + Private-Key: (256 bit) + priv: + cb:fe:0b:87:5b:cd:ec:ab:10:7d:b4:aa:4a:45:95: + 62:07:d8:51:40:08:66:6f:f6:45:bb:ac:d5:ad:4a: + 56:2d + pub: + 04:48:7e:8e:52:26:05:46:17:c8:81:69:78:18:6f: + 23:1e:88:fc:6b:ef:2b:7f:ab:79:b3:59:99:ff:84: + 9e:3e:52:a8:9b:7f:46:43:7e:29:55:8a:f2:27:d6: + 87:99:ba:0b:2d:fc:fa:f5:bc:c8:09:01:4a:6e:4a: + 10:e6:86:a2:7b + ASN1 OID: prime256v1 + NIST CURVE: P-256 + +C.1.2. Registrar Private Key + + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYJ/MP0dWA9BkYd4W + s6oRY62hDddaEmrAVm5dtAXE/UGhRANCAAQgMIVb6EaRCz7LFcr4Vy0+tWW9xlSh + Xvr27euqi54WCMXJEMk6IIaPyFBNNw8bJvqXWfZ5g7t4hj7amsvqUST2 + -----END PRIVATE KEY----- + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 71] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Private-Key: (256 bit) + priv: + 60:9f:cc:3f:47:56:03:d0:64:61:de:16:b3:aa:11: + 63:ad:a1:0d:d7:5a:12:6a:c0:56:6e:5d:b4:05:c4: + fd:41 + pub: + 04:20:30:85:5b:e8:46:91:0b:3e:cb:15:ca:f8:57: + 2d:3e:b5:65:bd:c6:54:a1:5e:fa:f6:ed:eb:aa:8b: + 9e:16:08:c5:c9:10:c9:3a:20:86:8f:c8:50:4d:37: + 0f:1b:26:fa:97:59:f6:79:83:bb:78:86:3e:da:9a: + cb:ea:51:24:f6 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + +C.1.3. MASA Private Key + + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgrbJ1oU+HIJ2SWYAk + DkBTL+YNPxQG+gwsMsZB94N8mZ2hRANCAASS9NVlWJdztwNY81yPlH2UODYWhlYA + ZfsqnEPSFZKnq8mq8gF78ZVbYi6q2FEg8kkORY/rpIU/X7SQsRuD+wMW + -----END PRIVATE KEY----- + + Private-Key: (256 bit) + priv: + ad:b2:75:a1:4f:87:20:9d:92:59:80:24:0e:40:53: + 2f:e6:0d:3f:14:06:fa:0c:2c:32:c6:41:f7:83:7c: + 99:9d + pub: + 04:92:f4:d5:65:58:97:73:b7:03:58:f3:5c:8f:94: + 7d:94:38:36:16:86:56:00:65:fb:2a:9c:43:d2:15: + 92:a7:ab:c9:aa:f2:01:7b:f1:95:5b:62:2e:aa:d8: + 51:20:f2:49:0e:45:8f:eb:a4:85:3f:5f:b4:90:b1: + 1b:83:fb:03:16 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + +C.2. Pledge, Registrar, Domain CA and MASA Certificates + + All keys and PKIX certificates used for the examples have been + generated with OpenSSL - see Appendix A.3 for more details on + certificate generation. Below the certificates are listed that + accompany the keys shown above. Each certificate description is + followed by the hexadecimal representation of the X.509 ASN.1 DER + encoded certificate. This representation can be for example decoded + using an online ASN.1 decoder. + +C.2.1. Pledge IDevID Certificate + + + + +Richardson, et al. Expires 10 December 2026 [Page 72] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 32429 (0x7ead) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = masa.stok.nl, O = vanderstok, L = Helmond, + C = NL + Validity + Not Before: Dec 9 12:50:47 2022 GMT + Not After : Dec 31 12:50:47 9999 GMT + Subject: CN = Stok IoT sensor Y-42, serialNumber = JADA123456789 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:48:7e:8e:52:26:05:46:17:c8:81:69:78:18:6f: + 23:1e:88:fc:6b:ef:2b:7f:ab:79:b3:59:99:ff:84: + 9e:3e:52:a8:9b:7f:46:43:7e:29:55:8a:f2:27:d6: + 87:99:ba:0b:2d:fc:fa:f5:bc:c8:09:01:4a:6e:4a: + 10:e6:86:a2:7b + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Key Encipherment, + Data Encipherment + X509v3 Basic Constraints: + CA:FALSE + X509v3 Authority Key Identifier: + CB:8D:98:CA:74:C5:1B:58:DD:E7:AC:EF:86:9A:94:43:A8:D6:66:A6 + 1.3.6.1.5.5.7.1.32: + hl=2 l= 12 prim: IA5STRING :masa.stok.nl + + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:4d:89:90:7e:03:fb:52:56:42:0c:3f:c1:b1:f1: + 47:b5:b3:93:65:45:2e:be:50:db:67:85:8f:23:89:a2:3f:9e: + 02:21:00:95:33:69:d1:c6:db:f0:f1:f6:52:24:59:d3:0a:95: + 4e:b2:f4:96:a1:31:3c:7b:d9:2f:28:b3:29:71:bb:60:df + + Below is the hexadecimal representation of the binary X.509 DER- + encoded certificate: + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 73] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 308201CE30820174A00302010202027EAD300A06082A8648CE3D040302304B31 + 15301306035504030C0C6D6173612E73746F6B2E6E6C31133011060355040A0C + 0A76616E64657273746F6B3110300E06035504070C0748656C6D6F6E64310B30 + 09060355040613024E4C3020170D3232313230393132353034375A180F393939 + 39313233313132353034375A3037311D301B06035504030C1453746F6B20496F + 542073656E736F7220592D3432311630140603550405130D4A41444131323334 + 35363738393059301306072A8648CE3D020106082A8648CE3D03010703420004 + 487E8E5226054617C8816978186F231E88FC6BEF2B7FAB79B35999FF849E3E52 + A89B7F46437E29558AF227D68799BA0B2DFCFAF5BCC809014A6E4A10E686A27B + A35A3058300E0603551D0F0101FF0404030204F030090603551D130402300030 + 1F0603551D23041830168014CB8D98CA74C51B58DDE7ACEF869A9443A8D666A6 + 301A06082B06010505070120040E160C6D6173612E73746F6B2E6E6C300A0608 + 2A8648CE3D040302034800304502204D89907E03FB5256420C3FC1B1F147B5B3 + 9365452EBE50DB67858F2389A23F9E022100953369D1C6DBF0F1F6522459D30A + 954EB2F496A1313C7BD92F28B32971BB60DF + +C.2.2. Registrar Certificate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 74] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c3:f6:21:49:b2:e3:0e:3e + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Custom-ER Global CA, OU = IT, O = "Custom-ER, Inc.", + L = San Jose, ST = CA, C = US + Validity + Not Before: Dec 9 12:50:47 2022 GMT + Not After : Dec 8 12:50:47 2025 GMT + Subject: CN = Custom-ER Registrar, OU = Office dept, O = "Custom-ER, + Inc.", L = Ottowa, ST = ON, C = CA + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:20:30:85:5b:e8:46:91:0b:3e:cb:15:ca:f8:57: + 2d:3e:b5:65:bd:c6:54:a1:5e:fa:f6:ed:eb:aa:8b: + 9e:16:08:c5:c9:10:c9:3a:20:86:8f:c8:50:4d:37: + 0f:1b:26:fa:97:59:f6:79:83:bb:78:86:3e:da:9a: + cb:ea:51:24:f6 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Key Encipherment, + Data Encipherment + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + C9:08:0B:38:7D:8D:D8:5B:3A:59:E7:EC:10:0B:86:63:93:A9:CA:4C + X509v3 Authority Key Identifier: + 92:EA:76:40:40:4A:8F:AB:4F:27:0B:F3:BC:37:9D:86:CD:72:80:F8 + X509v3 Extended Key Usage: critical + CMC Registration Authority, TLS Web Server Authentication, + TLS Web Client Authentication + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:21:00:d8:4a:7c:69:2f:f9:58:6e:82:22:87:18:f6: + 3b:c3:05:f0:ae:b8:ae:ec:42:78:82:38:79:81:2a:5d:15:61: + 64:02:20:08:f2:3c:13:69:13:b0:2c:e2:63:09:d5:99:4f:eb: + 75:70:af:af:ed:98:cd:f1:12:11:c0:37:f7:18:4d:c1:9d + + Below is the hexadecimal representation of the binary X.509 DER- + encoded certificate: + + + + + +Richardson, et al. Expires 10 December 2026 [Page 75] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 3082026D30820213A003020102020900C3F62149B2E30E3E300A06082A8648CE + 3D0403023072311C301A06035504030C13437573746F6D2D455220476C6F6261 + 6C204341310B3009060355040B0C02495431183016060355040A0C0F43757374 + 6F6D2D45522C20496E632E3111300F06035504070C0853616E204A6F7365310B + 300906035504080C024341310B3009060355040613025553301E170D32323132 + 30393132353034375A170D3235313230383132353034375A3079311C301A0603 + 5504030C13437573746F6D2D4552205265676973747261723114301206035504 + 0B0C0B4F6666696365206465707431183016060355040A0C0F437573746F6D2D + 45522C20496E632E310F300D06035504070C064F74746F7761310B3009060355 + 04080C024F4E310B30090603550406130243413059301306072A8648CE3D0201 + 06082A8648CE3D030107034200042030855BE846910B3ECB15CAF8572D3EB565 + BDC654A15EFAF6EDEBAA8B9E1608C5C910C93A20868FC8504D370F1B26FA9759 + F67983BB78863EDA9ACBEA5124F6A3818A308187300E0603551D0F0101FF0404 + 030204F030090603551D1304023000301D0603551D0E04160414C9080B387D8D + D85B3A59E7EC100B866393A9CA4C301F0603551D2304183016801492EA764040 + 4A8FAB4F270BF3BC379D86CD7280F8302A0603551D250101FF0420301E06082B + 0601050507031C06082B0601050507030106082B06010505070302300A06082A + 8648CE3D0403020348003045022100D84A7C692FF9586E82228718F63BC305F0 + AEB8AEEC4278823879812A5D156164022008F23C136913B02CE26309D5994FEB + 7570AFAFED98CDF11211C037F7184DC19D + +C.2.3. Domain CA Certificate + + The Domain CA certificate is the CA of the owner's domain. It has + signed the Registrar (RA) certificate. + + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 76] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3092288576548618702 (0x2aea0413a42dc1ce) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Custom-ER Global CA, OU = IT, O = "Custom-ER, Inc.", + L = San Jose, ST = CA, C = US + Validity + Not Before: Dec 9 12:50:47 2022 GMT + Not After : Dec 6 12:50:47 2032 GMT + Subject: CN = Custom-ER Global CA, OU = IT, O = "Custom-ER, Inc.", + L = San Jose, ST = CA, C = US + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:97:b1:ed:96:91:64:93:09:85:bb:b8:ac:9a:2a: + f9:45:5c:df:ee:a4:b1:1d:e2:e7:9d:06:8b:fa:80: + 39:26:b4:00:52:51:b3:4f:1c:08:15:a4:cb:e0:3f: + bd:1b:bc:b6:35:f6:43:1a:22:de:78:65:3b:87:b9: + 95:37:ec:e1:6c + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Alternative Name: + email:help@custom-er.example.com + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 92:EA:76:40:40:4A:8F:AB:4F:27:0B:F3:BC:37:9D:86:CD:72:80:F8 + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:44:02:20:66:15:df:c3:70:11:f6:73:78:d8:fd:1c:2a:3f: + bd:d1:3f:51:f6:b6:6f:2d:7c:e2:7a:13:18:21:bb:70:f0:c0: + 02:20:69:86:d8:d2:28:b2:92:6e:23:9e:19:0b:8f:18:25:c9: + c1:4c:67:95:ff:a0:b3:24:bd:4d:ac:2e:cb:68:d7:13 + + Below is the hexadecimal representation of the binary X.509 DER- + encoded certificate: + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 77] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 30820242308201E9A00302010202082AEA0413A42DC1CE300A06082A8648CE3D + 0403023072311C301A06035504030C13437573746F6D2D455220476C6F62616C + 204341310B3009060355040B0C02495431183016060355040A0C0F437573746F + 6D2D45522C20496E632E3111300F06035504070C0853616E204A6F7365310B30 + 0906035504080C024341310B3009060355040613025553301E170D3232313230 + 393132353034375A170D3332313230363132353034375A3072311C301A060355 + 04030C13437573746F6D2D455220476C6F62616C204341310B3009060355040B + 0C02495431183016060355040A0C0F437573746F6D2D45522C20496E632E3111 + 300F06035504070C0853616E204A6F7365310B300906035504080C024341310B + 30090603550406130255533059301306072A8648CE3D020106082A8648CE3D03 + 01070342000497B1ED969164930985BBB8AC9A2AF9455CDFEEA4B11DE2E79D06 + 8BFA803926B4005251B34F1C0815A4CBE03FBD1BBCB635F6431A22DE78653B87 + B99537ECE16CA369306730250603551D11041E301C811A68656C704063757374 + 6F6D2D65722E6578616D706C652E636F6D300E0603551D0F0101FF0404030201 + 86300F0603551D130101FF040530030101FF301D0603551D0E0416041492EA76 + 40404A8FAB4F270BF3BC379D86CD7280F8300A06082A8648CE3D040302034700 + 304402206615DFC37011F67378D8FD1C2A3FBDD13F51F6B66F2D7CE27A131821 + BB70F0C002206986D8D228B2926E239E190B8F1825C9C14C6795FFA0B324BD4D + AC2ECB68D713 + +C.2.4. MASA Certificate + + The MASA CA certificate is the CA that signed the Pledge's IDevID + certificate. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 78] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: + e3:9c:da:17:e1:38:6a:0a + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = masa.stok.nl, O = vanderstok, L = Helmond, + C = NL + Validity + Not Before: Dec 9 12:50:47 2022 GMT + Not After : Dec 6 12:50:47 2032 GMT + Subject: CN = masa.stok.nl, O = vanderstok, L = Helmond, + C = NL + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:92:f4:d5:65:58:97:73:b7:03:58:f3:5c:8f:94: + 7d:94:38:36:16:86:56:00:65:fb:2a:9c:43:d2:15: + 92:a7:ab:c9:aa:f2:01:7b:f1:95:5b:62:2e:aa:d8: + 51:20:f2:49:0e:45:8f:eb:a4:85:3f:5f:b4:90:b1: + 1b:83:fb:03:16 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Alternative Name: + email:info@masa.stok.nl + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Subject Key Identifier: + CB:8D:98:CA:74:C5:1B:58:DD:E7:AC:EF:86:9A:94:43:A8:D6:66:A6 + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:46:02:21:00:94:3f:a5:26:51:68:16:38:5b:78:9a:d8:c3: + af:8e:49:28:22:60:56:26:43:4a:14:98:3e:e1:e4:81:ad:ca: + 1b:02:21:00:ba:4d:aa:fd:fa:68:42:74:03:2b:a8:41:6b:e2: + 90:0c:9e:7b:b8:c0:9c:f7:0e:3f:b4:36:8a:b3:9c:3e:31:0e + + Below is the hexadecimal representation of the binary X.509 DER- + encoded certificate: + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 79] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 308201F130820196A003020102020900E39CDA17E1386A0A300A06082A8648CE + 3D040302304B3115301306035504030C0C6D6173612E73746F6B2E6E6C311330 + 11060355040A0C0A76616E64657273746F6B3110300E06035504070C0748656C + 6D6F6E64310B3009060355040613024E4C301E170D3232313230393132353034 + 375A170D3332313230363132353034375A304B3115301306035504030C0C6D61 + 73612E73746F6B2E6E6C31133011060355040A0C0A76616E64657273746F6B31 + 10300E06035504070C0748656C6D6F6E64310B3009060355040613024E4C3059 + 301306072A8648CE3D020106082A8648CE3D0301070342000492F4D565589773 + B70358F35C8F947D9438361686560065FB2A9C43D21592A7ABC9AAF2017BF195 + 5B622EAAD85120F2490E458FEBA4853F5FB490B11B83FB0316A3633061301C06 + 03551D11041530138111696E666F406D6173612E73746F6B2E6E6C300E060355 + 1D0F0101FF04040302018630120603551D130101FF040830060101FF02010330 + 1D0603551D0E04160414CB8D98CA74C51B58DDE7ACEF869A9443A8D666A6300A + 06082A8648CE3D0403020349003046022100943FA526516816385B789AD8C3AF + 8E492822605626434A14983EE1E481ADCA1B022100BA4DAAFDFA684274032BA8 + 416BE2900C9E7BB8C09CF70E3FB4368AB39C3E310E + +C.3. COSE-signed Pledge Voucher Request (PVR) + + In this example, the voucher request (PVR) has been signed by the + Pledge using the IDevID private key of Appendix C.1.1, and has been + sent to the link-local constrained Join Proxy (JP) over CoAPS to JP's + join port. The join port happens to use the default CoAPS UDP port + 5684. + + REQ: POST coaps://[JP-link-local-address]/b/rv + Content-Format: 836 (application/voucher+cose) + Payload: + + When the Join Proxy receives the DTLS handshake messages from the + Pledge, it will relay these messages to the Registrar. The payload + signed_voucher_request is shown as hexadecimal dump (with lf added) + below: + + D28443A10126A0587EA11909C5A40102074823BFBBC9C2BCF2130C585B305930 + 1306072A8648CE3D020106082A8648CE3D030107034200042030855BE846910B + 3ECB15CAF8572D3EB565BDC654A15EFAF6EDEBAA8B9E1608C5C910C93A20868F + C8504D370F1B26FA9759F67983BB78863EDA9ACBEA5124F60D6D4A4144413132 + 33343536373839584068987DE8B007F4E9416610BBE2D48E1D7EA1032092B8BF + CE611421950F45B22F17E214820C07E777ADF86175E25D3205568404C25FCEEC + 1B817C7861A6104B3D + + The representation of signed_pvr in CBOR diagnostic format (with lf + added) is: + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 80] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 18([h'A10126', {}, h'A11909C5A40102074823BFBBC9C2BCF2130C585B3059301 + 306072A8648CE3D020106082A8648CE3D030107034200042030855BE846910B3ECB1 + 5CAF8572D3EB565BDC654A15EFAF6EDEBAA8B9E1608C5C910C93A20868FC8504D370 + F1B26FA9759F67983BB78863EDA9ACBEA5124F60D6D4A41444131323334353637383 + 9', h'68987DE8B007F4E9416610BBE2D48E1D7EA1032092B8BFCE611421950F45B2 + 2F17E214820C07E777ADF86175E25D3205568404C25FCEEC1B817C7861A6104B3D'] + ) + + The COSE payload is the PVR voucher data, encoded as a CBOR byte + string. The diagnostic representation of it is shown below: + + {2501: {1: 2, 7: h'23BFBBC9C2BCF213', 12: h'3059301306072A8648CE3D02 + 0106082A8648CE3D030107034200042030855BE846910B3ECB15CAF8572D3EB565BD + C654A15EFAF6EDEBAA8B9E1608C5C910C93A20868FC8504D370F1B26FA9759F67983 + BB78863EDA9ACBEA5124F6', 13: "JADA123456789"}} + + The Pledge uses the 'proximity' (key '1', SID 2502, enum value 2) + assertion together with an included 'proximity-registrar-pubk' + attribute (key '12', SID 2513) to inform MASA about its proximity to + the specific Registrar. + +C.4. COSE-signed Registrar Voucher Request (RVR) + + In this example the Registrar's voucher request has been signed by + the JRC (Registrar) using the private key from Appendix C.1.2. + Contained within this voucher request is the voucher request PVR that + was made by the Pledge to JRC. Note that the RVR uses the HTTPS + protocol (not CoAP) and corresponding long URI path names as defined + in [RFC8995]. The Content-Type and Accept headers indicate the + constrained voucher format that is defined in the present document. + Because the Pledge used this format in the PVR, the JRC must also use + this format in the RVR. + + REQ: POST https://masa.stok.nl/.well-known/brski/requestvoucher + Content-Type: application/voucher+cose + Accept: application/voucher+cose + Body: + + The payload signed_rvr is shown as hexadecimal dump (with lf added): + + D28443A10126A11820825902843082028030820225A003020102020900C3F621 + 49B2E30E3E300A06082A8648CE3D0403023072311C301A06035504030C134375 + 73746F6D2D455220476C6F62616C204341310B3009060355040B0C0249543118 + 3016060355040A0C0F437573746F6D2D45522C20496E632E3111300F06035504 + 070C0853616E204A6F7365310B300906035504080C024341310B300906035504 + 0613025553301E170D3232313230363131333735395A170D3235313230353131 + 333735395A30818D3131302F06035504030C28437573746F6D2D455220436F6D + 6D65726369616C204275696C64696E6773205265676973747261723113301106 + + + +Richardson, et al. Expires 10 December 2026 [Page 81] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 0355040B0C0A4F6666696365206F707331183016060355040A0C0F437573746F + 6D2D45522C20496E632E310F300D06035504070C064F74746F7761310B300906 + 035504080C024F4E310B30090603550406130243413059301306072A8648CE3D + 020106082A8648CE3D030107034200042030855BE846910B3ECB15CAF8572D3E + B565BDC654A15EFAF6EDEBAA8B9E1608C5C910C93A20868FC8504D370F1B26FA + 9759F67983BB78863EDA9ACBEA5124F6A3818730818430090603551D13040230 + 00300B0603551D0F0404030204F0301D0603551D0E04160414C9080B387D8DD8 + 5B3A59E7EC100B866393A9CA4C301F0603551D2304183016801492EA7640404A + 8FAB4F270BF3BC379D86CD7280F8302A0603551D250101FF0420301E06082B06 + 01050507031C06082B0601050507030106082B06010505070302300A06082A86 + 48CE3D040302034900304602210091A2033692EB81503D53505FFC8DA326B1EE + 7DEA96F29174F0B3341A07812201022100FF7339288108B712F418530A18025A + 895408CC45E0BB678B46FBAB37DDB4D36B59024730820243308201E9A0030201 + 0202082AEA0413A42DC1CE300A06082A8648CE3D0403023072311C301A060355 + 04030C13437573746F6D2D455220476C6F62616C204341310B3009060355040B + 0C02495431183016060355040A0C0F437573746F6D2D45522C20496E632E3111 + 300F06035504070C0853616E204A6F7365310B300906035504080C024341310B + 3009060355040613025553301E170D3232313230363131333735395A170D3332 + 313230333131333735395A3072311C301A06035504030C13437573746F6D2D45 + 5220476C6F62616C204341310B3009060355040B0C0249543118301606035504 + 0A0C0F437573746F6D2D45522C20496E632E3111300F06035504070C0853616E + 204A6F7365310B300906035504080C024341310B300906035504061302555330 + 59301306072A8648CE3D020106082A8648CE3D0301070342000497B1ED969164 + 930985BBB8AC9A2AF9455CDFEEA4B11DE2E79D068BFA803926B4005251B34F1C + 0815A4CBE03FBD1BBCB635F6431A22DE78653B87B99537ECE16CA3693067300F + 0603551D130101FF040530030101FF30250603551D11041E301C811A68656C70 + 40637573746F6D2D65722E6578616D706C652E636F6D300E0603551D0F0101FF + 040403020186301D0603551D0E0416041492EA7640404A8FAB4F270BF3BC379D + 86CD7280F8300A06082A8648CE3D0403020348003045022100D6D813B390BD3A + 7B4E85424BCB1ED933AD1E981F2817B59083DD6EC1C5E3FADF02202CEE440619 + 2BC767E98D7CFAE044C6807481AD8564A7D569DCA3D1CDF1E5E843590124A119 + 09C5A60102027818323032322D31322D30365432303A30343A31352E3735345A + 05581A041830168014CB8D98CA74C51B58DDE7ACEF869A9443A8D666A6074823 + BFBBC9C2BCF2130958C9D28443A10126A0587EA11909C5A40102074823BFBBC9 + C2BCF2130C585B3059301306072A8648CE3D020106082A8648CE3D0301070342 + 00042030855BE846910B3ECB15CAF8572D3EB565BDC654A15EFAF6EDEBAA8B9E + 1608C5C910C93A20868FC8504D370F1B26FA9759F67983BB78863EDA9ACBEA51 + 24F60D6D4A414441313233343536373839584068987DE8B007F4E9416610BBE2 + D48E1D7EA1032092B8BFCE611421950F45B22F17E214820C07E777ADF86175E2 + 5D3205568404C25FCEEC1B817C7861A6104B3D0D6D4A41444131323334353637 + 38395840B1DD40B10787437588AEAC9036899191C16CCDBECA31C197855CCB6B + BA142D709FE329CBC3F76297D6063ACB6759EAB98E96EA4C4AA2135AA48A247B + AC1D6A3F + + The representation of signed_rvr in CBOR diagnostic format (with lf + added) is: + + + + + +Richardson, et al. Expires 10 December 2026 [Page 82] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 18([h'A10126', {32: [h'3082028030820225A003020102020900C3F62149B2E30 + E3E300A06082A8648CE3D0403023072311C301A06035504030C13437573746F6D2D4 + 55220476C6F62616C204341310B3009060355040B0C02495431183016060355040A0 + C0F437573746F6D2D45522C20496E632E3111300F06035504070C0853616E204A6F7 + 365310B300906035504080C024341310B3009060355040613025553301E170D32323 + 13230363131333735395A170D3235313230353131333735395A30818D3131302F060 + 35504030C28437573746F6D2D455220436F6D6D65726369616C204275696C64696E6 + 7732052656769737472617231133011060355040B0C0A4F6666696365206F7073311 + 83016060355040A0C0F437573746F6D2D45522C20496E632E310F300D06035504070 + C064F74746F7761310B300906035504080C024F4E310B30090603550406130243413 + 059301306072A8648CE3D020106082A8648CE3D030107034200042030855BE846910 + B3ECB15CAF8572D3EB565BDC654A15EFAF6EDEBAA8B9E1608C5C910C93A20868FC85 + 04D370F1B26FA9759F67983BB78863EDA9ACBEA5124F6A3818730818430090603551 + D1304023000300B0603551D0F0404030204F0301D0603551D0E04160414C9080B387 + D8DD85B3A59E7EC100B866393A9CA4C301F0603551D2304183016801492EA7640404 + A8FAB4F270BF3BC379D86CD7280F8302A0603551D250101FF0420301E06082B06010 + 50507031C06082B0601050507030106082B06010505070302300A06082A8648CE3D0 + 40302034900304602210091A2033692EB81503D53505FFC8DA326B1EE7DEA96F2917 + 4F0B3341A07812201022100FF7339288108B712F418530A18025A895408CC45E0BB6 + 78B46FBAB37DDB4D36B', h'30820243308201E9A00302010202082AEA0413A42DC1 + CE300A06082A8648CE3D0403023072311C301A06035504030C13437573746F6D2D45 + 5220476C6F62616C204341310B3009060355040B0C02495431183016060355040A0C + 0F437573746F6D2D45522C20496E632E3111300F06035504070C0853616E204A6F73 + 65310B300906035504080C024341310B3009060355040613025553301E170D323231 + 3230363131333735395A170D3332313230333131333735395A3072311C301A060355 + 04030C13437573746F6D2D455220476C6F62616C204341310B3009060355040B0C02 + 495431183016060355040A0C0F437573746F6D2D45522C20496E632E3111300F0603 + 5504070C0853616E204A6F7365310B300906035504080C024341310B300906035504 + 06130255533059301306072A8648CE3D020106082A8648CE3D0301070342000497B1 + ED969164930985BBB8AC9A2AF9455CDFEEA4B11DE2E79D068BFA803926B4005251B3 + 4F1C0815A4CBE03FBD1BBCB635F6431A22DE78653B87B99537ECE16CA3693067300F + 0603551D130101FF040530030101FF30250603551D11041E301C811A68656C704063 + 7573746F6D2D65722E6578616D706C652E636F6D300E0603551D0F0101FF04040302 + 0186301D0603551D0E0416041492EA7640404A8FAB4F270BF3BC379D86CD7280F830 + 0A06082A8648CE3D0403020348003045022100D6D813B390BD3A7B4E85424BCB1ED9 + 33AD1E981F2817B59083DD6EC1C5E3FADF02202CEE4406192BC767E98D7CFAE044C6 + 807481AD8564A7D569DCA3D1CDF1E5E843']}, h'A11909C5A601020278183230323 + 22D31322D30365432303A30343A31352E3735345A05581A041830168014CB8D98CA7 + 4C51B58DDE7ACEF869A9443A8D666A6074823BFBBC9C2BCF2130958C9D28443A1012 + 6A0587EA11909C5A40102074823BFBBC9C2BCF2130C585B3059301306072A8648CE3 + D020106082A8648CE3D030107034200042030855BE846910B3ECB15CAF8572D3EB56 + 5BDC654A15EFAF6EDEBAA8B9E1608C5C910C93A20868FC8504D370F1B26FA9759F67 + 983BB78863EDA9ACBEA5124F60D6D4A414441313233343536373839584068987DE8B + 007F4E9416610BBE2D48E1D7EA1032092B8BFCE611421950F45B22F17E214820C07E + 777ADF86175E25D3205568404C25FCEEC1B817C7861A6104B3D0D6D4A41444131323 + 3343536373839', h'B1DD40B10787437588AEAC9036899191C16CCDBECA31C19785 + 5CCB6BBA142D709FE329CBC3F76297D6063ACB6759EAB98E96EA4C4AA2135AA48A24 + 7BAC1D6A3F']) + + + +Richardson, et al. Expires 10 December 2026 [Page 83] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +C.5. COSE-signed Voucher from MASA + + The resulting voucher is created by the MASA and returned to the + Registrar: + + RES: 200 OK + Content-Type: application/voucher+cose + Body: + + The Registrar then returns the voucher to the Pledge: + + RES: 2.04 Changed + Content-Format: 836 (application/voucher+cose) + Payload: + + It is signed by the MASA's private key (see Appendix C.1.3) and can + be verified by the Pledge using the MASA's public key that it stores. + + Below is the binary signed_voucher, encoded in hexadecimal (with lf + added): + + D28443A10126A0590288A1190993A60102027818323032322D31322D30365432 + 303A32333A33302E3730385A03F4074857EED786AD4049070859024730820243 + 308201E9A00302010202082AEA0413A42DC1CE300A06082A8648CE3D04030230 + 72311C301A06035504030C13437573746F6D2D455220476C6F62616C20434131 + 0B3009060355040B0C02495431183016060355040A0C0F437573746F6D2D4552 + 2C20496E632E3111300F06035504070C0853616E204A6F7365310B3009060355 + 04080C024341310B3009060355040613025553301E170D323231323036313133 + 3735395A170D3332313230333131333735395A3072311C301A06035504030C13 + 437573746F6D2D455220476C6F62616C204341310B3009060355040B0C024954 + 31183016060355040A0C0F437573746F6D2D45522C20496E632E3111300F0603 + 5504070C0853616E204A6F7365310B300906035504080C024341310B30090603 + 550406130255533059301306072A8648CE3D020106082A8648CE3D0301070342 + 000497B1ED969164930985BBB8AC9A2AF9455CDFEEA4B11DE2E79D068BFA8039 + 26B4005251B34F1C0815A4CBE03FBD1BBCB635F6431A22DE78653B87B99537EC + E16CA3693067300F0603551D130101FF040530030101FF30250603551D11041E + 301C811A68656C7040637573746F6D2D65722E6578616D706C652E636F6D300E + 0603551D0F0101FF040403020186301D0603551D0E0416041492EA7640404A8F + AB4F270BF3BC379D86CD7280F8300A06082A8648CE3D04030203480030450221 + 00D6D813B390BD3A7B4E85424BCB1ED933AD1E981F2817B59083DD6EC1C5E3FA + DF02202CEE4406192BC767E98D7CFAE044C6807481AD8564A7D569DCA3D1CDF1 + E5E8430B6D4A4144413132333435363738395840DF31B21A6AD3F5AC7F4C8B02 + 6F551BD28FBCE62330D3E262AC170F6BFEDDBA5F2E8FBAA2CAACFED9E8614EAC + 5BF2450DADC53AC29DFA30E8787A1400B2E7C832 + + The representation of signed_voucher in CBOR diagnostic format (with + lf added) is: + + + + +Richardson, et al. Expires 10 December 2026 [Page 84] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + 18([h'A10126', {}, h'A1190993A60102027818323032322D31322D30365432303 + A32333A33302E3730385A03F4074857EED786AD4049070859024730820243308201E + 9A00302010202082AEA0413A42DC1CE300A06082A8648CE3D0403023072311C301A0 + 6035504030C13437573746F6D2D455220476C6F62616C204341310B3009060355040 + B0C02495431183016060355040A0C0F437573746F6D2D45522C20496E632E3111300 + F06035504070C0853616E204A6F7365310B300906035504080C024341310B3009060 + 355040613025553301E170D3232313230363131333735395A170D333231323033313 + 1333735395A3072311C301A06035504030C13437573746F6D2D455220476C6F62616 + C204341310B3009060355040B0C02495431183016060355040A0C0F437573746F6D2 + D45522C20496E632E3111300F06035504070C0853616E204A6F7365310B300906035 + 504080C024341310B30090603550406130255533059301306072A8648CE3D0201060 + 82A8648CE3D0301070342000497B1ED969164930985BBB8AC9A2AF9455CDFEEA4B11 + DE2E79D068BFA803926B4005251B34F1C0815A4CBE03FBD1BBCB635F6431A22DE786 + 53B87B99537ECE16CA3693067300F0603551D130101FF040530030101FF302506035 + 51D11041E301C811A68656C7040637573746F6D2D65722E6578616D706C652E636F6 + D300E0603551D0F0101FF040403020186301D0603551D0E0416041492EA7640404A8 + FAB4F270BF3BC379D86CD7280F8300A06082A8648CE3D0403020348003045022100D + 6D813B390BD3A7B4E85424BCB1ED933AD1E981F2817B59083DD6EC1C5E3FADF02202 + CEE4406192BC767E98D7CFAE044C6807481AD8564A7D569DCA3D1CDF1E5E8430B6D4 + A414441313233343536373839', h'DF31B21A6AD3F5AC7F4C8B026F551BD28FBCE6 + 2330D3E262AC170F6BFEDDBA5F2E8FBAA2CAACFED9E8614EAC5BF2450DADC53AC29D + FA30E8787A1400B2E7C832']) + + In the above, the third element in the array is the voucher data + encoded as a CBOR byte string. When decoded, it can be represented + by the following CBOR diagnostic notation: + + {2451: {1: 2, 2: "2022-12-06T20:23:30.708Z", 3: false, 7: h'57EED786 + AD404907', 8: h'30820243308201E9A00302010202082AEA0413A42DC1CE300A06 + 082A8648CE3D0403023072311C301A06035504030C13437573746F6D2D455220476C + 6F62616C204341310B3009060355040B0C02495431183016060355040A0C0F437573 + 746F6D2D45522C20496E632E3111300F06035504070C0853616E204A6F7365310B30 + 0906035504080C024341310B3009060355040613025553301E170D32323132303631 + 31333735395A170D3332313230333131333735395A3072311C301A06035504030C13 + 437573746F6D2D455220476C6F62616C204341310B3009060355040B0C0249543118 + 3016060355040A0C0F437573746F6D2D45522C20496E632E3111300F06035504070C + 0853616E204A6F7365310B300906035504080C024341310B30090603550406130255 + 533059301306072A8648CE3D020106082A8648CE3D0301070342000497B1ED969164 + 930985BBB8AC9A2AF9455CDFEEA4B11DE2E79D068BFA803926B4005251B34F1C0815 + A4CBE03FBD1BBCB635F6431A22DE78653B87B99537ECE16CA3693067300F0603551D + 130101FF040530030101FF30250603551D11041E301C811A68656C7040637573746F + 6D2D65722E6578616D706C652E636F6D300E0603551D0F0101FF040403020186301D + 0603551D0E0416041492EA7640404A8FAB4F270BF3BC379D86CD7280F8300A06082A + 8648CE3D0403020348003045022100D6D813B390BD3A7B4E85424BCB1ED933AD1E98 + 1F2817B59083DD6EC1C5E3FADF02202CEE4406192BC767E98D7CFAE044C6807481AD + 8564A7D569DCA3D1CDF1E5E843', 11: "JADA123456789"}} + + + + + +Richardson, et al. Expires 10 December 2026 [Page 85] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The largest element in the voucher is identified by key 8, which + decodes to SID 2459 (pinned-domain-cert) based on the delta encoding + defined by [RFC9254]. It contains the complete PKIX (DER-encoded + X.509v3) certificate of the Registrar's domain CA. This certificate + is shown in Appendix C.2.3. + +Appendix D. Pledge Device Class Profiles + + cBRSKI allows implementers to select between various functional + options for the Pledge, yielding different code size footprints and + different requirements on Pledge hardware. Thus for each product + type an optimal trade-off between functionality, development/ + maintenance cost and hardware cost can be made. + + This appendix illustrates different selection outcomes by means of + defining different example "profiles" of constrained Pledges. In the + following subsections, these profiles are defined and a comparison is + provided. + +D.1. Minimal Pledge + + The Minimal Pledge profile (Min) aims to reduce code size and + hardware cost to a minimum. This comes with some severe functional + restrictions, in particular: + + * No support for EST re-enrollment: whenever this would be needed, a + factory reset followed by a new onboarding process is required. + + * No support for change of Registrar: for this case, a factory reset + followed by a new onboarding process is required. + + This profile would be appropriate for single-use devices which must + be replaced rather than re-deployed. That might include medical + devices, but also sensors used during construction, such as concrete + temperature sensors. + +D.2. Typical Pledge + + The Typical Pledge profile (Typ) aims to support a typical cBRSKI + feature set including EST re-enrollment support and Registrar + changes. + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 86] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +D.3. Full-featured Pledge + + The Full-featured Pledge profile (Full) illustrates a Pledge category + that supports multiple onboarding methods, hardware real-time clock, + BRSKI/EST resource discovery, and CSR Attributes request/response. + It also supports most of the optional features defined in this + specification. + +D.4. Comparison Chart of Pledge Classes + + The below table specifies the functions implemented in the three + example Pledge classes Min (Appendix D.1), Typ (Appendix D.2) and + Full (Appendix D.3). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 87] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + +============================================+=======+=====+======+ + | Functions Implemented | Min | Typ | Full | + +============================================+=======+=====+======+ + | *General* | | | | + +--------------------------------------------+-------+-----+------+ + | Support cBRSKI onboarding | Y | Y | Y | + +--------------------------------------------+-------+-----+------+ + | Support other onboarding method(s) | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | Real-time clock and cert time checks | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | *cBRSKI* | | | | + +--------------------------------------------+-------+-----+------+ + | CoAP discovery for rt=brski* | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | Support pinned Registrar public key (RPK) | Y | - | Y | + +--------------------------------------------+-------+-----+------+ + | Support pinned Registrar certificate | - | Y | Y | + +--------------------------------------------+-------+-----+------+ + | Support pinned Domain CA | - | Y | Y | + +--------------------------------------------+-------+-----+------+ + | *EST-coaps* | | | | + +--------------------------------------------+-------+-----+------+ + | Explicit TA database size (#certs) | 0 | 3 | 8 | + +--------------------------------------------+-------+-----+------+ + | CoAP discovery for rt=ace.est* | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | GET /att and response parsing | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | GET /crts format 62 (multiple CA certs) | - | Y | Y | + +--------------------------------------------+-------+-----+------+ + | GET /crts format 281 (multiple CA certs) | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | ETag handling support for GET /crts | - | Y | Y | + +--------------------------------------------+-------+-----+------+ + | Re-enrollment supported | - (*) | Y | Y | + +--------------------------------------------+-------+-----+------+ + | Section 6.7.1 optimized procedure | Y | Y | - | + +--------------------------------------------+-------+-----+------+ + | Pro-active re-enrollment at own initiative | - | - | Y | + +--------------------------------------------+-------+-----+------+ + | Periodic trust anchor retrieval GET /crts | - (*) | Y | Y | + +--------------------------------------------+-------+-----+------+ + | Supports change of Registrar identity | - (*) | Y | Y | + +--------------------------------------------+-------+-----+------+ + + Table 5: Comparison Chart of Pledge Classes Min, Typ and Full + + + + +Richardson, et al. Expires 10 December 2026 [Page 88] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Notes: (*) means only possible via a factory-reset followed by a new + cBRSKI onboarding procedure. + +Appendix E. Pledge Discovery of Onboarding and Enrollment Options + + The discovery functionality described in this section is informative + only: it derives from the normative CoRE documents [RFC6690], + [RFC7252] and from [RFC9148]. In typical cases, for a constrained + Pledge that only supports a single onboarding and enrollment method, + this functionality is not needed. + + Note that the full-featured Pledge class defined in Appendix D.3 does + support CoAP discovery functionality. + +E.1. Pledge Discovery Query for All cBRSKI Resources + + A Pledge that wishes to discover the available cBRSKI onboarding + options/formats can do a discovery operation using CoAP discovery per + Section 7 of [RFC7252] and Section 4 of [RFC6690]. It first sends a + CoAP discovery query to the Registrar over the secured DTLS + connection. The Registrar then responds with a CoRE Link Format + payload containing the requested resources, if any. + + For example, if the Registrar supports a cBRSKI base resource /b in + addition to the longer /.well-known/brski base resource, and supports + only the voucher format application/voucher+cose (836), and status + reporting in both CBOR (60) and JSON (50) formats, a CoAP resource + discovery request and response may look as follows: + + REQ: GET /.well-known/core?rt=brski* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + ;rt=brski, + ;rt=brski.rv;ct=836, + ;rt=brski.vs;ct="50 60", + ;rt=brski.es;ct="50 60" + + In this case, the Registrar returns only the shorter URI paths + matching the query filter, which are located under the /b base + resource. The /.well-known/brski based URI paths are not returned, + as these are assumed to be well-known (i.e. mandatory to support for + a Registrar that offers this functionality under /b.) + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 89] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + The Registrar is however under no obligation to provide the shorter + URLs under /b, and may respond to this query with only the /.well- + known/brski/\ resources for the short names as defined + in Table 1, if these resources are not hosted anywhere else. This + case is shown in the below interaction: + + REQ: GET /.well-known/core?rt=brski* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + ;rt=brski, + ;rt=brski.rv;ct=836, + ;rt=brski.vs;ct="50 60", + ;rt=brski.es;ct="50 60" + + When responding to a discovery request for cBRSKI resources, the + Registrar may return the full resource paths for all + resources and the content-formats supported by these resources (using + ct attributes) as shown in the above examples. This is useful when + multiple content-formats are supported for a particular resource on + the Registrar and the discovering Pledge also supports multiple. + + Registrars that have implemented any cBRSKI or EST-coaps URI paths + outside of /.well-known must process a request on the corresponding + /.well-known/brski/\ or /.well-known/est/\ + URI paths identically. In particular, a Pledge may use the longer + (well-known) and shorter URI paths in any combination. + + A Registrar may also be implemented without support for the + (optional) CoAP discovery. In that case, it may for example return a + 4.04 Not Found as shown in the example below, in case the Registrar + does not host the resource /.well-known/core at all. In such case, + the Pledge cannot discover any onboarding/enrollment options and so + it has to rely on the default cBRSKI resources under /.well-known/ + brski/... and /.well-known/est/.... + + REQ: GET /.well-known/core?rt=brski* + + RES: 4.04 Not Found + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 90] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + +E.2. Pledge Discovery Query for the cBRSKI Base Resource + + In case the client queries for only rt=brski type resources, the + Registrar responds with only the base path for the cBRSKI resources + (rt=brski, resource /b in earlier examples) and no others. (So, the + query is "rt=brski", without the wildcard character.) This is shown + in the below example. The Pledge in this case requests only the + cBRSKI base resource of type rt=brski to check if cBRSKI is supported + by the Registrar and if a shorter-length cBRSKI base resource path is + supported or not. In this case, the Pledge is not interested to + check what voucher request formats, or status telemetry formats -- + other than the mandatory default formats -- are supported. The + compact response below then shows that the Registrar indeed supports + a cBRSKI resource at /b: + + REQ: GET /.well-known/core?rt=brski + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + ;rt=brski + + The Pledge can now start using any of the cBRSKI resources + /b/\ in a next CoAP request to the Registrar. In above + example, again the well-known resource present under /.well-known/ + brski is not returned because this is assumed to be well-known to the + Pledge and mandatory to support for a Registrar that offers this + functionality under /b. + + As a follow-up example, the Pledge can now start the onboarding by + sending its PVR: + + REQ: POST /b/rv + Content-Format: 836 (application/voucher+cose) + Accept: 836 (application/voucher+cose) + Payload: + +E.3. Usage of ct Attribute + + The return of multiple content-formats in the 'ct' link format + attribute by the Registrar allows the Pledge to choose the most + appropriate one for a particular operation, and allows extension with + new voucher formats. Note that only content-format 836 (application/ + voucher+cose) is defined in this document for the voucher request + resource (/rv), both as request payload and as response payload. If + the 'ct' attribute is not indicated for the /rv resource in the CoRE + Link Format description, this implies that at least format 836 is + supported and maybe more. + + + +Richardson, et al. Expires 10 December 2026 [Page 91] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Note that this specification allows for application/voucher+cose + payloads to be transmitted over HTTPS, as well as for application/ + voucher-cms+json and other formats yet to be defined over CoAP. The + burden for this flexibility is placed upon the Registrar. A Pledge + on constrained hardware is expected to support a single format only. + + The Pledge needs to support one or more formats for the PVR and + resulting voucher. The MASA needs to support all formats that the + associated Pledges use. + + In the below example, a Pledge queries specifically for the brski.rv + resource type to learn what voucher formats are supported: + + REQ: GET /.well-known/core?rt=brski.rv + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + ;rt=brski.rv;ct="836 65123 65124" + + The Registrar returns 3 supported voucher formats: 836, 65123, and + 65124. The first is the mandatory application/voucher+cose. The + other two are numbers from the Experimental Use number range of the + CoAP Content-Formats sub-registry, which are used as mere examples. + The Pledge can now make a selection between the supported formats. + + Note that if the Registrar only supports the default content-formats + for each cBRSKI resource as specified by this document, it may omit + the ct attributes in the discovery query response. For example as in + the following interaction: + + REQ: GET /.well-known/core?rt=brski* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + ;rt=brski, + ;rt=brski.rv, + ;rt=brski.vs, + ;rt=brski.es + +E.4. EST-coaps Resource Discovery + + The Pledge can also use CoAP discovery to identify enrollment + options, for example enrollment using EST-coaps or other methods. + The below example shows a Pledge that wants to identify EST-coaps + enrollment options by sending a discovery query. This is done either + before or after the voucher has been validated. + + + +Richardson, et al. Expires 10 December 2026 [Page 92] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + Content-Format: 40 (application/link-format) + Payload: + ;rt=ace.est.crts;ct="62 281 287", + ;rt=ace.est.sen;ct="281 287", + ;rt=ace.est.sren;ct="281 287", + ;rt=ace.est.att, + ;rt=ace.est.skg, + ;rt=ace.est.skc + + The response from the Registrar indicates that EST-coaps enrollment + (/sen) and re-enrollment (/sren) is supported, with a choice of two + content-formats for the response payload: either a PKCS#7 container + with a single LDevID certificate (application/pkcs7-mime;smime- + type=certs-only, content-format 281) which is the BRSKI [RFC8995] + encoding, or just a single LDevID certificate (application/pkix-cert, + content-format 287) which is the default cBRSKI encoding. + + For the EST cacerts resource (/crts) there are three content-formats + supported: an application/multipart-core container (62) per + Section 6.7.5, a PKCS#7 container with all CA certificates (287), or + a single (most relevant) CA certificate (281). + + The Pledge can now send a CoAP request to one of the discovered + resources, with the Accept Option to indicate which return payload + content-format the Pledge wants to receive. + +Acknowledgements + + We are very grateful to Jim Schaad for explaining COSE/CMS choices + and for correcting early versions of the COSE_Sign1 objects. + + Michel Veillette did extensive work on _pyang_ to extend it to + support the SID allocation process, and this document was among its + first users. + + Russ Housley , Daniel Franke , Henk Birkholtz , Kathleen Moriarty , + Xufeng Liu and Karl Moberg provided review feedback. + + The BRSKI design team has met on many Tuesdays and Thursdays for + document review. The team includes the authors and: Aurelio + Schellenbaum , David von Oheimb , Steffen Fries , Thomas Werner , + Bill Atwood and Toerless Eckert . + + Darrel Miller , Orie Steele and Manu Sporny provided review feedback + on the registration of the +cose structured syntax suffix. + + + +Richardson, et al. Expires 10 December 2026 [Page 93] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + Carsten Bormann suggested the use of CBOR Web Token (CWT) claims in + the voucher's COSE header. + +Changelog + + -31: Move BRSKI/cBRSKI generic functions and RFC 8995 updates out of + the cBRSKI-specific DTLS section (#352). Better formulation on how + RFC 8995 and RFC 9148 are updated and where. Replace 'rt=brski.jp' + discovery query by 'brski-jp=*' per #88 of draft-ietf-anima- + constrained-join-proxy. Added cipher suite details for DTLS 1.2 and + 1.3. Bugfix to Pledge IDevID cert creation script (avoid 'faketime' + process which had a conditional bug). Updated masa-considerations + reference to the adopted WG draft. + + -30: Require Pledge's DTLS cert chain to be included in RVR 'x5bag' + (#343). Add support for CoAP Uri-Path-Abbrev Option (#336). Move + 'idevid-issuer' clarification text to draft-8366bis. Update the + duplicate serial number attack to focus only on the case where the + attack could be successful (equal CAs). Update section references + draft-ietf-anima-8366bis to latest version. Remove reference to the + to-be-deprecated RFC 8366. Align terms and notation with draft-ietf- + anima-8366bis. Editorial (wording) updates. + + -29: Clarify that each brski.jp link indicates a root resource (/) + (#335). Clarify that Pledge uses IP link-local address of JP's + discovery response, instead of the UTF-8 encoded IP address literal + (#334). Add example of Join Proxy offering multiple Registrars + (endpoints) (#333). Updated CoAP request/response formatting of + examples. Updated acknowledgements (#331). Editorial updates. + + -28: Cleanup of normative/informative references, setting each to + right category. Bugfix and clarification in text around EdDSA Curve + selection. Added section on additional information in COSE header + with 'iat' CWT timestamp example. Updates to BRSKI Well-Known URIs + registry, including a rename of the "URI" column (#326). Unify COSE + header parameters terminology (#330). Text formatting and editorial + updates. + + -27: Clarify x5bag for storing signing chain and Registrar removes + unprotected x5bag/x5chain (#324, #323, #230). Clarify RPK use with + "placeholder" certificate. Merged the very similar BRSKI-MASA + security considerations sections (#312). Require CBOR format for + Pledge's/EST-client's telemetry (#309, #317). Removed figure + captions from code examples for consistency (#315). Add base + resource type (rt) for "ace.est" and related terminology (#314). + Update IEEE 802.1AR reference to 2018 version (#313). Editorial + updates. + + + + +Richardson, et al. Expires 10 December 2026 [Page 94] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + -26: Updated I-D/RFC references to newer versions. Corrected "sub- + registry" term to official "registry", in IANA section. Explicitly + imported terminology from [RFC7252]. Corrected "router" term in + Thread/MLE section, with clarifications, and [Thread] reference fix. + Moved references between "Informative" and "Normative" based on + what's required to implement all the optional features. Removal of + some lingering legacy text. Editorial improvements, bugfixes and + typo corrections. + + -25: Moved all software/library support info into Appendix A and + added "open source" section; Removed use of formal Extends/Amends + Update-tags (#303, #304); Moved Section 14 to Appendix E (#302); + Editorial improvements. + + -24: Rephrased well-known URL requirement in 14.1 (#292, #293); Added + paragraph on future certificate formats like C509 (#281, #294); Add + formal specification for CoAP discovery of Join Proxy by Pledge, + instead of only showing examples (#296, #300); Enable mDNS discovery + of Join Proxy by Pledge (also in mesh networks) and list service name + to use (#297, #299); Add requirement to support content-format 287 in + /sen and /sren response (#295, #298). + + -23: Removed Update tag for RFC 8366 (#285, #288); Introduced cBRSKI + acronym (#284, #286); Added Update tag for RFC 9148 (#283, #289); + Keep CoAP discovery as only mechanism and refer to future discovery + work (#279, #282, #290); Introduce formal CBOR diagnostics ellipsis + elision syntax (#281, #287); Support for multi-tier CAs by + introducing multipart-core /crts format (#275, #291); Terminology + updated for consistency with RFC 8366-bis (#274, #280); Rename + voucher media type to application/voucher+cose and register +cose SSS + (#264, #277); Editorial changes including section restructuring. + + -22: Streamlined text to focus mostly on the default flow, with + optional functions moved to their own sections (#269, #273); For DTLS + 1.3 client, use the record_size_limit extensions RFC 8449 (#270); + Editorial updates; Reference rfc6125bis updated to RFC 9525. + + -11 to -21: (For change details see GitHub issues https://github.com/ + anima-wg/constrained-voucher/issues , related Pull Requests and + commits.) + + -10: Design considerations extended; Examples made consistent. + + -08: Examples for cose_sign1 are completed and improved. + + -06: New SID values assigned; regenerated examples. + + + + + +Richardson, et al. Expires 10 December 2026 [Page 95] + +Internet-Draft Constrained BRSKI (cBRSKI) June 2026 + + + -04: voucher and request-voucher MUST be signed; examples for signed + request are added in appendix; IANA SID registration is updated; SID + values in examples are aligned; signed cms examples aligned with new + SIDs. + + -03: Examples are inverted. + + -02: Example of requestvoucher with unsigned application/cbor is + added; attributes of voucher "refined" to optional; CBOR + serialization of vouchers improved; Discovery port numbers are + specified. + + -01: application/json is optional, application/cbor is compulsory; + Cms and cose mediatypes are introduced. + + -00: Initial version. + +Authors' Addresses + + Michael Richardson + Sandelman Software Works + Email: mcr+ietf@sandelman.ca + + + Peter van der Stok + vanderstok consultancy + Email: stokcons@kpnmail.nl + + + Panos Kampanakis + Cisco Systems + Email: pkampana@cisco.com + + + Esko Dijk + IoTconsultancy.nl + Email: esko.dijk@iotconsultancy.nl + + + + + + + + + + + + + + +Richardson, et al. Expires 10 December 2026 [Page 96] diff --git a/docs/rfc9148-bis-source/rfc9148-bis-patch-map.md b/docs/rfc9148-bis-source/rfc9148-bis-patch-map.md new file mode 100644 index 0000000000..4b5c7bd7b6 --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-patch-map.md @@ -0,0 +1,31 @@ +# RFC 9148 bis patch map + +Mapping from **RFC 9148** locations to actions and **cBRSKI -31** source sections. + +| RFC 9148 bis location | Action | cBRSKI -31 source | Fragment block | +|-----------------------|--------|-------------------|----------------| +| §3 (after DTLS 1.3 paragraph) | INSERT §3.1 | §6.1.1 | `section-3.1` | +| §3 (replace Curve25519 future text) | REPLACE + INSERT §3.2 | §6.1.2.1, §6.1.2.2 | `section-3.2` | +| §3 (after fragmentation quote) | INSERT §3.3 | §6.1.4 | `section-3.3` | +| §4.1 discovery example | REPLACE `ct` on `/crts` line | §6.7.5 (implicit) | `section-4.1` | +| §4.1 (after well-known est paragraph) | INSERT base `rt` prose | §15.1 | `section-4.1` | +| §4.3 Payload Formats | REPLACE `/crts` CF paragraph | §6.7.5, §6.8 | `section-4.3` | +| §4.3 Payload Formats | ADD `/sen` `/sren` CF 287 MUST | §6.8 | `section-4.3-sen-sren` | +| §4.5 / Table 4 | ADD 4.06 for `/crts` Accept failure | §6.8 | `section-4.5` | +| §4.9 (new) | INSERT CA renewal | §6.7.2 | `section-4.9` | +| §4.10 (new) | INSERT re-enrollment + TA change | §6.7.3, §6.7.4 | `section-4.10` | +| §8.2 Resource Type registry | ADD `ace.est` row | §15.1 | `section-8.2` | +| Introduction | ADD Updates boilerplate | §5 | `front-matter` | + +## Not included in RFC 9148 bis (remain in cBRSKI only) + +| Topic | cBRSKI source | Reason | +|-------|---------------|--------| +| Voucher-pinned CA skip-`/crts` bootstrap | §6.7.1 steps 1–3 | BRSKI/cBRSKI-specific | +| Enrollment status telemetry `/es` on failure | §6.7.1 step 5, §6.7.4 step 4 | BRSKI resource; optional cross-ref only | +| Join Proxy PMTU motivation | §6.1.4 (Join Proxy) | Deployment-specific to cBRSKI | +| Registrar COSE header stripping | §6.8 (x5bag/x5chain) | cBRSKI voucher transport | + +## Renumbering note + +Inserting §4.9 and §4.10 may require renumbering subsequent RFC 9148 sections (current §4.6–§4.8 become §4.11–§4.13, etc.) unless the bis editor merges lifecycle text into an existing §4 subsection. diff --git a/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.mkd b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.mkd new file mode 100644 index 0000000000..604de1d5e4 --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.mkd @@ -0,0 +1,479 @@ +%%% + title = "EST-coaps Updates from cBRSKI (RFC 9148 bis fragment)" + abbrev = "EST-coaps-bis-fragment" + category = "std" + ipr = "trust200902" + area = "Ops" + workgroup = "Network Working Group" + keyword = ["EST", "CoAP", "DTLS", "IoT"] + + [seriesInfo] + name = "Internet-Draft" + value = "draft-example-est-coaps-rfc9148-bis-fragment-00" + stream = "IETF" + status = "informational" + + [[author]] + initials = "M." + surname = "Richardson" + fullname = "Michael Richardson" + organization = "Sandelman Software Works" + [author.address] + email = "mcr+ietf@sandelman.ca" + + [[author]] + initials = "P." + surname = "van der Stok" + fullname = "Peter van der Stok" + organization = "vanderstok consultancy" + [author.address] + email = "stokcons@kpnmail.nl" + + [normative] + RFC2119 = "RFC2119" + RFC8174 = "RFC8174" + RFC9148 = "RFC9148" + RFC9147 = "RFC9147" + RFC8446 = "RFC8446" + RFC8449 = "RFC8449" + RFC6066 = "RFC6066" + RFC7251 = "RFC7251" + RFC7252 = "RFC7252" + RFC7959 = "RFC7959" + RFC8710 = "RFC8710" + RFC7030 = "RFC7030" + RFC4210 = "RFC4210" + RFC6347 = "RFC6347" + RFC7925 = "RFC7925" + RFC8422 = "RFC8422" + + [informative] + CBRSKI = "I-D.draft-ietf-anima-constrained-voucher" +%%% + +--- abstract + +This document is a **fragment** for a future revision of RFC 9148 +(EST-coaps). It contains paste-ready replacement and insertion text +derived from draft-ietf-anima-constrained-voucher-31 (cBRSKI), which +Updates RFC 9148. Each section uses an anchor matching the target +location in RFC 9148. This fragment is intended for ANIMA WG editors +preparing an RFC 9148 bis or for implementers tracking normative deltas. + +--- middle + +# Introduction + +[RFC9148] defines Enrollment over Secure Transport (EST) for constrained +devices using CoAP and DTLS (EST-coaps). [CBRSKI] extends BRSKI for +constrained IoT deployments and Updates [RFC9148] in several areas: +DTLS version and cipher suite requirements, `/crts` payload formats, +CA certificate renewal, and client re-enrollment with trust anchor update. + +This fragment collects the EST-coaps-specific updates in RFC 9148 +section order. Text is generalized to EST-coaps client/server +terminology unless noted as cBRSKI-only. + +## Fragment conventions + +Each block below is labeled: + +- **REPLACE** — substitute for existing RFC 9148 text at this anchor. +- **INSERT** — add as a new subsection at this anchor. +- **ADD** — append to existing prose or a table at this anchor. + +--- note "Not for publication" +This is a working fragment, not a submitted Internet-Draft. Remove +boilerplate and renumber sections when merging into a full RFC 9148 bis. +--- end note + +
+ +**ADD** to the RFC 9148 bis document header and Introduction: + +``` +Updates: 9148 +``` + +Introduction paragraph to add: + +``` + This document updates [RFC9148] to specify mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. +``` + +
+ +
+ +**INSERT** new Section 3.1 after RFC 9148 Section 3 paragraph on DTLS 1.3 +Supported Groups (before server/client authentication text). + +``` +3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. +``` + +
+ +
+ +**REPLACE** in RFC 9148 Section 3 the sentence: + +> After the publication of [RFC7748], support for Curve25519 will likely be required in the future by (D)TLS profiles for the Internet of Things [RFC7925]. + +**With** new Section 3.2: + +``` +3.2. DTLS Cipher Suite Requirements + +3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + +3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. +``` + +
+ +
+ +**INSERT** new Section 3.3 after the existing RFC 9148 Section 3 quote from +[RFC6347] on DTLS handshake fragmentation. + +``` +3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). +``` + +
+ +
+ +**REPLACE** in the RFC 9148 Section 4.1 discovery response example: + +``` + ;rt="ace.est.crts";ct="281 287", +``` + +**With:** + +``` + ;rt="ace.est.crts";ct="62 281 287", +``` + +Apply the same `ct` change to the non-default port discovery example. + +**INSERT** after the paragraph *"The server MUST support the default +/.well-known/est root resource."*: + +``` + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. +``` + +
+ +
+ +**REPLACE** RFC 9148 Section 4.3 paragraphs from *"Content-Format 287 +can be used in place of 281…"* through *"…server SHOULD choose format +281."* **With:** + +``` + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified in this section. + + The client uses a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] +``` + +**Keep unchanged** the existing RFC 9148 Section 4.3 multipart `/skg` +example (Figure 2). + +
+ +
+ +**ADD** at the end of RFC 9148 Section 4.3 (before Section 4.4): + +``` + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. +``` + +
+ +
+ +**ADD** to RFC 9148 Section 4.5 prose and/or Table 4: + +``` + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). +``` + +Suggested Table 4 addition: + +``` + | /crts | 4.06 | Accept Option cannot be | + | | | satisfied (multi-TA). | +``` + +
+ +
+ +**INSERT** as new Section 4.9 (renumber subsequent Section 4.x as needed). + +``` +4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. +``` + +
+ +
+ +**INSERT** as new Section 4.10. + +``` +4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + +4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. +``` + +
+ +
+ +**ADD** row to RFC 9148 Table 6 (Resource Type registry): + +``` + +==========+===============================================+ + | ace.est | Base resource of all EST-coaps resources | + +==========+===============================================+ +``` + +Reference: This RFC (or cBRSKI if merged upstream). + +
+ +
+ +The following procedures from [CBRSKI] Section 6.7.1 are **not** included +in this RFC 9148 fragment because they depend on BRSKI voucher artifacts: + +1. Use voucher-pinned domain CA as provisional trust anchor (skip initial + `/crts`). +2. Proceed with `/sen` using provisional anchor. +3. Accept pinned root CA if it signed the LDevID; otherwise fetch `/crts` + and validate chain. +4. On failure, report via BRSKI enrollment status telemetry (`/es`). + +Implementers of cBRSKI should follow [CBRSKI] Section 6.7.1 in full. +EST-coaps-only deployments should follow Sections 4.9 and 4.10 of this +fragment (or the merged RFC 9148 bis). + +Cross-reference text optional in RFC 9148 bis Security Considerations: + +``` + Deployments using BRSKI or cBRSKI MAY optimize initial enrollment by + using voucher-pinned trust anchors; see [CBRSKI], Section 6.7.1. +``` + +
+ +--- backmatter + +# Acknowledgements + +Text in this fragment is derived from draft-ietf-anima-constrained-voucher-31 +by Michael Richardson, Peter van der Stok, Panos Kampanakis, and Esko Dijk. + +# Change Log + +- 00: Initial fragment extracted from cBRSKI -31 analysis. diff --git a/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.txt b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.txt new file mode 100644 index 0000000000..498b2e7cb1 --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.txt @@ -0,0 +1,309 @@ +================================================================================ +RFC 9148 BIS UPDATE FRAGMENT +Derived from: draft-ietf-anima-constrained-voucher-31 (2026-06-08) +Source WG: ANIMA +See also: rfc9148-bis-patch-map.md, rfc9148-bis-update-fragment.mkd +================================================================================ + +Each block is labeled REPLACE, INSERT, or ADD at the target RFC 9148 anchor. + +-------------------------------------------------------------------------------- +FRONT MATTER — ADD +-------------------------------------------------------------------------------- + +Updates: 9148 + +Introduction paragraph: + + This document updates [RFC9148] to specify mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. + +-------------------------------------------------------------------------------- +SECTION 3.1 — INSERT (after DTLS 1.3 Supported Groups paragraph) +-------------------------------------------------------------------------------- + +3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. + +-------------------------------------------------------------------------------- +SECTION 3.2 — REPLACE (Curve25519 "future" sentence) + INSERT +-------------------------------------------------------------------------------- + +3.2. DTLS Cipher Suite Requirements + +3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + +3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. + +-------------------------------------------------------------------------------- +SECTION 3.3 — INSERT (after RFC6347 fragmentation quote) +-------------------------------------------------------------------------------- + +3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). + +-------------------------------------------------------------------------------- +SECTION 4.1 — REPLACE discovery example ct= ; ADD base rt prose +-------------------------------------------------------------------------------- + +REPLACE: + ;rt="ace.est.crts";ct="281 287", +WITH: + ;rt="ace.est.crts";ct="62 281 287", + +(Same ct change in non-default port example.) + +ADD after "The server MUST support the default /.well-known/est root +resource.": + + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. + +-------------------------------------------------------------------------------- +SECTION 4.3 — REPLACE /crts payload format paragraphs +-------------------------------------------------------------------------------- + + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified in this section. + + The client uses a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] + +-------------------------------------------------------------------------------- +SECTION 4.3 — ADD (/sen and /sren) +-------------------------------------------------------------------------------- + + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. + +-------------------------------------------------------------------------------- +SECTION 4.5 — ADD (Table 4 / prose) +-------------------------------------------------------------------------------- + + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). + +-------------------------------------------------------------------------------- +SECTION 4.9 — INSERT (NEW) +-------------------------------------------------------------------------------- + +4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. + +-------------------------------------------------------------------------------- +SECTION 4.10 — INSERT (NEW) +-------------------------------------------------------------------------------- + +4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + +4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. + +-------------------------------------------------------------------------------- +SECTION 8.2 — ADD (Table 6 row) +-------------------------------------------------------------------------------- + + +==========+===============================================+ + | ace.est | Base resource of all EST-coaps resources | + +==========+===============================================+ + +-------------------------------------------------------------------------------- +INFORMATIVE — NOT FOR RFC 9148 BIS (cBRSKI Section 6.7.1 only) +-------------------------------------------------------------------------------- + + During BRSKI/cBRSKI onboarding, if the voucher pins a single domain + CA certificate, the Pledge MAY use that certificate as a provisional + EST trust anchor and proceed with /sen before performing /crts, + subject to chaining checks defined in [CBRSKI], Section 6.7.1. + + On enrollment failure, cBRSKI uses BRSKI enrollment status telemetry + (POST /.well-known/brski/es). Pure EST-coaps servers need not + implement /es. + +================================================================================ +END OF FRAGMENT +================================================================================ From a06e2523abd8ae897d2590f2beba8a3157d36c42 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 8 Jun 2026 20:04:42 +0000 Subject: [PATCH 14/15] Add RFC 7991 v3 XML fragment and xml2rfc-rendered output Provide valid xml2rfc source with full normative sourcecode blocks per RFC 9148 section anchor, plus rendered text output for validation. Co-authored-by: Mohamed --- docs/rfc9148-bis-source/README.md | 13 +- .../rfc9148-bis-update-fragment-from-xml.txt | 504 ++++++++++++++++++ .../rfc9148-bis-update-fragment.xml | 362 +++++++++++++ 3 files changed, 875 insertions(+), 4 deletions(-) create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-update-fragment-from-xml.txt create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-update-fragment.xml diff --git a/docs/rfc9148-bis-source/README.md b/docs/rfc9148-bis-source/README.md index a547aa1019..d1fb66943e 100644 --- a/docs/rfc9148-bis-source/README.md +++ b/docs/rfc9148-bis-source/README.md @@ -13,14 +13,19 @@ This directory holds source material for normative updates to [RFC 9148](https:/ | File | Purpose | |------|---------| | `draft-ietf-anima-constrained-voucher-31.txt` | Upstream cBRSKI Internet-Draft (reference copy) | -| `rfc9148-bis-update-fragment.mkd` | Paste-ready replacement/insert text for an RFC 9148 bis, with `
` tags aligned to RFC 9148 numbering | +| `rfc9148-bis-update-fragment.xml` | RFC 7991 v3 XML; render with `xml2rfc --text rfc9148-bis-update-fragment.xml` | +| `rfc9148-bis-update-fragment.mkd` | mmark/kramdown source with `
` anchors aligned to RFC 9148 numbering | +| `rfc9148-bis-update-fragment.txt` | Plain copy-paste blocks (no tooling required) | +| `rfc9148-bis-update-fragment-from-xml.txt` | Text rendered from XML via `xml2rfc --text` (validates XML structure) | | `rfc9148-bis-patch-map.md` | Section-by-section map: RFC 9148 location → action → cBRSKI source | ## Usage -1. Open `rfc9148-bis-update-fragment.mkd`. -2. For each `
` block, apply the indicated **REPLACE**, **INSERT**, or **ADD** action at that location in the RFC 9148 bis source. -3. Cross-check against `rfc9148-bis-patch-map.md` and the live cBRSKI draft before submitting to the ANIMA WG or RFC Editor. +1. **Quick copy-paste:** use `rfc9148-bis-update-fragment.txt`. +2. **Structured editing:** use `rfc9148-bis-update-fragment.mkd` or `rfc9148-bis-update-fragment.xml`. +3. **Validate XML:** `xml2rfc --text rfc9148-bis-update-fragment.xml` (produces `rfc9148-bis-update-fragment-from-xml.txt`). +4. For each block, apply the indicated **REPLACE**, **INSERT**, or **ADD** action at that location in the RFC 9148 bis source. +5. Cross-check against `rfc9148-bis-patch-map.md` and the live cBRSKI draft before submitting to the ANIMA WG or RFC Editor. ## Scope diff --git a/docs/rfc9148-bis-source/rfc9148-bis-update-fragment-from-xml.txt b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment-from-xml.txt new file mode 100644 index 0000000000..1ea650022a --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment-from-xml.txt @@ -0,0 +1,504 @@ + + + + +Network Working Group M. Richardson +Internet-Draft Sandelman Software Works +Intended status: Informational P. van der Stok +Expires: 10 December 2026 vanderstok consultancy + 8 June 2026 + + + EST-coaps Updates from cBRSKI (RFC 9148 bis Fragment) + draft-example-est-coaps-rfc9148-bis-fragment-00 + +Abstract + + Paste-ready replacement and insertion text for a future RFC 9148 + revision, derived from draft-ietf-anima-constrained-voucher-31 + (cBRSKI). Section anchors match target locations in RFC 9148. Full + normative paragraphs appear in sourcecode blocks within each section. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on 10 December 2026. + +Copyright Notice + + Copyright (c) 2026 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents (https://trustee.ietf.org/ + license-info) in effect on the date of publication of this document. + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. Code Components + extracted from this document must include Revised BSD License text as + described in Section 4.e of the Trust Legal Provisions and are + provided without warranty as described in the Revised BSD License. + + + + +Richardson & van der StoExpires 10 December 2026 [Page 1] + +Internet-Draft EST-coaps bis fragment June 2026 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Front Matter (ADD) . . . . . . . . . . . . . . . . . . . . . 2 + 3. Section 3.1 DTLS Version Requirements (INSERT) . . . . . . . 2 + 4. Section 3.2 DTLS Cipher Suite Requirements (REPLACE) . . . . 3 + 5. Section 3.3 DTLS Fragmentation (INSERT) . . . . . . . . . . . 4 + 6. Section 4.1 Resource Discovery (REPLACE and ADD) . . . . . . 5 + 7. Section 4.3 Payload Formats (REPLACE and ADD) . . . . . . . . 5 + 8. Section 4.5 CoAP Response Codes (ADD) . . . . . . . . . . . . 6 + 9. Section 4.9 Renewal of CA Certificates (INSERT) . . . . . . . 7 + 10. Section 4.10 Re-enrollment Procedure (INSERT) . . . . . . . . 7 + 11. Section 8.2 Resource Type Registry (ADD) . . . . . . . . . . 8 + 12. Informative: cBRSKI-only (NOT for RFC 9148 bis) . . . . . . . 8 + 13. Normative References . . . . . . . . . . . . . . . . . . . . 9 + 14. Informative References . . . . . . . . . . . . . . . . . . . 9 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 9 + +1. Introduction + + [RFC9148] defines EST-coaps. [CBRSKI] Updates [RFC9148]. This + fragment collects EST-coaps-specific deltas in RFC 9148 section + order. See also rfc9148-bis-patch-map.md in this directory for the + action map. + + Each section below is labeled REPLACE, INSERT, or ADD. Merge into an + RFC 9148 bis source; renumber Section 4.x as needed when inserting + Sections 4.9 and 4.10. + +2. Front Matter (ADD) + + Updates: 9148 + + This document updates [RFC9148] to specify mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. + +3. Section 3.1 DTLS Version Requirements (INSERT) + + INSERT after RFC 9148 Section 3 DTLS 1.3 Supported Groups paragraph. + + + + + + + +Richardson & van der StoExpires 10 December 2026 [Page 2] + +Internet-Draft EST-coaps bis fragment June 2026 + + + 3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. + +4. Section 3.2 DTLS Cipher Suite Requirements (REPLACE) + + REPLACE RFC 9148 Section 3 sentence on future Curve25519 requirement. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Richardson & van der StoExpires 10 December 2026 [Page 3] + +Internet-Draft EST-coaps bis fragment June 2026 + + + 3.2. DTLS Cipher Suite Requirements + + 3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + + 3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. + +5. Section 3.3 DTLS Fragmentation (INSERT) + + INSERT after RFC 9148 Section 3 RFC6347 fragmentation quote. + + + + +Richardson & van der StoExpires 10 December 2026 [Page 4] + +Internet-Draft EST-coaps bis fragment June 2026 + + + 3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). + +6. Section 4.1 Resource Discovery (REPLACE and ADD) + + REPLACE: + ;rt="ace.est.crts";ct="281 287", + WITH: + ;rt="ace.est.crts";ct="62 281 287", + + (Same ct change in non-default port example.) + + ADD after "The server MUST support the default /.well-known/est root + resource.": + + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. + +7. Section 4.3 Payload Formats (REPLACE and ADD) + + REPLACE /crts paragraphs in Section 4.3: + + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified in this section. + + The client uses a CoAP Accept Option in the request to express the + + + +Richardson & van der StoExpires 10 December 2026 [Page 5] + +Internet-Draft EST-coaps bis fragment June 2026 + + + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] + + ADD at end of Section 4.3: + + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. + +8. Section 4.5 CoAP Response Codes (ADD) + + + + + + + +Richardson & van der StoExpires 10 December 2026 [Page 6] + +Internet-Draft EST-coaps bis fragment June 2026 + + + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). + +9. Section 4.9 Renewal of CA Certificates (INSERT) + + 4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. + +10. Section 4.10 Re-enrollment Procedure (INSERT) + + 4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + + + +Richardson & van der StoExpires 10 December 2026 [Page 7] + +Internet-Draft EST-coaps bis fragment June 2026 + + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + + 4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. + +11. Section 8.2 Resource Type Registry (ADD) + + +==========+===============================================+ + | ace.est | Base resource of all EST-coaps resources | + +==========+===============================================+ + +12. Informative: cBRSKI-only (NOT for RFC 9148 bis) + + + + + + + + +Richardson & van der StoExpires 10 December 2026 [Page 8] + +Internet-Draft EST-coaps bis fragment June 2026 + + + During BRSKI/cBRSKI onboarding, if the voucher pins a single domain + CA certificate, the Pledge MAY use that certificate as a provisional + EST trust anchor and proceed with /sen before performing /crts, + subject to chaining checks defined in [CBRSKI], Section 6.7.1. + + On enrollment failure, cBRSKI uses BRSKI enrollment status telemetry + (POST /.well-known/brski/es). Pure EST-coaps servers need not + implement /es. + +13. Normative References + + [RFC9148] van der Stok, P., "EST over secure CoAP (EST-coaps)", + RFC 9148, April 2022, + . + +14. Informative References + + [CBRSKI] Richardson, M., "Constrained Bootstrapping Remote Secure + Key Infrastructure (cBRSKI)", Work in Progress, Internet- + Draft, draft-ietf-anima-constrained-voucher-31, 8 June + 2026, . + +Authors' Addresses + + Michael Richardson + Sandelman Software Works + Email: mcr+ietf@sandelman.ca + + + Peter van der Stok + vanderstok consultancy + Email: stokcons@kpnmail.nl + + + + + + + + + + + + + + + + + + +Richardson & van der StoExpires 10 December 2026 [Page 9] diff --git a/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.xml b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.xml new file mode 100644 index 0000000000..42f18cc3d6 --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-update-fragment.xml @@ -0,0 +1,362 @@ + + + + + EST-coaps Updates from cBRSKI (RFC 9148 bis Fragment) + + + Sandelman Software Works +
mcr+ietf@sandelman.ca
+
+ + vanderstok consultancy +
stokcons@kpnmail.nl
+
+ + + Paste-ready replacement and insertion text for a future RFC 9148 revision, derived from draft-ietf-anima-constrained-voucher-31 (cBRSKI). Section anchors match target locations in RFC 9148. Full normative paragraphs appear in sourcecode blocks within each section. + +
+ + +
+ Introduction + defines EST-coaps. Updates . This fragment collects EST-coaps-specific deltas in RFC 9148 section order. See also rfc9148-bis-patch-map.md in this directory for the action map. + Each section below is labeled REPLACE, INSERT, or ADD. Merge into an RFC 9148 bis source; renumber Section 4.x as needed when inserting Sections 4.9 and 4.10. +
+ +
+ Front Matter (ADD) + +Updates: 9148 + + This document updates [RFC9148] to specify mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. + +
+ +
+ Section 3.1 DTLS Version Requirements (INSERT) + INSERT after RFC 9148 Section 3 DTLS 1.3 Supported Groups paragraph. + +3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. + +
+ +
+ Section 3.2 DTLS Cipher Suite Requirements (REPLACE) + REPLACE RFC 9148 Section 3 sentence on future Curve25519 requirement. + +3.2. DTLS Cipher Suite Requirements + +3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + +3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. + +
+ +
+ Section 3.3 DTLS Fragmentation (INSERT) + INSERT after RFC 9148 Section 3 RFC6347 fragmentation quote. + +3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). + +
+ +
+ Section 4.1 Resource Discovery (REPLACE and ADD) + +REPLACE: + </est/crts>;rt="ace.est.crts";ct="281 287", +WITH: + </est/crts>;rt="ace.est.crts";ct="62 281 287", + +(Same ct change in non-default port example.) + +ADD after "The server MUST support the default /.well-known/est root +resource.": + + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. + +
+ +
+ Section 4.3 Payload Formats (REPLACE and ADD) + +REPLACE /crts paragraphs in Section 4.3: + + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified in this section. + + The client uses a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] + +ADD at end of Section 4.3: + + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. + +
+ +
+ Section 4.5 CoAP Response Codes (ADD) + + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). + +
+ +
+ Section 4.9 Renewal of CA Certificates (INSERT) + +4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. + +
+ +
+ Section 4.10 Re-enrollment Procedure (INSERT) + +4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + +4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. + +
+ +
+ Section 8.2 Resource Type Registry (ADD) + + +==========+===============================================+ + | ace.est | Base resource of all EST-coaps resources | + +==========+===============================================+ + +
+ +
+ Informative: cBRSKI-only (NOT for RFC 9148 bis) + + During BRSKI/cBRSKI onboarding, if the voucher pins a single domain + CA certificate, the Pledge MAY use that certificate as a provisional + EST trust anchor and proceed with /sen before performing /crts, + subject to chaining checks defined in [CBRSKI], Section 6.7.1. + + On enrollment failure, cBRSKI uses BRSKI enrollment status telemetry + (POST /.well-known/brski/es). Pure EST-coaps servers need not + implement /es. + +
+
+ + + + Normative References + + + EST over secure CoAP (EST-coaps) + + + + + + + + Informative References + + + Constrained Bootstrapping Remote Secure Key Infrastructure (cBRSKI) + + + + + + + +
From dca25ff7ab741db71a596d826a1155e6f5b469c1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 8 Jun 2026 20:06:58 +0000 Subject: [PATCH 15/15] Add merged RFC 9148 bis skeleton with build script Apply all cBRSKI-derived fragment updates to full RFC 9148 text: new Sections 3.1-3.3, 4.9-4.10, /crts formats, discovery, and IANA. Co-authored-by: Mohamed --- docs/rfc9148-bis-source/README.md | 22 +- .../build-rfc9148-bis-skeleton.py | 475 ++++ .../rfc9148-bis-skeleton.mkd | 2302 +++++++++++++++++ .../rfc9148-bis-skeleton.txt | 2285 ++++++++++++++++ docs/rfc9148-bis-source/rfc9148.txt | 2108 +++++++++++++++ 5 files changed, 7188 insertions(+), 4 deletions(-) create mode 100644 docs/rfc9148-bis-source/build-rfc9148-bis-skeleton.py create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-skeleton.mkd create mode 100644 docs/rfc9148-bis-source/rfc9148-bis-skeleton.txt create mode 100644 docs/rfc9148-bis-source/rfc9148.txt diff --git a/docs/rfc9148-bis-source/README.md b/docs/rfc9148-bis-source/README.md index d1fb66943e..c9d23326d7 100644 --- a/docs/rfc9148-bis-source/README.md +++ b/docs/rfc9148-bis-source/README.md @@ -17,15 +17,29 @@ This directory holds source material for normative updates to [RFC 9148](https:/ | `rfc9148-bis-update-fragment.mkd` | mmark/kramdown source with `
` anchors aligned to RFC 9148 numbering | | `rfc9148-bis-update-fragment.txt` | Plain copy-paste blocks (no tooling required) | | `rfc9148-bis-update-fragment-from-xml.txt` | Text rendered from XML via `xml2rfc --text` (validates XML structure) | +| `rfc9148-bis-skeleton.txt` | **Merged RFC 9148 bis skeleton** (RFC 9148 + all fragment updates applied) | +| `rfc9148-bis-skeleton.mkd` | Same skeleton wrapped for mmark (regenerate via build script) | +| `build-rfc9148-bis-skeleton.py` | Script to regenerate the merged skeleton from `rfc9148.txt` | | `rfc9148-bis-patch-map.md` | Section-by-section map: RFC 9148 location → action → cBRSKI source | +| `rfc9148.txt` | Cached RFC 9148 source text (downloaded by build script) | -## Usage +## Regenerate merged skeleton + +```bash +cd docs/rfc9148-bis-source +python3 build-rfc9148-bis-skeleton.py +``` + +Downloads `rfc9148.txt` if missing, applies all fragment updates, writes +`rfc9148-bis-skeleton.txt` and `rfc9148-bis-skeleton.mkd`. + +## Usage (fragment-only workflow) 1. **Quick copy-paste:** use `rfc9148-bis-update-fragment.txt`. 2. **Structured editing:** use `rfc9148-bis-update-fragment.mkd` or `rfc9148-bis-update-fragment.xml`. -3. **Validate XML:** `xml2rfc --text rfc9148-bis-update-fragment.xml` (produces `rfc9148-bis-update-fragment-from-xml.txt`). -4. For each block, apply the indicated **REPLACE**, **INSERT**, or **ADD** action at that location in the RFC 9148 bis source. -5. Cross-check against `rfc9148-bis-patch-map.md` and the live cBRSKI draft before submitting to the ANIMA WG or RFC Editor. +3. **Full merged draft:** use `rfc9148-bis-skeleton.txt` (or regenerate with the build script). +4. **Validate XML:** `xml2rfc --text rfc9148-bis-update-fragment.xml`. +5. Cross-check against `rfc9148-bis-patch-map.md` and cBRSKI -31 before WG submission. ## Scope diff --git a/docs/rfc9148-bis-source/build-rfc9148-bis-skeleton.py b/docs/rfc9148-bis-source/build-rfc9148-bis-skeleton.py new file mode 100644 index 0000000000..fe0fe0651b --- /dev/null +++ b/docs/rfc9148-bis-source/build-rfc9148-bis-skeleton.py @@ -0,0 +1,475 @@ +#!/usr/bin/env python3 +"""Merge RFC 9148 with cBRSKI-derived updates into a bis skeleton.""" + +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +RFC9148 = ROOT / "rfc9148.txt" +FRAGMENT = ROOT / "rfc9148-bis-update-fragment.txt" +OUT_TXT = ROOT / "rfc9148-bis-skeleton.txt" +OUT_MKD = ROOT / "rfc9148-bis-skeleton.mkd" + +BIS_HEADER = """\ +================================================================================ +WORK IN PROGRESS — RFC 9148 bis skeleton (not submitted to IETF) +Merged from RFC 9148 + updates derived from draft-ietf-anima-constrained-voucher-31 +Generated by build-rfc9148-bis-skeleton.py — review before any publication use +================================================================================ + +Internet-Draft Skeleton Editor +Obsoletes: 9148 (if approved) P. van der Stok +Intended status: Standards Track (based on RFC 9148 authors) +Expires: TBD + + EST over secure CoAP (EST-coaps) + bis skeleton draft + +""" + +INTRO_ADDITION = """ + This document obsoletes [RFC9148]. It adds mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. +""" + +SECTION_3_1 = """ +3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. +""" + +SECTION_3_2 = """ +3.2. DTLS Cipher Suite Requirements + +3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + +3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. +""" + +SECTION_3_3 = """ +3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). +""" + +ACE_EST_RT = """ + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. +""" + +SECTION_4_3_CRTS = """\ + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified below. + + The client uses a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] +""" + +SECTION_4_3_SEN = """ + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. +""" + +SECTION_4_5_ADD = """ + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). +""" + +SECTION_4_9 = """ +4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. +""" + +SECTION_4_10 = """ +4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + +4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. +""" + +OLD_CIPHER_BLOCK = """\ + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. After the publication of [RFC7748], support for Curve25519 + will likely be required in the future by (D)TLS profiles for the + Internet of Things [RFC7925]. +""" + +OLD_4_3_BLOCK = """\ + Content-Format 287 can be used in place of 281 to carry a single + certificate instead of a PKCS #7 container in a /crts, /sen, /sren, + or /skg response. Content-Format 281 MUST be supported by EST-coaps + servers. Servers MAY also support Content-Format 287. It is up to + the client to support only Content-Format 281, 287 or both. The + client will use a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. +""" + + +def merge(text: str) -> str: + # Strip RFC front matter through section 1 header; prepend bis header + idx = text.find("1. Introduction") + if idx == -1: + raise SystemExit("Could not find Introduction in RFC 9148 source") + body = text[idx:] + + # Introduction addition + marker = " supported.\n\n2. Terminology" + if marker not in body: + raise SystemExit("Introduction marker not found") + body = body.replace(marker, " supported." + INTRO_ADDITION + "\n\n2. Terminology", 1) + + # Section 3: remove old cipher block, insert 3.1-3.3 after Supported Groups + if OLD_CIPHER_BLOCK not in body: + raise SystemExit("Old cipher block not found in RFC 9148") + body = body.replace(OLD_CIPHER_BLOCK, "", 1) + + groups_anchor = ( + " extension has been renamed to Supported Groups.\n\n" + " CoAP was designed to avoid IP fragmentation." + ) + if groups_anchor not in body: + raise SystemExit("Supported Groups anchor not found") + body = body.replace( + groups_anchor, + " extension has been renamed to Supported Groups.\n" + + SECTION_3_1 + + SECTION_3_2 + + "\n CoAP was designed to avoid IP fragmentation.", + 1, + ) + + frag_anchor = ' avoiding IP fragmentation" [RFC6347].\n\n The authentication' + if frag_anchor not in body: + raise SystemExit("Fragmentation anchor not found") + body = body.replace( + frag_anchor, + ' avoiding IP fragmentation" [RFC6347].\n' + SECTION_3_3 + "\n The authentication", + 1, + ) + + # Section 4.1 discovery ct on /crts only (not /sen or /sren) + body = body.replace( + ';rt="ace.est.crts";ct="281 287"', + ';rt="ace.est.crts";ct="62 281 287"', + ) + body = body.replace( + 'ace.est.crts";\n ct="281 287"', + 'ace.est.crts";\n ct="62 281 287"', + ) + rt_anchor = ( + " The server MUST support the default /.well-known/est root resource.\n" + " The server SHOULD support resource discovery" + ) + if rt_anchor not in body: + raise SystemExit("4.1 rt anchor not found") + body = body.replace( + rt_anchor, + " The server MUST support the default /.well-known/est root resource.\n" + + ACE_EST_RT + + "\n The server SHOULD support resource discovery", + 1, + ) + + # Section 4.3 + if OLD_4_3_BLOCK not in body: + raise SystemExit("Old 4.3 block not found") + body = body.replace(OLD_4_3_BLOCK, SECTION_4_3_CRTS + "\n", 1) + + sen_anchor = ( + " binary form. An example is shown in Appendix A.3.\n\n4.4. Message Bindings" + ) + if sen_anchor not in body: + raise SystemExit("4.3 sen anchor not found") + body = body.replace( + sen_anchor, + " binary form. An example is shown in Appendix A.3.\n" + + SECTION_4_3_SEN + + "\n4.4. Message Bindings", + 1, + ) + + # Section 4.5 + table4_anchor = " codes in EST-coaps. Table 4 summarizes the EST-coaps response codes.\n" + if table4_anchor not in body: + raise SystemExit("4.5 table anchor not found") + body = body.replace( + table4_anchor, + " codes in EST-coaps." + SECTION_4_5_ADD + "\n Table 4 summarizes the EST-coaps response codes.\n", + 1, + ) + body = body.replace( + " | /crts, /att | 2.05 | Success. Certs included |\n" + " | | | in the response payload. |\n" + " +-------------+-------------------------+--------------------------+\n" + " | | 4.xx / 5.xx | Failure. |", + " | /crts, /att | 2.05 | Success. Certs included |\n" + " | | | in the response payload. |\n" + " +-------------+-------------------------+--------------------------+\n" + " | /crts | 4.06 | Accept Option cannot be |\n" + " | | | satisfied (multi-TA). |\n" + " +-------------+-------------------------+--------------------------+\n" + " | | 4.xx / 5.xx | Failure. |", + 1, + ) + + # Sections 4.9 and 4.10 after 4.8 + sec5_anchor = "\n5. HTTPS-CoAPS Registrar\n" + if sec5_anchor not in body: + raise SystemExit("Section 5 anchor not found") + body = body.replace(sec5_anchor, SECTION_4_9 + SECTION_4_10 + sec5_anchor, 1) + + # Section 8.2 ace.est row + body = body.replace( + " +==============+===================================+===========+\n" + " | Value | Description | Reference |\n" + " +==============+===================================+===========+\n" + " | ace.est.crts |", + " +==============+===================================+===========+\n" + " | Value | Description | Reference |\n" + " +==============+===================================+===========+\n" + " | ace.est | Base resource of all EST-coaps | This doc |\n" + " | | resources | |\n" + " +--------------+-----------------------------------+-----------+\n" + " | ace.est.crts |", + 1, + ) + + # Informative reference stub for CBRSKI in section 10.2 + cbrski_ref = """ + [CBRSKI] Richardson, M., van der Stok, P., Kampanakis, P., and E. + Dijk, "Constrained Bootstrapping Remote Secure Key + Infrastructure (cBRSKI)", Work in Progress, draft-ietf- + anima-constrained-voucher-31, 8 June 2026, + . +""" + sec10_2 = "10.2. Informative References\n" + if sec10_2 not in body: + raise SystemExit("10.2 not found") + body = body.replace(sec10_2, sec10_2 + cbrski_ref, 1) + + return BIS_HEADER + body + + +def main() -> None: + if not RFC9148.exists(): + import urllib.request + + url = "https://www.rfc-editor.org/rfc/rfc9148.txt" + print(f"Downloading {url} ...") + RFC9148.write_bytes(urllib.request.urlopen(url).read()) + + merged = merge(RFC9148.read_text()) + OUT_TXT.write_text(merged) + + mkd = ( + "%%%\n" + "title = \"EST over secure CoAP (EST-coaps) — bis skeleton\"\n" + "abbrev = \"EST-coaps-bis\"\n" + "category = \"std\"\n" + "ipr = \"trust200902\"\n" + "submissionType = \"IETF\"\n" + "version = \"3\"\n" + "obsoletes = [\"9148\"]\n" + "%%%\n\n" + "--- note \"Work in Progress\"\n" + "Skeleton merged from RFC 9148 and cBRSKI -31 updates. " + "Regenerate with `python3 build-rfc9148-bis-skeleton.py`.\n" + "--- end note\n\n" + "```\n" + + merged + + "\n```\n" + ) + OUT_MKD.write_text(mkd) + print(f"Wrote {OUT_TXT} ({OUT_TXT.stat().st_size} bytes)") + print(f"Wrote {OUT_MKD} ({OUT_MKD.stat().st_size} bytes)") + + +if __name__ == "__main__": + main() diff --git a/docs/rfc9148-bis-source/rfc9148-bis-skeleton.mkd b/docs/rfc9148-bis-source/rfc9148-bis-skeleton.mkd new file mode 100644 index 0000000000..fbe67e6ca1 --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-skeleton.mkd @@ -0,0 +1,2302 @@ +%%% +title = "EST over secure CoAP (EST-coaps) — bis skeleton" +abbrev = "EST-coaps-bis" +category = "std" +ipr = "trust200902" +submissionType = "IETF" +version = "3" +obsoletes = ["9148"] +%%% + +--- note "Work in Progress" +Skeleton merged from RFC 9148 and cBRSKI -31 updates. Regenerate with `python3 build-rfc9148-bis-skeleton.py`. +--- end note + +``` +================================================================================ +WORK IN PROGRESS — RFC 9148 bis skeleton (not submitted to IETF) +Merged from RFC 9148 + updates derived from draft-ietf-anima-constrained-voucher-31 +Generated by build-rfc9148-bis-skeleton.py — review before any publication use +================================================================================ + +Internet-Draft Skeleton Editor +Obsoletes: 9148 (if approved) P. van der Stok +Intended status: Standards Track (based on RFC 9148 authors) +Expires: TBD + + EST over secure CoAP (EST-coaps) + bis skeleton draft + +1. Introduction + 2. Terminology + 3. DTLS and Conformance to RFC 7925 Profiles + 4. Protocol Design + 4.1. Discovery and URIs + 4.2. Mandatory/Optional EST Functions + 4.3. Payload Formats + 4.4. Message Bindings + 4.5. CoAP Response Codes + 4.6. Message Fragmentation + 4.7. Delayed Responses + 4.8. Server-Side Key Generation + 5. HTTPS-CoAPS Registrar + 6. Parameters + 7. Deployment Limitations + 8. IANA Considerations + 8.1. Content-Formats Registry + 8.2. Resource Type Registry + 8.3. Well-Known URIs Registry + 9. Security Considerations + 9.1. EST Server Considerations + 9.2. HTTPS-CoAPS Registrar Considerations + 10. References + 10.1. Normative References + 10.2. Informative References + + [CBRSKI] Richardson, M., van der Stok, P., Kampanakis, P., and E. + Dijk, "Constrained Bootstrapping Remote Secure Key + Infrastructure (cBRSKI)", Work in Progress, draft-ietf- + anima-constrained-voucher-31, 8 June 2026, + . + Appendix A. EST Messages to EST-coaps + A.1. cacerts + A.2. enroll / reenroll + A.3. serverkeygen + A.4. csrattrs + Appendix B. EST-coaps Block Message Examples + B.1. cacerts + B.2. enroll / reenroll + Appendix C. Message Content Breakdown + C.1. cacerts + C.2. enroll / reenroll + C.3. serverkeygen + Acknowledgements + Contributors + Authors' Addresses + +1. Introduction + + "Classical" Enrollment over Secure Transport (EST) [RFC7030] is used + for authenticated/authorized endpoint certificate enrollment (and + optionally key provisioning) through a Certification Authority (CA) + or Registration Authority (RA). EST transports messages over HTTPS. + + This document defines a new transport for EST based on the + Constrained Application Protocol (CoAP) since some Internet of Things + (IoT) devices use CoAP instead of HTTP. Therefore, this + specification utilizes DTLS [RFC6347] and CoAP [RFC7252] instead of + TLS [RFC8446] and HTTP [RFC7230]. + + EST responses can be relatively large, and for this reason, this + specification also uses CoAP Block-Wise Transfer [RFC7959] to offer a + fragmentation mechanism of EST messages at the CoAP layer. + + This document also profiles the use of EST to support certificate- + based client authentication only. Neither HTTP Basic nor Digest + authentication (as described in Section 3.2.3 of [RFC7030]) is + supported. + This document obsoletes [RFC9148]. It adds mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. + + +2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + Many of the concepts in this document are taken from [RFC7030]. + Consequently, much text is directly traceable to [RFC7030]. + +3. DTLS and Conformance to RFC 7925 Profiles + + This section describes how EST-coaps conforms to the profiles of low- + resource devices described in [RFC7925]. EST-coaps can transport + certificates and private keys. Certificates are responses to + (re-)enrollment requests or requests for a trusted certificate list. + Private keys can be transported as responses to a server-side key + generation request as described in Section 4.4 of [RFC7030] (and + subsections) and discussed in Section 4.8 of this document. + + EST-coaps depends on a secure transport mechanism that secures the + exchanged CoAP messages. DTLS is one such secure protocol. No other + changes are necessary regarding the secure transport of EST messages. + + +------------------------------------------------+ + | EST request/response messages | + +------------------------------------------------+ + | CoAP for message transfer and signaling | + +------------------------------------------------+ + | Secure Transport | + +------------------------------------------------+ + + Figure 1: EST-coaps Protocol Layers + + + DTLS 1.2 implementations must use the Supported Elliptic Curves and + Supported Point Formats Extensions in [RFC8422]. Uncompressed point + format must also be supported. DTLS 1.3 [RFC9147] implementations + differ from DTLS 1.2 because they do not support point format + negotiation in favor of a single point format for each curve. Thus, + support for DTLS 1.3 does not mandate point format extensions and + negotiation. In addition, in DTLS 1.3, the Supported Elliptic Curves + extension has been renamed to Supported Groups. + +3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. + +3.2. DTLS Cipher Suite Requirements + +3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + +3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. + + CoAP was designed to avoid IP fragmentation. DTLS is used to secure + CoAP messages. However, fragmentation is still possible at the DTLS + layer during the DTLS handshake even when using Elliptic Curve + Cryptography (ECC) cipher suites. If fragmentation is necessary, + "DTLS provides a mechanism for fragmenting a handshake message over a + number of records, each of which can be transmitted separately, thus + avoiding IP fragmentation" [RFC6347]. + +3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). + + The authentication of the EST-coaps server by the EST-coaps client is + based on certificate authentication in the DTLS handshake. The EST- + coaps client MUST be configured with at least an Implicit Trust + Anchor database, which will enable the authentication of the server + the first time before updating its trust anchor (Explicit TA) + [RFC7030]. + + The authentication of the EST-coaps client MUST be with a client + certificate in the DTLS handshake. This can either be: + + * A previously issued client certificate (e.g., an existing + certificate issued by the EST CA); this could be a common case for + simple re-enrollment of clients. + + * A previously installed certificate (e.g., manufacturer IDevID + [IEEE802.1AR] or a certificate issued by some other party). + IDevID's are expected to have a very long life, as long as the + device, but under some conditions could expire. In that case, the + server MAY authenticate a client certificate against its trust + store though the certificate is expired (Section 9). + + EST-coaps supports the certificate types and TAs that are specified + for EST in Section 3 of [RFC7030]. + + As described in Section 2.1 of [RFC5272], proof-of-identity refers to + a value that can be used to prove that an end entity or client is in + the possession of and can use the private key corresponding to the + certified public key. Additionally, channel-binding information can + link proof-of-identity with an established connection. Connection- + based proof-of-possession is OPTIONAL for EST-coaps clients and + servers. When proof-of-possession is desired, a set of actions are + required regarding the use of tls-unique, described in Section 3.5 of + [RFC7030]. The tls-unique information consists of the contents of + the first Finished message in the (D)TLS handshake between server and + client [RFC5929]. The client adds the Finished message as a + challengePassword in the attributes section of the PKCS #10 + CertificationRequest [RFC5967] to prove that the client is indeed in + control of the private key at the time of the (D)TLS session + establishment. In the case of handshake message fragmentation, if + proof-of-possession is desired, the Finished message added as the + challengePassword in the Certificate Signing Request (CSR) is + calculated as specified by (D)TLS. We summarize it here for + convenience. For DTLS 1.2, in the event of handshake message + fragmentation, the hash of the handshake messages used in the Message + Authentication Code (MAC) calculation of the Finished message must be + computed on each reassembled message, as if each message had not been + fragmented (Section 4.2.6 of [RFC6347]). The Finished message is + calculated as shown in Section 7.4.9 of [RFC5246]. + + For (D)TLS 1.3, Appendix C.5 of [RFC8446] describes the lack of + channel bindings similar to tls-unique. [TLS13-CHANNEL-BINDINGS] can + be used instead to derive a 32-byte tls-exporter binding from the + (D)TLS 1.3 master secret by using a PRF negotiated in the (D)TLS 1.3 + handshake, "EXPORTER-Channel-Binding" with no terminating NUL as the + label, the ClientHello.random and ServerHello.random, and a zero- + length context string. When proof-of-possession is desired, the + client adds the tls-exporter value as a challengePassword in the + attributes section of the PKCS #10 CertificationRequest [RFC5967] to + prove that the client is indeed in control of the private key at the + time of the (D)TLS session establishment. + + In a constrained CoAP environment, endpoints can't always afford to + establish a DTLS connection for every EST transaction. An EST-coaps + DTLS connection MAY remain open for sequential EST transactions, + which was not the case with [RFC7030]. For example, if a /crts + request is followed by a /sen request, both can use the same + authenticated DTLS connection. However, when a /crts request is + included in the set of sequential EST transactions, some additional + security considerations apply regarding the use of the Implicit and + Explicit TA database as explained in Section 9.1. + + Given that after a successful enrollment, it is more likely that a + new EST transaction will not take place for a significant amount of + time, the DTLS connections SHOULD only be kept alive for EST messages + that are relatively close to each other. These could include a /sen + immediately following a /crts when a device is getting bootstrapped. + In some cases, like NAT rebinding, keeping the state of a connection + is not possible when devices sleep for extended periods of time. In + such occasions, [RFC9146] negotiates a connection ID that can + eliminate the need for a new handshake and its additional cost; or, + DTLS session resumption provides a less costly alternative than + redoing a full DTLS handshake. + +4. Protocol Design + + EST-coaps uses CoAP to transfer EST messages, aided by Block-Wise + Transfer [RFC7959], to avoid IP fragmentation. The use of blocks for + the transfer of larger EST messages is specified in Section 4.6. + Figure 1 shows the layered EST-coaps architecture. + + The EST-coaps protocol design follows closely the EST design. The + supported message types in EST-coaps are: + + * CA certificate retrieval needed to receive the complete set of CA + certificates. + + * Simple enroll and re-enroll for a CA to sign client identity + public keys. + + * Certificate Signing Request (CSR) attribute messages that informs + the client of the fields to include in a CSR. + + * Server-side key generation messages to provide a client identity + private key when the client chooses so. + + While [RFC7030] permits a number of the EST functions to be used + without authentication, this specification requires that the client + MUST be authenticated for all functions. + +4.1. Discovery and URIs + + EST-coaps is targeted for low-resource networks with small packets. + Two types of installations are possible: (1) a rigid one, where the + address and the supported functions of the EST server(s) are known, + and (2) a flexible one, where the EST server and its supported + functions need to be discovered. + + For both types of installations, saving header space is important and + short EST-coaps URIs are specified in this document. These URIs are + shorter than the ones in [RFC7030]. Two example EST-coaps resource + path names are: + + coaps://example.com:/.well-known/est/ + coaps://example.com:/.well-known/est/ArbitraryLabel/ + + The short-est strings are defined in Table 1. Arbitrary Labels are + usually defined and used by EST CAs in order to route client requests + to the appropriate certificate profile. Implementers should consider + using short labels to minimize transmission overhead. + + The EST-coaps server URIs, obtained through discovery of the EST- + coaps resource(s) as shown below, are of the form: + + coaps://example.com:// + coaps://example.com://ArbitraryLabel/ + + Figure 5 in Section 3.2.2 of [RFC7030] enumerates the operations and + corresponding paths that are supported by EST. Table 1 provides the + mapping from the EST URI path to the shorter EST-coaps URI path. + + +=================+==============================+ + | EST | EST-coaps | + +=================+==============================+ + | /cacerts | /crts | + +-----------------+------------------------------+ + | /simpleenroll | /sen | + +-----------------+------------------------------+ + | /simplereenroll | /sren | + +-----------------+------------------------------+ + | /serverkeygen | /skg (PKCS #7) | + +-----------------+------------------------------+ + | /serverkeygen | /skc (application/pkix-cert) | + +-----------------+------------------------------+ + | /csrattrs | /att | + +-----------------+------------------------------+ + + Table 1: Short EST-coaps URI Path + + The /skg message is the EST /serverkeygen equivalent where the client + requests a certificate in PKCS #7 format and a private key. If the + client prefers a single application/pkix-cert certificate instead of + PKCS #7, it will make an /skc request. In both cases (i.e., /skg, + /skc), a private key MUST be returned. + + Clients and servers MUST support the short resource EST-coaps URIs. + + In the context of CoAP, the presence and location of (path to) the + EST resources are discovered by sending a GET request to "/.well- + known/core" including a resource type (RT) parameter with the value + "ace.est*" [RFC6690]. The example below shows the discovery over + CoAPS of the presence and location of EST-coaps resources. Linefeeds + are included only for readability. + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + ;rt="ace.est.crts";ct="62 281 287", + ;rt="ace.est.sen";ct="281 287", + ;rt="ace.est.sren";ct="281 287", + ;rt="ace.est.att";ct=285, + ;rt="ace.est.skg";ct=62, + ;rt="ace.est.skc";ct=62 + + The first three lines, describing ace.est.crts, ace.est.sen, and + ace.est.sren, of the discovery response above MUST be returned if the + server supports resource discovery. The last three lines are only + included if the corresponding EST functions are implemented (see + Table 2). The Content-Formats in the response allow the client to + request one that is supported by the server. These are the values + that would be sent in the client request with an Accept Option. + + Discoverable port numbers can be returned in the response payload. + An example response payload for non-default CoAPS server port 61617 + follows below. Linefeeds are included only for readability. + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + ;rt="ace.est.crts"; + ct="62 281 287", + ;rt="ace.est.sen"; + ct="281 287", + ;rt="ace.est.sren"; + ct="281 287", + ;rt="ace.est.att"; + ct=285, + ;rt="ace.est.skg"; + ct=62, + ;rt="ace.est.skc"; + ct=62 + + The server MUST support the default /.well-known/est root resource. + + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. + + The server SHOULD support resource discovery when it supports non- + default URIs (like /est or /est/ArbitraryLabel) or ports. The client + SHOULD use resource discovery when it is unaware of the available + EST-coaps resources. + + Throughout this document, the example root resource of /est is used. + +4.2. Mandatory/Optional EST Functions + + This specification contains a set of required-to-implement functions, + optional functions, and not-specified functions. The unspecified + functions are deemed too expensive for low-resource devices in + payload and calculation times. + + Table 2 specifies the mandatory-to-implement or optional + implementation of the EST-coaps functions. Discovery of the + existence of optional functions is described in Section 4.1. + + +=================+==========================+ + | EST Functions | EST-coaps Implementation | + +=================+==========================+ + | /cacerts | MUST | + +-----------------+--------------------------+ + | /simpleenroll | MUST | + +-----------------+--------------------------+ + | /simplereenroll | MUST | + +-----------------+--------------------------+ + | /fullcmc | Not specified | + +-----------------+--------------------------+ + | /serverkeygen | OPTIONAL | + +-----------------+--------------------------+ + | /csrattrs | OPTIONAL | + +-----------------+--------------------------+ + + Table 2: List of EST-coaps Functions + +4.3. Payload Formats + + EST-coaps is designed for low-resource devices; hence, it does not + need to send Base64-encoded data. Simple binary is more efficient + (30% smaller payload for DER-encoded ASN.1) and well supported by + CoAP. Thus, the payload for a given media type follows the ASN.1 + structure of the media type and is transported in binary format. + + The Content-Format (HTTP Content-Type equivalent) of the CoAP message + determines which EST message is transported in the CoAP payload. The + media types specified in the HTTP Content-Type header field + (Section 3.2.4 of [RFC7030]) are specified by the Content-Format + Option (12) of CoAP. The combination of URI-Path and Content-Format + in EST-coaps MUST map to an allowed combination of URI and media type + in EST. The required Content-Formats for these requests and response + messages are defined in Section 8.1. The CoAP response codes are + defined in Section 4.5. + + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified below. + + The client uses a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] + + + Content-Format 286 is used in /sen, /sren, and /skg requests and 285 + in /att responses. + + A representation with Content-Format identifier 62 contains a + collection of representations along with their respective Content- + Format. The Content-Format identifies the media type application/ + multipart-core specified in [RFC8710]. For example, a collection, + containing two representations in response to an EST-coaps server- + side key generation /skg request, could include a private key in PKCS + #8 [RFC5958] with Content-Format identifier 284 (0x011C) and a single + certificate in a PKCS #7 container with Content-Format identifier 281 + (0x0119). Such a collection would look like + [284,h'0123456789abcdef', 281,h'fedcba9876543210'] in diagnostic + Concise Binary Object Representation (CBOR) notation. The + serialization of such CBOR content would be: + + 84 # array(4) + 19 011C # unsigned(284) + 48 # bytes(8) + 0123456789ABCDEF # "\x01#Eg\x89\xAB\xCD\xEF" + 19 0119 # unsigned(281) + 48 # bytes(8) + FEDCBA9876543210 # "\xFE\xDC\xBA\x98vT2\x10" + + Figure 2: Multipart /skg Response Serialization + + When the client makes an /skc request, the certificate returned with + the private key is a single X.509 certificate (not a PKCS #7 + container) with Content-Format identifier 287 (0x011F) instead of + 281. In cases where the private key is encrypted with Cryptographic + Message Syntax (CMS) (as explained in Section 4.8), the Content- + Format identifier is 280 (0x0118) instead of 284. The Content-Format + used in the response is summarized in Table 3. + + +==========+==================+==================+ + | Function | Response, Part 1 | Response, Part 2 | + +==========+==================+==================+ + | /skg | 284 | 281 | + +----------+------------------+------------------+ + | /skc | 280 | 287 | + +----------+------------------+------------------+ + + Table 3: Response Content-Formats for /skg and + /skc + + The key and certificate representations are DER-encoded ASN.1, in its + binary form. An example is shown in Appendix A.3. + + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. + +4.4. Message Bindings + + The general EST-coaps message characteristics are: + + * EST-coaps servers sometimes need to provide delayed responses, + which are preceded by an immediately returned empty ACK or an ACK + containing response code 5.03 as explained in Section 4.7. Thus, + it is RECOMMENDED for implementers to send EST-coaps requests in + Confirmable (CON) CoAP messages. + + * The CoAP Options used are Uri-Host, Uri-Path, Uri-Port, Content- + Format, Block1, Block2, and Accept. These CoAP Options are used + to communicate the HTTP fields specified in the EST REST messages. + The Uri-host and Uri-Port Options can be omitted from the CoAP + message sent on the wire. When omitted, they are logically + assumed to be the transport protocol destination address and port, + respectively. Explicit Uri-Host and Uri-Port Options are + typically used when an endpoint hosts multiple virtual servers and + uses the Options to route the requests accordingly. Other CoAP + Options should be handled in accordance with [RFC7252]. + + * EST URLs are HTTPS based (https://); in CoAP, these are assumed to + be translated to CoAPS (coaps://). + + Table 1 provides the mapping from the EST URI path to the EST-coaps + URI path. Appendix A includes some practical examples of EST + messages translated to CoAP. + +4.5. CoAP Response Codes + + Section 5.9 of [RFC7252] and Section 7 of [RFC8075] specify the + mapping of HTTP response codes to CoAP response codes. The success + code in response to an EST-coaps GET request (/crts, /att) is 2.05. + Similarly, 2.04 is used in successful response to EST-coaps POST + requests (/sen, /sren, /skg, /skc). + + EST makes use of HTTP 204 or 404 responses when a resource is not + available for the client. In EST-coaps, 2.04 is used in response to + a POST (/sen, /sren, /skg, /skc). 4.04 is used when the resource is + not available for the client. + + HTTP response code 202 with a Retry-After header field in [RFC7030] + has no equivalent in CoAP. HTTP 202 with Retry-After is used in EST + for delayed server responses. Section 4.7 specifies how EST-coaps + handles delayed messages with 5.03 responses with a Max-Age Option. + + Additionally, EST's HTTP 400, 401, 403, 404, and 503 status codes + have their equivalent CoAP 4.00, 4.01, 4.03, 4.04, and 5.03 response + codes in EST-coaps. + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). + + Table 4 summarizes the EST-coaps response codes. + + +=============+=========================+==========================+ + | Operation | EST-coaps Response Code | Description | + +=============+=========================+==========================+ + | /crts, /att | 2.05 | Success. Certs included | + | | | in the response payload. | + +-------------+-------------------------+--------------------------+ + | /crts | 4.06 | Accept Option cannot be | + | | | satisfied (multi-TA). | + +-------------+-------------------------+--------------------------+ + | | 4.xx / 5.xx | Failure. | + +-------------+-------------------------+--------------------------+ + | /sen, /skg, | 2.04 | Success. Cert included | + | /sren, /skc | | in the response payload. | + +-------------+-------------------------+--------------------------+ + | | 5.03 | Retry in Max-Age Option | + | | | time. | + +-------------+-------------------------+--------------------------+ + | | 4.xx / 5.xx | Failure. | + +-------------+-------------------------+--------------------------+ + + Table 4: EST-coaps Response Codes + +4.6. Message Fragmentation + + DTLS defines fragmentation only for the handshake and not for secure + data exchange (DTLS records). [RFC6347] states that to avoid using + IP fragmentation, which involves error-prone datagram reconstitution, + invokers of the DTLS record layer should size DTLS records so that + they fit within any Path MTU estimates obtained from the record + layer. In addition, invokers residing on 6LoWPAN (IPv6 over Low- + Power Wireless Personal Area Networks) over IEEE 802.15.4 networks + [IEEE802.15.4] are recommended to size CoAP messages such that each + DTLS record will fit within one or two IEEE 802.15.4 frames. + + That is not always possible in EST-coaps. Even though ECC + certificates are small in size, they can vary greatly based on + signature algorithms, key sizes, and Object Identifier (OID) fields + used. For 256-bit curves, common Elliptic Curve Digital Signature + Algorithm (ECDSA) cert sizes are 500-1000 bytes, which could + fluctuate further based on the algorithms, OIDs, Subject Alternative + Names (SANs), and cert fields. For 384-bit curves, ECDSA + certificates increase in size and can sometimes reach 1.5KB. + Additionally, there are times when the EST cacerts response from the + server can include multiple certificates that amount to large + payloads. Section 4.6 of [RFC7252] (CoAP) describes the possible + payload sizes: "if nothing is known about the size of the headers, + good upper bounds are 1152 bytes for the message size and 1024 bytes + for the payload size". Section 4.6 of [RFC7252] also suggests that + IPv4 implementations may want to limit themselves to more + conservative IPv4 datagram sizes such as 576 bytes. Even with ECC, + EST-coaps messages can still exceed MTU sizes on the Internet or + 6LoWPAN [RFC4919] (Section 2 of [RFC7959]). EST-coaps needs to be + able to fragment messages into multiple DTLS datagrams. + + To perform fragmentation in CoAP, [RFC7959] specifies the Block1 + Option for fragmentation of the request payload and the Block2 Option + for fragmentation of the return payload of a CoAP flow. As explained + in Section 1 of [RFC7959], block-wise transfers should be used in + Confirmable CoAP messages to avoid the exacerbation of lost blocks. + EST-coaps servers MUST implement Block1 and Block2. EST-coaps + clients MUST implement Block2. EST-coaps clients MUST implement + Block1 only if they are expecting to send EST-coaps requests with a + packet size that exceeds the path MTU. + + [RFC7959] also defines Size1 and Size2 Options to provide size + information about the resource representation in a request and + response. The EST-coaps client and server MAY support Size1 and + Size2 Options. + + Examples of fragmented EST-coaps messages are shown in Appendix B. + +4.7. Delayed Responses + + Server responses can sometimes be delayed. According to + Section 5.2.2 of [RFC7252], a slow server can acknowledge the request + and respond later with the requested resource representation. In + particular, a slow server can respond to an EST-coaps enrollment + request with an empty ACK with code 0.00 before sending the + certificate to the client after a short delay. If the certificate + response is large, the server will need more than one Block2 block to + transfer it. + + This situation is shown in Figure 3. The client sends an enrollment + request that uses N1+1 Block1 blocks. The server uses an empty 0.00 + ACK to announce the delayed response, which is provided later with + 2.04 messages containing N2+1 Block2 Options. The first 2.04 is a + Confirmable message that is acknowledged by the client. Onwards, the + client acknowledges all subsequent Block2 blocks. The notation of + Figure 3 is explained in Appendix B.1. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + <-- (0.00 empty ACK) + | + ... Short delay before the certificate is ready ... + | + <-- (CON) (1:N1/0/256)(2:0/1/256)(2.04 Changed) + {Cert resp (frag# 1)} + (ACK) --> + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256) (2.04 Changed) {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) {Cert resp (frag# N2+1)} + + Figure 3: EST-coaps Enrollment with Short Wait + + If the server is very slow (for example, manual intervention is + required, which would take minutes), it SHOULD respond with an ACK + containing response code 5.03 (Service unavailable) and a Max-Age + Option to indicate the time the client SHOULD wait before sending + another request to obtain the content. After a delay of Max-Age, the + client SHOULD resend the identical CSR to the server. As long as the + server continues to respond with response code 5.03 (Service + Unavailable) with a Max-Age Option, the client will continue to delay + for Max-Age and then resend the enrollment request until the server + responds with the certificate or the client abandons the request due + to policy or other reasons. + + To demonstrate this scenario, Figure 4 shows a client sending an + enrollment request that uses N1+1 Block1 blocks to send the CSR to + the server. The server needs N2+1 Block2 blocks to respond but also + needs to take a long delay (minutes) to provide the response. + Consequently, the server uses a 5.03 ACK response with a Max-Age + Option. The client waits for a period of Max-Age as many times as it + receives the same 5.03 response and retransmits the enrollment + request until it receives a certificate in a fragmented 2.04 + response. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + <-- (ACK) (1:N1/0/256) (5.03 Service Unavailable) (Max-Age) + | + | + ... Client tries again after Max-Age with identical payload ... + | + | + POST [2001:db8::2:1]:61616/est/sen(CON)(1:0/1/256) + {CSR (frag# 1)}--> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + | + ... Immediate response when certificate is ready ... + | + <-- (ACK) (1:N1/0/256) (2:0/1/256) (2.04 Changed) + {Cert resp (frag# 1)} + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256) (2.04 Changed) {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) {Cert resp (frag# N2+1)} + + Figure 4: EST-coaps Enrollment with Long Wait + +4.8. Server-Side Key Generation + + Private keys can be generated on the server to support scenarios + where server-side key generation is needed. Such scenarios include + those where it is considered more secure to generate the long-lived, + random private key that identifies the client at the server, or where + the resources spent to generate a random private key at the client + are considered scarce, or where the security policy requires that the + certificate public and corresponding private keys are centrally + generated and controlled. As always, it is necessary to use proper + random numbers in various protocols such as (D)TLS (Section 9.1). + + When requesting server-side key generation, the client asks for the + server or proxy to generate the private key and the certificate, + which are transferred back to the client in the server-side key + generation response. In all respects, the server treats the CSR as + it would treat any enroll or re-enroll CSR; the only distinction here + is that the server MUST ignore the public key values and signature in + the CSR. These are included in the request only to allow reuse of + existing codebases for generating and parsing such requests. + + The client /skg request is for a certificate in a PKCS #7 container + and private key in two application/multipart-core elements. + Respectively, an /skc request is for a single application/pkix-cert + certificate and a private key. The private key Content-Format + requested by the client is indicated in the PKCS #10 CSR request. If + the request contains SMIMECapabilities and DecryptKeyIdentifier or + AsymmetricDecryptKeyIdentifier, the client is expecting Content- + Format 280 for the private key. Then, this private key is encrypted + symmetrically or asymmetrically per [RFC7030]. The symmetric key or + the asymmetric keypair establishment method is out of scope of this + specification. An /skg or /skc request with a CSR without + SMIMECapabilities expects an application/multipart-core with an + unencrypted PKCS #8 private key with Content-Format 284. + + The EST-coaps server-side key generation response is returned with + Content-Format application/multipart-core [RFC8710] containing a CBOR + array with four items (Section 4.3). The two representations (each + consisting of two CBOR array items) do not have to be in a particular + order since each representation is preceded by its Content-Format ID. + Depending on the request, the private key can be in unprotected PKCS + #8 format [RFC5958] (Content-Format 284) or protected inside of CMS + SignedData (Content-Format 280). The SignedData, placed in the + outermost container, is signed by the party that generated the + private key, which may be the EST server or the EST CA. SignedData + placed within the Enveloped Data does not need additional signing as + explained in Section 4.4.2 of [RFC7030]. In summary, the + symmetrically encrypted key is included in the encryptedKey attribute + in a KEKRecipientInfo structure. In the case where the asymmetric + encryption key is suitable for transport key operations, the + generated private key is encrypted with a symmetric key. The + symmetric key itself is encrypted by the client-defined (in the CSR) + asymmetric public key and is carried in an encryptedKey attribute in + a KeyTransRecipientInfo structure. Finally, if the asymmetric + encryption key is suitable for key agreement, the generated private + key is encrypted with a symmetric key. The symmetric key itself is + encrypted by the client defined (in the CSR) asymmetric public key + and is carried in a recipientEncryptedKeys attribute in a + KeyAgreeRecipientInfo. + + [RFC7030] recommends the use of additional encryption of the returned + private key. For the context of this specification, clients and + servers that choose to support server-side key generation MUST + support unprotected (PKCS #8) private keys (Content-Format 284). + Symmetric or asymmetric encryption of the private key (CMS + EnvelopedData, Content-Format 280) SHOULD be supported for + deployments where end-to-end encryption is needed between the client + and a server. Such cases could include architectures where an entity + between the client and the CA terminates the DTLS connection + (Registrar in Figure 5). Though [RFC7030] strongly recommends that + clients request the use of CMS encryption on top of the TLS channel's + protection, this document does not make such a recommendation; CMS + encryption can still be used when mandated by the use case. + +4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. + +4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + +4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. + +5. HTTPS-CoAPS Registrar + + In real-world deployments, the EST server will not always reside + within the CoAP boundary. The EST server can exist outside the + constrained network, in which case it will support TLS/HTTP instead + of CoAPS. In such environments, EST-coaps is used by the client + within the CoAP boundary and TLS is used to transport the EST + messages outside the CoAP boundary. A Registrar at the edge is + required to operate between the CoAP environment and the external + HTTP network as shown in Figure 5. + + Constrained Network + .------. .----------------------------. + | CA | |.--------------------------.| + '------' || || + | || || + .------. HTTP .------------------. CoAPS .-----------. || + | EST |<------->|EST-coaps-to-HTTPS|<------->| EST Client| || + |Server|over TLS | Registrar | '-----------' || + '------' '------------------' || + || || + |'--------------------------'| + '----------------------------' + + Figure 5: EST-coaps-to-HTTPS Registrar at the CoAP Boundary + + The EST-coaps-to-HTTPS Registrar MUST terminate EST-coaps downstream + and initiate EST connections over TLS upstream. The Registrar MUST + authenticate and optionally authorize the client requests while it + MUST be authenticated by the EST server or CA. The trust + relationship between the Registrar and the EST server SHOULD be pre- + established for the Registrar to proxy these connections on behalf of + various clients. + + When enforcing Proof-of-Possession (POP) linking, the tls-unique or + tls-exporter value of the session for DTLS 1.2 and DTLS 1.3, + respectively, is used to prove that the private key corresponding to + the public key is in the possession of the client and was used to + establish the connection as explained in Section 3. The POP linking + information is lost between the EST-coaps client and the EST server + when a Registrar is present. The EST server becomes aware of the + presence of a Registrar from its TLS client certificate that includes + the id-kp-cmcRA extended key usage (EKU) extension [RFC6402]. As + explained in Section 3.7 of [RFC7030], the "EST server SHOULD apply + authorization policy consistent with an RA client ... the EST server + could be configured to accept POP linking information that does not + match the current TLS session because the authenticated EST client RA + has verified this information when acting as an EST server". + + Table 1 contains the URI mappings between EST-coaps and EST that the + Registrar MUST adhere to. Section 4.5 of this specification and + Section 7 of [RFC8075] define the mappings between EST-coaps and HTTP + response codes that determine how the Registrar MUST translate CoAP + response codes from/to HTTP status codes. The mapping from CoAP + Content-Format to HTTP Content-Type is defined in Section 8.1. + Additionally, a conversion from CBOR major type 2 to Base64 encoding + MUST take place at the Registrar. If CMS end-to-end encryption is + employed for the private key, the encrypted CMS EnvelopedData blob + MUST be converted at the Registrar to binary CBOR type 2 downstream + to the client. This is a format conversion that does not require + decryption of the CMS EnvelopedData. + + A deviation from the mappings in Table 1 could take place if clients + that leverage server-side key generation preferred for the enrolled + keys to be generated by the Registrar in the case the CA does not + support server-side key generation. Such a Registrar is responsible + for generating a new CSR signed by a new key that will be returned to + the client along with the certificate from the CA. In these cases, + the Registrar MUST use random number generation with proper entropy. + + Due to fragmentation of large messages into blocks, an EST-coaps-to- + HTTP Registrar MUST reassemble the blocks before translating the + binary content to Base64 and consecutively relay the message + upstream. + + The EST-coaps-to-HTTP Registrar MUST support resource discovery + according to the rules in Section 4.1. + +6. Parameters + + This section addresses transmission parameters described in Sections + 4.7 and 4.8 of [RFC7252]. EST does not impose any unique values on + the CoAP parameters in [RFC7252], but the setting of the CoAP + parameter values may have consequence for the setting of the EST + parameter values. + + Implementations should follow the default CoAP configuration + parameters [RFC7252]. However, depending on the implementation + scenario, retransmissions and timeouts can also occur on other + networking layers, governed by other configuration parameters. When + a change in a server parameter has taken place, the parameter values + in the communicating endpoints MUST be adjusted as necessary. + Examples of how parameters could be adjusted include higher-layer + congestion protocols, provisioning agents, and configurations + included in firmware updates. + + Some further comments about some specific parameters, mainly from + Table 2 in [RFC7252], include the following: + + NSTART: A parameter that controls the number of simultaneous + outstanding interactions that a client maintains to a given + server. An EST-coaps client is expected to control at most one + interaction with a given server, which is the default NSTART value + defined in [RFC7252]. + + DEFAULT_LEISURE: A setting that is only relevant in multicast + scenarios and is outside the scope of EST-coaps. + + PROBING_RATE: A parameter that specifies the rate of resending Non- + confirmable messages. In the rare situations that Non-confirmable + messages are used, the default PROBING_RATE value defined in + [RFC7252] applies. + + Finally, the Table 3 parameters in [RFC7252] are mainly derived from + Table 2. Directly changing parameters on one table would affect + parameters on the other. + +7. Deployment Limitations + + Although EST-coaps paves the way for the utilization of EST by + constrained devices in constrained networks, some classes of devices + [RFC7228] will not have enough resources to handle the payloads that + come with EST-coaps. The specification of EST-coaps is intended to + ensure that EST works for networks of constrained devices that choose + to limit their communications stack to DTLS/CoAP. It is up to the + network designer to decide which devices execute the EST protocol and + which do not. + +8. IANA Considerations + +8.1. Content-Formats Registry + + IANA has registered the following Content-Formats given in Table 5 in + the "CoAP Content-Formats" subregistry within the "CoRE Parameters" + registry [CORE-PARAMS]. These have been registered in the IETF + Review or IESG Approval range (256-9999). + + +=================================+=====+====================+ + | Media Type | ID | Reference | + +=================================+=====+====================+ + | application/pkcs7-mime; smime- | 280 | [RFC7030] | + | type=server-generated-key | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkcs7-mime; smime- | 281 | [RFC8551] RFC 9148 | + | type=certs-only | | | + +---------------------------------+-----+--------------------+ + | application/pkcs8 | 284 | [RFC5958] | + | | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/csrattrs | 285 | [RFC7030] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkcs10 | 286 | [RFC5967] | + | | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkix-cert | 287 | [RFC2585] RFC 9148 | + +---------------------------------+-----+--------------------+ + + Table 5: New CoAP Content-Formats + +8.2. Resource Type Registry + + IANA has registered the following Resource Type (rt=) Link Target + Attributes given in Table 6 in the "Resource Type (rt=) Link Target + Attribute Values" subregistry under the "Constrained RESTful + Environments (CoRE) Parameters" registry. + + +==============+===================================+===========+ + | Value | Description | Reference | + +==============+===================================+===========+ + | ace.est | Base resource of all EST-coaps | This doc | + | | resources | | + +--------------+-----------------------------------+-----------+ + | ace.est.crts | This resource depicts the support | RFC 9148 | + | | of EST GET cacerts. | | + +--------------+-----------------------------------+-----------+ + | ace.est.sen | This resource depicts the support | RFC 9148 | + | | of EST simple enroll. | | + +--------------+-----------------------------------+-----------+ + | ace.est.sren | This resource depicts the support | RFC 9148 | + | | of EST simple reenroll. | | + +--------------+-----------------------------------+-----------+ + | ace.est.att | This resource depicts the support | RFC 9148 | + | | of EST GET CSR attributes. | | + +--------------+-----------------------------------+-----------+ + | ace.est.skg | This resource depicts the support | RFC 9148 | + | | of EST server-side key generation | | + | | with the returned certificate in | | + | | a PKCS #7 container. | | + +--------------+-----------------------------------+-----------+ + | ace.est.skc | This resource depicts the support | RFC 9148 | + | | of EST server-side key generation | | + | | with the returned certificate in | | + | | application/pkix-cert format. | | + +--------------+-----------------------------------+-----------+ + + Table 6: New Resource Type (rt=) Link Target Attributes + +8.3. Well-Known URIs Registry + + IANA has added an additional reference to the est URI in the "Well- + Known URIs" registry: + + URI Suffix: est + + Change Controller: IETF + + References: [RFC7030] RFC 9148 + + Status: permanent + + Related Information: + + Date Registered: 2013-08-16 + + Date Modified: 2020-04-29 + +9. Security Considerations + +9.1. EST Server Considerations + + The security considerations in Section 6 of [RFC7030] are only + partially valid for the purposes of this document. As HTTP Basic + Authentication is not supported, the considerations expressed for + using passwords do not apply. The other portions of the security + considerations in [RFC7030] continue to apply. + + Modern security protocols require random numbers to be available + during the protocol run, for example, for nonces and ephemeral (EC) + Diffie-Hellman key generation. This capability to generate random + numbers is also needed when the constrained device generates the + private key (that corresponds to the public key enrolled in the CSR). + When server-side key generation is used, the constrained device + depends on the server to generate the private key randomly, but it + still needs locally generated random numbers for use in security + protocols, as explained in Section 12 of [RFC7925]. Additionally, + the transport of keys generated at the server is inherently risky. + For those deploying server-side key generation, analysis SHOULD be + done to establish whether server-side key generation increases or + decreases the probability of digital identity theft. + + It is important to note that, as pointed out in [PsQs], sources + contributing to the randomness pool used to generate random numbers + on laptops or desktop PCs, such as mouse movement, timing of + keystrokes, or air turbulence on the movement of hard drive heads, + are not available on many constrained devices. Other sources have to + be used or dedicated hardware has to be added. Selecting hardware + for an IoT device that is capable of producing high-quality random + numbers is therefore important [RSA-FACT]. + + As discussed in Section 6 of [RFC7030], it is + + | RECOMMENDED that the Implicit Trust Anchor database used for EST + | server authentication be carefully managed to reduce the chance of + | a third-party CA with poor certification practices from being + | trusted. Disabling the Implicit Trust Anchor database after + | successfully receiving the Distribution of CA certificates + | response ([RFC7030], Section 6) limits any vulnerability to the + | first TLS exchange. + + Alternatively, in a case where a /sen request immediately follows a + /crts, a client MAY choose to keep the connection authenticated by + the Implicit TA open for efficiency reasons (Section 3). A client + that interleaves EST-coaps /crts request with other requests in the + same DTLS connection SHOULD revalidate the server certificate chain + against the updated Explicit TA from the /crts response before + proceeding with the subsequent requests. If the server certificate + chain does not authenticate against the database, the client SHOULD + close the connection without completing the rest of the requests. + The updated Explicit TA MUST continue to be used in new DTLS + connections. + + In cases where the Initial Device Identifier (IDevID) used to + authenticate the client is expired, the server MAY still authenticate + the client because IDevIDs are expected to live as long as the device + itself (Section 3). In such occasions, checking the certificate + revocation status or authorizing the client using another method is + important for the server to raise its confidence that the client can + be trusted. + + In accordance with [RFC7030], TLS cipher suites that include + "_EXPORT_" and "_DES_" in their names MUST NOT be used. More + recommendations for secure use of TLS and DTLS are included in + [BCP195]. + + As described in Certificate Management over CMS (CMC), Section 6.7 of + [RFC5272], "For keys that can be used as signature keys, signing the + certification request with the private key serves as a POP on that + key pair". In (D)TLS 1.2, the inclusion of tls-unique in the + certificate request links the proof-of-possession to the (D)TLS + proof-of-identity. This implies but does not prove that only the + authenticated client currently has access to the private key. + + What's more, CMC POP linking uses tls-unique as it is defined in + [RFC5929]. The 3SHAKE attack [TRIPLESHAKE] poses a risk by allowing + an on-path active attacker to leverage session resumption and + renegotiation to inject itself between a client and server even when + channel binding is in use. Implementers should use the Extended + Master Secret Extension in DTLS [RFC7627] to prevent such attacks. + In the context of this specification, an attacker could invalidate + the purpose of the POP linking challengePassword in the client + request by resuming an EST-coaps connection. Even though the + practical risk of such an attack to EST-coaps is not devastating, we + would rather use a more secure channel-binding mechanism. In this + specification, we still depend on the tls-unique mechanism defined in + [RFC5929] for DTLS 1.2 because a 3SHAKE attack does not expose + messages exchanged with EST-coaps. But for DTLS 1.3, + [TLS13-CHANNEL-BINDINGS] is used instead to derive a 32-byte tls- + exporter binding in place of the tls-unique value in the CSR. That + would alleviate the risks from the 3SHAKE attack [TRIPLESHAKE]. + + Interpreters of ASN.1 structures should be aware of the use of + invalid ASN.1 length fields and should take appropriate measures to + guard against buffer overflows, stack overruns in particular, and + malicious content in general. + +9.2. HTTPS-CoAPS Registrar Considerations + + The Registrar proposed in Section 5 must be deployed with care and + only when direct client-server connections are not possible. When + POP linking is used, the Registrar terminating the DTLS connection + establishes a new TLS connection with the upstream CA. Thus, it is + impossible for POP linking to be enforced end to end for the EST + transaction. The EST server could be configured to accept POP + linking information that does not match the current TLS session + because the authenticated EST Registrar is assumed to have verified + POP linking downstream to the client. + + The introduction of an EST-coaps-to-HTTP Registrar assumes the client + can authenticate the Registrar using its implicit or explicit TA + database. It also assumes the Registrar has a trust relationship + with the upstream EST server in order to act on behalf of the + clients. When a client uses the Implicit TA database for certificate + validation, it SHOULD confirm if the server is acting as an RA by the + presence of the id-kp-cmcRA EKU [RFC6402] in the server certificate. + + In a server-side key generation case, if no end-to-end encryption is + used, the Registrar may be able see the private key as it acts as a + man in the middle. Thus, the client puts its trust on the Registrar + not exposing the private key. + + Clients that leverage server-side key generation without end-to-end + encryption of the private key (Section 4.8) have no knowledge as to + whether the Registrar will be generating the private key and + enrolling the certificates with the CA or if the CA will be + responsible for generating the key. In such cases, the existence of + a Registrar requires the client to put its trust on the Registrar + when it is generating the private key. + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC2585] Housley, R. and P. Hoffman, "Internet X.509 Public Key + Infrastructure Operational Protocols: FTP and HTTP", + RFC 2585, DOI 10.17487/RFC2585, May 1999, + . + + [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security + (TLS) Protocol Version 1.2", RFC 5246, + DOI 10.17487/RFC5246, August 2008, + . + + [RFC5958] Turner, S., "Asymmetric Key Packages", RFC 5958, + DOI 10.17487/RFC5958, August 2010, + . + + [RFC5967] Turner, S., "The application/pkcs10 Media Type", RFC 5967, + DOI 10.17487/RFC5967, August 2010, + . + + [RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer + Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347, + January 2012, . + + [RFC6690] Shelby, Z., "Constrained RESTful Environments (CoRE) Link + Format", RFC 6690, DOI 10.17487/RFC6690, August 2012, + . + + [RFC7030] Pritikin, M., Ed., Yee, P., Ed., and D. Harkins, Ed., + "Enrollment over Secure Transport", RFC 7030, + DOI 10.17487/RFC7030, October 2013, + . + + [RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained + Application Protocol (CoAP)", RFC 7252, + DOI 10.17487/RFC7252, June 2014, + . + + [RFC7925] Tschofenig, H., Ed. and T. Fossati, "Transport Layer + Security (TLS) / Datagram Transport Layer Security (DTLS) + Profiles for the Internet of Things", RFC 7925, + DOI 10.17487/RFC7925, July 2016, + . + + [RFC7959] Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in + the Constrained Application Protocol (CoAP)", RFC 7959, + DOI 10.17487/RFC7959, August 2016, + . + + [RFC8075] Castellani, A., Loreto, S., Rahman, A., Fossati, T., and + E. Dijk, "Guidelines for Mapping Implementations: HTTP to + the Constrained Application Protocol (CoAP)", RFC 8075, + DOI 10.17487/RFC8075, February 2017, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + + [RFC8422] Nir, Y., Josefsson, S., and M. Pegourie-Gonnard, "Elliptic + Curve Cryptography (ECC) Cipher Suites for Transport Layer + Security (TLS) Versions 1.2 and Earlier", RFC 8422, + DOI 10.17487/RFC8422, August 2018, + . + + [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol + Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, + . + + [RFC8551] Schaad, J., Ramsdell, B., and S. Turner, "Secure/ + Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 + Message Specification", RFC 8551, DOI 10.17487/RFC8551, + April 2019, . + + [RFC8710] Fossati, T., Hartke, K., and C. Bormann, "Multipart + Content-Format for the Constrained Application Protocol + (CoAP)", RFC 8710, DOI 10.17487/RFC8710, February 2020, + . + + [RFC9147] Rescorla, E., Tschofenig, H., and N. Modadugu, "The + Datagram Transport Layer Security (DTLS) Protocol Version + 1.3", RFC 9147, DOI 10.17487/RFC9147, April 2022, + . + +10.2. Informative References + + [BCP195] Sheffer, Y., Holz, R., and P. Saint-Andre, + "Recommendations for Secure Use of Transport Layer + Security (TLS) and Datagram Transport Layer Security + (DTLS)", BCP 195, RFC 7525, May 2015. + + + + [CORE-PARAMS] + IANA, "Constrained RESTful Environments (CoRE) + Parameters", + . + + [IEEE802.15.4] + IEEE, "IEEE 802.15.4-2020 - IEEE Standard for Low-Rate + Wireless Networks", May 2020. + + [IEEE802.1AR] + IEEE, "IEEE Standard for Local and metropolitan area + networks - Secure Device Identity", December 2009. + + [PKI-GUIDE] + Moskowitz, R., Birkholz, H., Xia, L., and M. Richardson, + "Guide for building an ECC pki", Work in Progress, + Internet-Draft, draft-moskowitz-ecdsa-pki-10, 31 January + 2021, . + + [PsQs] Heninger, N., Durumeric, Z., Wustrow, E., and J. Alex + Halderman, "Mining Your Ps and Qs: Detection of Widespread + Weak Keys in Network Devices", USENIX Security Symposium + 2012, ISBN 978-931971-95-9, August 2012. + + [RFC4919] Kushalnagar, N., Montenegro, G., and C. Schumacher, "IPv6 + over Low-Power Wireless Personal Area Networks (6LoWPANs): + Overview, Assumptions, Problem Statement, and Goals", + RFC 4919, DOI 10.17487/RFC4919, August 2007, + . + + [RFC5272] Schaad, J. and M. Myers, "Certificate Management over CMS + (CMC)", RFC 5272, DOI 10.17487/RFC5272, June 2008, + . + + [RFC5929] Altman, J., Williams, N., and L. Zhu, "Channel Bindings + for TLS", RFC 5929, DOI 10.17487/RFC5929, July 2010, + . + + [RFC6402] Schaad, J., "Certificate Management over CMS (CMC) + Updates", RFC 6402, DOI 10.17487/RFC6402, November 2011, + . + + [RFC7228] Bormann, C., Ersue, M., and A. Keranen, "Terminology for + Constrained-Node Networks", RFC 7228, + DOI 10.17487/RFC7228, May 2014, + . + + [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer + Protocol (HTTP/1.1): Message Syntax and Routing", + RFC 7230, DOI 10.17487/RFC7230, June 2014, + . + + [RFC7251] McGrew, D., Bailey, D., Campagna, M., and R. Dugal, "AES- + CCM Elliptic Curve Cryptography (ECC) Cipher Suites for + TLS", RFC 7251, DOI 10.17487/RFC7251, June 2014, + . + + [RFC7299] Housley, R., "Object Identifier Registry for the PKIX + Working Group", RFC 7299, DOI 10.17487/RFC7299, July 2014, + . + + [RFC7627] Bhargavan, K., Ed., Delignat-Lavaud, A., Pironti, A., + Langley, A., and M. Ray, "Transport Layer Security (TLS) + Session Hash and Extended Master Secret Extension", + RFC 7627, DOI 10.17487/RFC7627, September 2015, + . + + [RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves + for Security", RFC 7748, DOI 10.17487/RFC7748, January + 2016, . + + [RFC9146] Rescorla, E., Ed., Tschofenig, H., Ed., Fossati, T., and + A. Kraus, "Connection Identifier for DTLS 1.2", RFC 9146, + DOI 10.17487/RFC9146, March 2022, + . + + [RSA-FACT] Bernstein, D., Chang, Y., Cheng, C., Chou, L., Heninger, + N., Lange, T., and N. Someren, "Factoring RSA keys from + certified smart cards: Coppersmith in the wild", Advances + in Cryptology - ASIACRYPT 2013, August 2013. + + [TLS13-CHANNEL-BINDINGS] + Whited, S., "Channel Bindings for TLS 1.3", Work in + Progress, Internet-Draft, draft-ietf-kitten-tls-channel- + bindings-for-tls13-15, 4 March 2022, + . + + [TRIPLESHAKE] + Bhargavan, B., Delignat-Lavaud, A., Fournet, C., Pironti, + A., and P. Strub, "Triple Handshakes and Cookie Cutters: + Breaking and Fixing Authentication over TLS", + ISBN 978-1-4799-4686-0, DOI 10.1109/SP.2014.14, May 2014, + . + +Appendix A. EST Messages to EST-coaps + + This section shows similar examples to the ones presented in + Appendix A of [RFC7030]. The payloads in the examples are the hex- + encoded binary, generated with 'xxd -p', of the PKI certificates + created following [PKI-GUIDE]. Hex is used for visualization + purposes because a binary representation cannot be rendered well in + text. The hexadecimal representations would not be transported in + hex, but in binary. The payloads are shown unencrypted. In + practice, the message content would be transferred over an encrypted + DTLS channel. + + The certificate responses included in the examples contain Content- + Format 281 (application/pkcs7). If the client had requested Content- + Format 287 (application/pkix-cert), the server would respond with a + single DER binary certificate. That certificate would be in a + multipart-core container specifically in the case of a response to a + /est/skc query. + + These examples assume a short resource path of "/est". Even though + omitted from the examples for brevity, before making the EST-coaps + requests, a client would learn about the server supported EST-coaps + resources with a GET request for /.well-known/core?rt=ace.est* as + explained in Section 4.1. + + The corresponding CoAP headers are only shown in Appendix A.1. + Creating CoAP headers is assumed to be generally understood. + + The message content is presented in plain text in Appendix C. + +A.1. cacerts + + In EST-coaps, a cacerts message can be the following: + + GET example.com:9085/est/crts + (Accept: 281) + + The corresponding CoAP header fields are shown below. The use of + block and DTLS are shown in Appendix B. + + Ver = 1 + T = 0 (CON) + Code = 0x01 (0.01 is GET) + Token = 0x9a (client generated) + Options + Option (Uri-Host) + Option Delta = 0x3 (option# 3) + Option Length = 0xB + Option Value = "example.com" + Option (Uri-Port) + Option Delta = 0x4 (option# 3+4=7) + Option Length = 0x2 + Option Value = 9085 + Option (Uri-Path) + Option Delta = 0x4 (option# 7+4=11) + Option Length = 0x3 + Option Value = "est" + Option (Uri-Path) + Option Delta = 0x0 (option# 11+0=11) + Option Length = 0x4 + Option Value = "crts" + Option (Accept) + Option Delta = 0x6 (option# 11+6=17) + Option Length = 0x2 + Option Value = 281 + Payload = [Empty] + + As specified in Section 5.10.1 of [RFC7252], the Uri-Host and Uri- + Port Options can be omitted if they coincide with the transport + protocol destination address and port, respectively. + + A 2.05 Content response with a cert in EST-coaps will then be the + following: + + 2.05 Content (Content-Format: 281) + {payload with certificate in binary format} + + With the following CoAP fields: + + Ver = 1 + T = 2 (ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option (Content-Format) + Option Delta = 0xC (option# 12) + Option Length = 0x2 + Option Value = 281 + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 3082027a06092a864886f70d010702a082026b308202670201013100300b + 06092a864886f70d010701a082024d30820249308201efa0030201020208 + 0b8bb0fe604f6a1e300a06082a8648ce3d0403023067310b300906035504 + 0613025553310b300906035504080c024341310b300906035504070c024c + 4131143012060355040a0c0b4578616d706c6520496e6331163014060355 + 040b0c0d63657274696669636174696f6e3110300e06035504030c07526f + 6f74204341301e170d3139303133313131323730335a170d333930313236 + 3131323730335a3067310b3009060355040613025553310b300906035504 + 080c024341310b300906035504070c024c4131143012060355040a0c0b45 + 78616d706c6520496e6331163014060355040b0c0d636572746966696361 + 74696f6e3110300e06035504030c07526f6f742043413059301306072a86 + 48ce3d020106082a8648ce3d030107034200040c1b1e82ba8cc72680973f + 97edb8a0c72ab0d405f05d4fe29b997a14ccce89008313d09666b6ce375c + 595fcc8e37f8e4354497011be90e56794bd91ad951ab45a3818430818130 + 1d0603551d0e041604141df1208944d77b5f1d9dcb51ee244a523f3ef5de + 301f0603551d230418301680141df1208944d77b5f1d9dcb51ee244a523f + 3ef5de300f0603551d130101ff040530030101ff300e0603551d0f0101ff + 040403020106301e0603551d110417301581136365727469667940657861 + 6d706c652e636f6d300a06082a8648ce3d040302034800304502202b891d + d411d07a6d6f621947635ba4c43165296b3f633726f02e51ecf464bd4002 + 2100b4be8a80d08675f041fbc719acf3b39dedc85dc92b3035868cb2daa8 + f05db196a1003100 + + The payload is shown in plain text in Appendix C.1. + +A.2. enroll / reenroll + + During the (re-)enroll exchange, the EST-coaps client uses a CSR + (Content-Format 286) request in the POST request payload. The Accept + Option tells the server that the client is expecting Content-Format + 281 (PKCS #7) in the response. As shown in Appendix C.2, the CSR + contains a challengePassword, which is used for POP linking + (Section 3). + + POST [2001:db8::2:321]:61616/est/sen + (Token: 0x45) + (Accept: 281) + (Content-Format: 286) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3082018b30820131020100305c310b3009060355040613025553310b3009 + 06035504080c024341310b300906035504070c024c413114301206035504 + 0a0c0b6578616d706c6520496e63310c300a060355040b0c03496f54310f + 300d060355040513065774313233343059301306072a8648ce3d02010608 + 2a8648ce3d03010703420004c8b421f11c25e47e3ac57123bf2d9fdc494f + 028bc351cc80c03f150bf50cff958d75419d81a6a245dffae790be95cf75 + f602f9152618f816a2b23b5638e59fd9a073303406092a864886f70d0109 + 0731270c2576437630292a264a4b4a3bc3a2c280c2992f3e3c2e2c3d6b6e + 7634332323403d204e787e60303b06092a864886f70d01090e312e302c30 + 2a0603551d1104233021a01f06082b06010505070804a013301106092b06 + 010401b43b0a01040401020304300a06082a8648ce3d0403020348003045 + 02210092563a546463bd9ecff170d0fd1f2ef0d3d012160e5ee90cffedab + ec9b9a38920220179f10a3436109051abad17590a09bc87c4dce5453a6fc + 1135a1e84eed754377 + + After verification of the CSR by the server, a 2.04 Changed response + with the issued certificate will be returned to the client. + + 2.04 Changed + (Token: 0x45) + (Content-Format: 281) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3082026e06092a864886f70d010702a082025f3082025b0201013100300b + 06092a864886f70d010701a08202413082023d308201e2a0030201020208 + 7e7661d7b54e4632300a06082a8648ce3d040302305d310b300906035504 + 0613025553310b300906035504080c02434131143012060355040a0c0b45 + 78616d706c6520496e6331163014060355040b0c0d636572746966696361 + 74696f6e3113301106035504030c0a3830322e3141522043413020170d31 + 39303133313131323931365a180f39393939313233313233353935395a30 + 5c310b3009060355040613025553310b300906035504080c024341310b30 + 0906035504070c024c4131143012060355040a0c0b6578616d706c652049 + 6e63310c300a060355040b0c03496f54310f300d06035504051306577431 + 3233343059301306072a8648ce3d020106082a8648ce3d03010703420004 + c8b421f11c25e47e3ac57123bf2d9fdc494f028bc351cc80c03f150bf50c + ff958d75419d81a6a245dffae790be95cf75f602f9152618f816a2b23b56 + 38e59fd9a3818a30818730090603551d1304023000301d0603551d0e0416 + 041496600d8716bf7fd0e752d0ac760777ad665d02a0301f0603551d2304 + 183016801468d16551f951bfc82a431d0d9f08bc2d205b1160300e060355 + 1d0f0101ff0404030205a0302a0603551d1104233021a01f06082b060105 + 05070804a013301106092b06010401b43b0a01040401020304300a06082a + 8648ce3d0403020349003046022100c0d81996d2507d693f3c48eaa5ee94 + 91bda6db214099d98117c63b361374cd86022100a774989f4c321a5cf25d + 832a4d336a08ad67df20f1506421188a0ade6d349236a1003100 + + The request and response is shown in plain text in Appendix C.2. + +A.3. serverkeygen + + In a serverkeygen exchange, the CoAP POST request looks like the + following: + + POST 192.0.2.1:8085/est/skg + (Token: 0xa5) + (Accept: 62) + (Content-Format: 286) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3081d03078020100301631143012060355040a0c0b736b67206578616d70 + 6c653059301306072a8648ce3d020106082a8648ce3d03010703420004c8 + b421f11c25e47e3ac57123bf2d9fdc494f028bc351cc80c03f150bf50cff + 958d75419d81a6a245dffae790be95cf75f602f9152618f816a2b23b5638 + e59fd9a000300a06082a8648ce3d040302034800304502207c553981b1fe + 349249d8a3f50a0346336b7dfaa099cf74e1ec7a37a0a760485902210084 + 79295398774b2ff8e7e82abb0c17eaef344a5088fa69fd63ee611850c34b + 0a + + The response would follow [RFC8710] and could look like the + following: + + 2.04 Changed + (Token: 0xa5) + (Content-Format: 62) + + [ The hexadecimal representations below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 84 # array(4) + 19 011C # unsigned(284) + 58 8A # bytes(138) + 308187020100301306072a8648ce3d020106082a8648ce3d030107046d30 + 6b020101042061336a86ac6e7af4a96f632830ad4e6aa0837679206094d7 + 679a01ca8c6f0c37a14403420004c8b421f11c25e47e3ac57123bf2d9fdc + 494f028bc351cc80c03f150bf50cff958d75419d81a6a245dffae790be95 + cf75f602f9152618f816a2b23b5638e59fd9 + 19 0119 # unsigned(281) + 59 01D3 # bytes(467) + 308201cf06092a864886f70d010702a08201c0308201bc0201013100300b + 06092a864886f70d010701a08201a23082019e30820144a0030201020209 + 00b3313e8f3fc9538e300a06082a8648ce3d040302301631143012060355 + 040a0c0b736b67206578616d706c65301e170d3139303930343037343430 + 335a170d3339303833303037343430335a301631143012060355040a0c0b + 736b67206578616d706c653059301306072a8648ce3d020106082a8648ce + 3d03010703420004c8b421f11c25e47e3ac57123bf2d9fdc494f028bc351 + cc80c03f150bf50cff958d75419d81a6a245dffae790be95cf75f602f915 + 2618f816a2b23b5638e59fd9a37b307930090603551d1304023000302c06 + 096086480186f842010d041f161d4f70656e53534c2047656e6572617465 + 64204365727469666963617465301d0603551d0e0416041496600d8716bf + 7fd0e752d0ac760777ad665d02a0301f0603551d2304183016801496600d + 8716bf7fd0e752d0ac760777ad665d02a0300a06082a8648ce3d04030203 + 48003045022100e95bfa25a08976652246f2d96143da39fce0dc4c9b26b9 + cce1f24164cc2b12b602201351fd8eea65764e3459d324e4345ff5b2a915 + 38c04976111796b3698bf6379ca1003100 + + The private key in the response above is without CMS EnvelopedData + and has no additional encryption beyond DTLS (Section 4.8). + + The request and response is shown in plain text in Appendix C.3. + +A.4. csrattrs + + The following is a csrattrs exchange: + + REQ: + GET example.com:61616/est/att + + RES: + 2.05 Content + (Content-Format: 285) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 307c06072b06010101011630220603883701311b131950617273652053455 + 420617320322e3939392e31206461746106092a864886f70d010907302c06 + 0388370231250603883703060388370413195061727365205345542061732 + 0322e3939392e32206461746106092b240303020801010b06096086480165 + 03040202 + + A 2.05 Content response should contain attributes that are relevant + for the authenticated client. This example is copied from + Appendix A.2 of [RFC7030], where the base64 representation is + replaced with a hexadecimal representation of the equivalent binary + format. The EST-coaps server returns attributes that the client can + ignore if they are unknown to the client. + +Appendix B. EST-coaps Block Message Examples + + Two examples are presented in this section: + + 1. A cacerts exchange shows the use of Block2 and the block headers. + + 2. An enroll exchange shows the Block1 and Block2 size negotiation + for request and response payloads. + + The payloads are shown unencrypted. In practice, the message + contents would be binary formatted and transferred over an encrypted + DTLS tunnel. The corresponding CoAP headers are only shown in + Appendix B.1. Creating CoAP headers is assumed to be generally + known. + +B.1. cacerts + + This section provides a detailed example of the messages using DTLS + and CoAP Option Block2. The example block length is taken as 64, + which gives an SZX value of 2. + + The following is an example of a cacerts exchange over DTLS. The + content length of the cacerts response in Appendix A.1 of [RFC7030] + contains 639 bytes in binary in this example. The CoAP message adds + around 10 bytes in this example, and the DTLS record around 29 bytes. + To avoid IP fragmentation, the CoAP Block Option is used and an MTU + of 127 is assumed to stay within one IEEE 802.15.4 packet. To stay + below the MTU of 127, the payload is split in 9 packets with a + payload of 64 bytes each, followed by a last tenth packet of 63 + bytes. The client sends an IPv6 packet containing a UDP datagram + with DTLS record protection that encapsulates a CoAP request 10 times + (one fragment of the request per block). The server returns an IPv6 + packet containing a UDP datagram with the DTLS record that + encapsulates the CoAP response. The CoAP request-response exchange + with block option is shown below. Block Option is shown in a + decomposed way (block-option:NUM/M/size) indicating the kind of Block + Option (2 in this case) followed by a colon, and then the block + number (NUM), the more bit (M = 0 in Block2 response means it is last + block), and block size with exponent (2^(SZX+4)) separated by + slashes. The Length 64 is used with SZX=2. The CoAP Request is sent + Confirmable (CON), and the Content-Format of the response, even + though not shown, is 281 (application/pkcs7-mime; smime-type=certs- + only). The transfer of the 10 blocks with partially filled block + NUM=9 is shown below. + + GET example.com:9085/est/crts (2:0/0/64) --> + <-- (2:0/1/64) 2.05 Content + GET example.com:9085/est/crts (2:1/0/64) --> + <-- (2:1/1/64) 2.05 Content + | + | + | + GET example.com:9085/est/crts (2:9/0/64) --> + <-- (2:9/0/64) 2.05 Content + + The header of the GET request looks like the following: + + Ver = 1 + T = 0 (CON) + Code = 0x01 (0.1 GET) + Token = 0x9a (client generated) + Options + Option (Uri-Host) + Option Delta = 0x3 (option# 3) + Option Length = 0xB + Option Value = "example.com" + Option (Uri-Port) + Option Delta = 0x4 (option# 3+4=7) + Option Length = 0x2 + Option Value = 9085 + Option (Uri-Path) + Option Delta = 0x4 (option# 7+4=11) + Option Length = 0x3 + Option Value = "est" + Option (Uri-Path)Uri-Path) + Option Delta = 0x0 (option# 11+0=11) + Option Length = 0x4 + Option Value = "crts" + Option (Accept) + Option Delta = 0x6 (option# 11+6=17) + Option Length = 0x2 + Option Value = 281 + Payload = [Empty] + + The Uri-Host and Uri-Port Options can be omitted if they coincide + with the transport protocol destination address and port, + respectively. Explicit Uri-Host and Uri-Port Options are typically + used when an endpoint hosts multiple virtual servers and uses the + Options to route the requests accordingly. + + To provide further details on the CoAP headers, the first two and the + last blocks are written out below. The header of the first Block2 + response looks like the following: + + Ver = 1 + T = 2 (ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option# 12+11=23 Block2) + Option Length = 0x1 + Option Value = 0x0A (block#=0, M=1, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 3082027b06092a864886f70d010702a082026c308202680201013100300b + 06092a864886f70d010701a082024e3082024a308201f0a0030201020209 + 009189bc + + The header of the second Block2 response looks like the following: + + Ver = 1 + T = 2 (means ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option 12+11=23 Block2) + Option Length = 0x1 + Option Value = 0x1A (block#=1, M=1, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + df9c99244b300a06082a8648ce3d0403023067310b300906035504061302 + 5553310b300906035504080c024341310b300906035504070c024c413114 + 30120603 + + The header of the tenth and final Block2 response looks like the + following: + + Ver = 1 + T = 2 (means ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option# 12+11=23 Block2 ) + Option Length = 0x1 + Option Value = 0x92 (block#=9, M=0, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 2ec0b4af52d46f3b7ecc9687ddf267bcec368f7b7f1353272f022047a28a + e5c7306163b3c3834bab3c103f743070594c089aaa0ac870cd13b902caa1 + 003100 + +B.2. enroll / reenroll + + In this example, the requested Block2 size of 256 bytes, required by + the client, is transferred to the server in the very first request + message. The block size of 256 is equal to (2^(SZX+4)), which gives + SZX=4. The notation for block numbering is the same as in + Appendix B.1. The header fields and the payload are omitted for + brevity. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(1:N1/0/256) + {CSR(frag# N1+1)}--> + | + ...........Immediate response ......... + | + <-- (ACK) (1:N1/0/256)(2:0/1/256)(2.04 Changed) + {Cert resp (frag# 1)} + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256)(2.04 Changed) + {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:321]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) + {Cert resp (frag# N2+1)} + + Figure 6: EST-coaps Enrollment with Multiple Blocks + + N1+1 blocks have been transferred from client to server, and N2+1 + blocks have been transferred from server to client. + +Appendix C. Message Content Breakdown + + This appendix presents the hexadecimal dumps of the binary payloads + in plain text shown in Appendix A. + +C.1. cacerts + + The cacerts response containing one root CA certificate is presented + in plain text in the following: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 831953162763987486 (0xb8bb0fe604f6a1e) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=CA, L=LA, O=Example Inc, + OU=certification, CN=Root CA + Validity + Not Before: Jan 31 11:27:03 2019 GMT + Not After : Jan 26 11:27:03 2039 GMT + Subject: C=US, ST=CA, L=LA, O=Example Inc, + OU=certification, CN=Root CA + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:0c:1b:1e:82:ba:8c:c7:26:80:97:3f:97:ed:b8: + a0:c7:2a:b0:d4:05:f0:5d:4f:e2:9b:99:7a:14:cc: + ce:89:00:83:13:d0:96:66:b6:ce:37:5c:59:5f:cc: + 8e:37:f8:e4:35:44:97:01:1b:e9:0e:56:79:4b:d9: + 1a:d9:51:ab:45 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + 1D:F1:20:89:44:D7:7B:5F:1D:9D:CB:51:EE:24:4A:52:3F:3E:F5:DE + X509v3 Authority Key Identifier: + keyid: + 1D:F1:20:89:44:D7:7B:5F:1D:9D:CB:51:EE:24:4A:52:3F:3E:F5:DE + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + email:certify@example.com + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:2b:89:1d:d4:11:d0:7a:6d:6f:62:19:47:63:5b: + a4:c4:31:65:29:6b:3f:63:37:26:f0:2e:51:ec:f4:64:bd:40: + 02:21:00:b4:be:8a:80:d0:86:75:f0:41:fb:c7:19:ac:f3:b3: + 9d:ed:c8:5d:c9:2b:30:35:86:8c:b2:da:a8:f0:5d:b1:96 + +C.2. enroll / reenroll + + The enrollment request is presented in plain text in the following: + + Certificate Request: + Data: + Version: 0 (0x0) + Subject: C=US, ST=CA, L=LA, O=example Inc, + OU=IoT/serialNumber=Wt1234 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Attributes: + challengePassword: <256-bit POP linking value> + Requested Extensions: + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:92:56:3a:54:64:63:bd:9e:cf:f1:70:d0:fd: + 1f:2e:f0:d3:d0:12:16:0e:5e:e9:0c:ff:ed:ab:ec:9b:9a:38: + 92:02:20:17:9f:10:a3:43:61:09:05:1a:ba:d1:75:90:a0:9b: + c8:7c:4d:ce:54:53:a6:fc:11:35:a1:e8:4e:ed:75:43:77 + + The CSR contains a challengePassword, which is used for POP linking + (Section 3). The CSR also contains an id-on-hardwareModuleName + hardware identifier to customize the returned certificate to the + requesting device (See [RFC7299] and [PKI-GUIDE]). + + The issued certificate presented in plain text in the following: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 9112578475118446130 (0x7e7661d7b54e4632) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=CA, O=Example Inc, + OU=certification, CN=802.1AR CA + Validity + Not Before: Jan 31 11:29:16 2019 GMT + Not After : Dec 31 23:59:59 9999 GMT + Subject: C=US, ST=CA, L=LA, O=example Inc, + OU=IoT/serialNumber=Wt1234 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + X509v3 Authority Key Identifier: + keyid: + 68:D1:65:51:F9:51:BF:C8:2A:43:1D:0D:9F:08:BC:2D:20:5B:11:60 + + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:c0:d8:19:96:d2:50:7d:69:3f:3c:48:ea:a5: + ee:94:91:bd:a6:db:21:40:99:d9:81:17:c6:3b:36:13:74:cd: + 86:02:21:00:a7:74:98:9f:4c:32:1a:5c:f2:5d:83:2a:4d:33: + 6a:08:ad:67:df:20:f1:50:64:21:18:8a:0a:de:6d:34:92:36 + +C.3. serverkeygen + + The following is the server-side key generation request presented in + plain text: + + Certificate Request: + Data: + Version: 0 (0x0) + Subject: O=skg example + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Attributes: + a0:00 + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:7c:55:39:81:b1:fe:34:92:49:d8:a3:f5:0a:03: + 46:33:6b:7d:fa:a0:99:cf:74:e1:ec:7a:37:a0:a7:60:48:59: + 02:21:00:84:79:29:53:98:77:4b:2f:f8:e7:e8:2a:bb:0c:17: + ea:ef:34:4a:50:88:fa:69:fd:63:ee:61:18:50:c3:4b:0a + + The following is the private key content of the server-side key + generation response presented in plain text: + + Private-Key: (256 bit) + priv: + 61:33:6a:86:ac:6e:7a:f4:a9:6f:63:28:30:ad:4e: + 6a:a0:83:76:79:20:60:94:d7:67:9a:01:ca:8c:6f: + 0c:37 + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + + The following is the certificate in the server-side key generation + response payload presented in plain text: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b3:31:3e:8f:3f:c9:53:8e + Signature Algorithm: ecdsa-with-SHA256 + Issuer: O=skg example + Validity + Not Before: Sep 4 07:44:03 2019 GMT + Not After : Aug 30 07:44:03 2039 GMT + Subject: O=skg example + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + X509v3 Authority Key Identifier: + keyid: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:e9:5b:fa:25:a0:89:76:65:22:46:f2:d9:61: + 43:da:39:fc:e0:dc:4c:9b:26:b9:cc:e1:f2:41:64:cc:2b:12: + b6:02:20:13:51:fd:8e:ea:65:76:4e:34:59:d3:24:e4:34:5f: + f5:b2:a9:15:38:c0:49:76:11:17:96:b3:69:8b:f6:37:9c + +Acknowledgements + + The authors are very grateful to Klaus Hartke for his detailed + explanations on the use of Block with DTLS and his support for the + Content-Format specification. The authors would like to thank Esko + Dijk and Michael Verschoor for the valuable discussions that helped + in shaping the solution. They would also like to thank Peter + Panburana for his feedback on technical details of the solution. + Constructive comments were received from Benjamin Kaduk, Eliot Lear, + Jim Schaad, Hannes Tschofenig, Julien Vermillard, John Manuel, Oliver + Pfaff, Pete Beal, and Carsten Bormann. + + Interop tests were done by Oliver Pfaff, Thomas Werner, Oskar + Camezind, Bjorn Elmers, and Joel Hoglund. + + Robert Moskowitz provided code to create the examples. + +Contributors + + Martin Furuhed contributed to the EST-coaps specification by + providing feedback based on the Nexus EST-over-CoAPS server + implementation that started in 2015. Sandeep Kumar kick-started this + specification and was instrumental in drawing attention to the + importance of the subject. + +Authors' Addresses + + Peter van der Stok + Consultant + Email: stokcons@bbhmail.nl + + + Panos Kampanakis + Cisco Systems + Email: pkampana@cisco.com + + + Michael C. Richardson + Sandelman Software Works + Email: mcr+ietf@sandelman.ca + URI: https://www.sandelman.ca/ + + + Shahid Raza + RISE Research Institutes of Sweden + Isafjordsgatan 22 + SE-16440 Kista, Stockholm + Sweden + Email: shahid.raza@ri.se + +``` diff --git a/docs/rfc9148-bis-source/rfc9148-bis-skeleton.txt b/docs/rfc9148-bis-source/rfc9148-bis-skeleton.txt new file mode 100644 index 0000000000..a7d2945ce2 --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148-bis-skeleton.txt @@ -0,0 +1,2285 @@ +================================================================================ +WORK IN PROGRESS — RFC 9148 bis skeleton (not submitted to IETF) +Merged from RFC 9148 + updates derived from draft-ietf-anima-constrained-voucher-31 +Generated by build-rfc9148-bis-skeleton.py — review before any publication use +================================================================================ + +Internet-Draft Skeleton Editor +Obsoletes: 9148 (if approved) P. van der Stok +Intended status: Standards Track (based on RFC 9148 authors) +Expires: TBD + + EST over secure CoAP (EST-coaps) + bis skeleton draft + +1. Introduction + 2. Terminology + 3. DTLS and Conformance to RFC 7925 Profiles + 4. Protocol Design + 4.1. Discovery and URIs + 4.2. Mandatory/Optional EST Functions + 4.3. Payload Formats + 4.4. Message Bindings + 4.5. CoAP Response Codes + 4.6. Message Fragmentation + 4.7. Delayed Responses + 4.8. Server-Side Key Generation + 5. HTTPS-CoAPS Registrar + 6. Parameters + 7. Deployment Limitations + 8. IANA Considerations + 8.1. Content-Formats Registry + 8.2. Resource Type Registry + 8.3. Well-Known URIs Registry + 9. Security Considerations + 9.1. EST Server Considerations + 9.2. HTTPS-CoAPS Registrar Considerations + 10. References + 10.1. Normative References + 10.2. Informative References + + [CBRSKI] Richardson, M., van der Stok, P., Kampanakis, P., and E. + Dijk, "Constrained Bootstrapping Remote Secure Key + Infrastructure (cBRSKI)", Work in Progress, draft-ietf- + anima-constrained-voucher-31, 8 June 2026, + . + Appendix A. EST Messages to EST-coaps + A.1. cacerts + A.2. enroll / reenroll + A.3. serverkeygen + A.4. csrattrs + Appendix B. EST-coaps Block Message Examples + B.1. cacerts + B.2. enroll / reenroll + Appendix C. Message Content Breakdown + C.1. cacerts + C.2. enroll / reenroll + C.3. serverkeygen + Acknowledgements + Contributors + Authors' Addresses + +1. Introduction + + "Classical" Enrollment over Secure Transport (EST) [RFC7030] is used + for authenticated/authorized endpoint certificate enrollment (and + optionally key provisioning) through a Certification Authority (CA) + or Registration Authority (RA). EST transports messages over HTTPS. + + This document defines a new transport for EST based on the + Constrained Application Protocol (CoAP) since some Internet of Things + (IoT) devices use CoAP instead of HTTP. Therefore, this + specification utilizes DTLS [RFC6347] and CoAP [RFC7252] instead of + TLS [RFC8446] and HTTP [RFC7230]. + + EST responses can be relatively large, and for this reason, this + specification also uses CoAP Block-Wise Transfer [RFC7959] to offer a + fragmentation mechanism of EST messages at the CoAP layer. + + This document also profiles the use of EST to support certificate- + based client authentication only. Neither HTTP Basic nor Digest + authentication (as described in Section 3.2.3 of [RFC7030]) is + supported. + This document obsoletes [RFC9148]. It adds mandatory DTLS 1.3 cipher + suites, DTLS version and record-size requirements for constrained + deployments, multipart-core encoding for the /crts resource, server + behavior for single-certificate /crts responses (Content-Format 287), + and normative procedures for CA certificate renewal and client re- + enrollment with trust anchor update. These updates were first + specified in the context of cBRSKI [CBRSKI]. + + +2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + Many of the concepts in this document are taken from [RFC7030]. + Consequently, much text is directly traceable to [RFC7030]. + +3. DTLS and Conformance to RFC 7925 Profiles + + This section describes how EST-coaps conforms to the profiles of low- + resource devices described in [RFC7925]. EST-coaps can transport + certificates and private keys. Certificates are responses to + (re-)enrollment requests or requests for a trusted certificate list. + Private keys can be transported as responses to a server-side key + generation request as described in Section 4.4 of [RFC7030] (and + subsections) and discussed in Section 4.8 of this document. + + EST-coaps depends on a secure transport mechanism that secures the + exchanged CoAP messages. DTLS is one such secure protocol. No other + changes are necessary regarding the secure transport of EST messages. + + +------------------------------------------------+ + | EST request/response messages | + +------------------------------------------------+ + | CoAP for message transfer and signaling | + +------------------------------------------------+ + | Secure Transport | + +------------------------------------------------+ + + Figure 1: EST-coaps Protocol Layers + + + DTLS 1.2 implementations must use the Supported Elliptic Curves and + Supported Point Formats Extensions in [RFC8422]. Uncompressed point + format must also be supported. DTLS 1.3 [RFC9147] implementations + differ from DTLS 1.2 because they do not support point format + negotiation in favor of a single point format for each curve. Thus, + support for DTLS 1.3 does not mandate point format extensions and + negotiation. In addition, in DTLS 1.3, the Supported Elliptic Curves + extension has been renamed to Supported Groups. + +3.1. DTLS Version Requirements + + DTLS version 1.3 [RFC9147] SHOULD be used in any implementation of + this specification. An EST-coaps server MUST by default support both + DTLS 1.3 and DTLS 1.2 client connections. For security reasons, an + EST-coaps server MAY be administratively configured to support only a + particular DTLS version or higher. + + An EST-coaps client that implements DTLS 1.3 MUST NOT additionally + support DTLS 1.2. This prevents a rogue server from forcing the + client onto DTLS 1.2, reduces the DTLS code attack surface on + constrained clients, and keeps more handshake metadata encrypted. + + An exception case where DTLS 1.2 MAY be used is a client on a software + platform where a DTLS 1.3 client is not available (yet), for example + when a legacy device is software-upgraded to support EST-coaps. + +3.2. DTLS Cipher Suite Requirements + +3.2.1. DTLS 1.2 Cipher Suites + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS 1.2 in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. + + An EST-coaps client using DTLS 1.2 MUST implement + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 and MAY implement other cipher + suites. + +3.2.2. DTLS 1.3 Cipher Suites + + An EST-coaps server MUST support the following DTLS 1.3 cipher suites: + + * the mandatory TLS 1.3 cipher suites as defined in Section 9.1 of + [RFC8446] (TLS_AES_128_GCM_SHA256 with the digital signature and + key exchange algorithms listed there), + + * TLS_AES_128_CCM_8_SHA256 (with the same digital signature and key + exchange algorithms), and + + * TLS_AES_128_CCM_SHA256 (with the same digital signature and key + exchange algorithms). + + To enable clients whose certificate contains an Ed25519 public key, + an EST-coaps server MUST support digital signature algorithm Ed25519 + and elliptic curve group X25519 (see [RFC8446]). + + Per Section 4.5.3 of [RFC9147], the cipher suite + TLS_AES_128_CCM_8_SHA256 cannot be used unless specific measures are + taken against packet forgery attacks. The RECOMMENDED safeguard is + to limit the number of records that can fail authentication to at + most 2^7, as defined in Appendix B.3 of [RFC9147]. If this measure + is applied and the limit is reached, the DTLS connection MUST be + closed. + + An EST-coaps client using DTLS 1.3 MUST implement at least one of + the above cipher suites supported by the server and MAY implement + multiple of these. + + CoAP was designed to avoid IP fragmentation. DTLS is used to secure + CoAP messages. However, fragmentation is still possible at the DTLS + layer during the DTLS handshake even when using Elliptic Curve + Cryptography (ECC) cipher suites. If fragmentation is necessary, + "DTLS provides a mechanism for fragmenting a handshake message over a + number of records, each of which can be transmitted separately, thus + avoiding IP fragmentation" [RFC6347]. + +3.3. DTLS Handshake Fragmentation and Record Size Limits + + On constrained networks, particularly when DTLS records are relayed + through an intermediary with limited MTU, it is RECOMMENDED that a + PMTU of 1024 bytes be assumed for the DTLS handshake and that + appropriate DTLS fragmentation be used. + + During EST-coaps operation, the CoAP Block-Wise transfer mechanism + [RFC7959] is used automatically when message sizes exceed the PMTU. + An EST-coaps client on a constrained network operating as a DTLS 1.2 + client MUST use the (D)TLS maximum fragment length extension + ('max_fragment_length') defined in Section 4 of [RFC6066], with the + maximum fragment length set to a value of either 2^9 or 2^10. + + An EST-coaps client operating as a DTLS 1.3 client MUST use the + (D)TLS record size limit extension ('record_size_limit') defined in + Section 4 of [RFC8449], with RecordSizeLimit set to a value between + 512 and 1024 (inclusive). + + The authentication of the EST-coaps server by the EST-coaps client is + based on certificate authentication in the DTLS handshake. The EST- + coaps client MUST be configured with at least an Implicit Trust + Anchor database, which will enable the authentication of the server + the first time before updating its trust anchor (Explicit TA) + [RFC7030]. + + The authentication of the EST-coaps client MUST be with a client + certificate in the DTLS handshake. This can either be: + + * A previously issued client certificate (e.g., an existing + certificate issued by the EST CA); this could be a common case for + simple re-enrollment of clients. + + * A previously installed certificate (e.g., manufacturer IDevID + [IEEE802.1AR] or a certificate issued by some other party). + IDevID's are expected to have a very long life, as long as the + device, but under some conditions could expire. In that case, the + server MAY authenticate a client certificate against its trust + store though the certificate is expired (Section 9). + + EST-coaps supports the certificate types and TAs that are specified + for EST in Section 3 of [RFC7030]. + + As described in Section 2.1 of [RFC5272], proof-of-identity refers to + a value that can be used to prove that an end entity or client is in + the possession of and can use the private key corresponding to the + certified public key. Additionally, channel-binding information can + link proof-of-identity with an established connection. Connection- + based proof-of-possession is OPTIONAL for EST-coaps clients and + servers. When proof-of-possession is desired, a set of actions are + required regarding the use of tls-unique, described in Section 3.5 of + [RFC7030]. The tls-unique information consists of the contents of + the first Finished message in the (D)TLS handshake between server and + client [RFC5929]. The client adds the Finished message as a + challengePassword in the attributes section of the PKCS #10 + CertificationRequest [RFC5967] to prove that the client is indeed in + control of the private key at the time of the (D)TLS session + establishment. In the case of handshake message fragmentation, if + proof-of-possession is desired, the Finished message added as the + challengePassword in the Certificate Signing Request (CSR) is + calculated as specified by (D)TLS. We summarize it here for + convenience. For DTLS 1.2, in the event of handshake message + fragmentation, the hash of the handshake messages used in the Message + Authentication Code (MAC) calculation of the Finished message must be + computed on each reassembled message, as if each message had not been + fragmented (Section 4.2.6 of [RFC6347]). The Finished message is + calculated as shown in Section 7.4.9 of [RFC5246]. + + For (D)TLS 1.3, Appendix C.5 of [RFC8446] describes the lack of + channel bindings similar to tls-unique. [TLS13-CHANNEL-BINDINGS] can + be used instead to derive a 32-byte tls-exporter binding from the + (D)TLS 1.3 master secret by using a PRF negotiated in the (D)TLS 1.3 + handshake, "EXPORTER-Channel-Binding" with no terminating NUL as the + label, the ClientHello.random and ServerHello.random, and a zero- + length context string. When proof-of-possession is desired, the + client adds the tls-exporter value as a challengePassword in the + attributes section of the PKCS #10 CertificationRequest [RFC5967] to + prove that the client is indeed in control of the private key at the + time of the (D)TLS session establishment. + + In a constrained CoAP environment, endpoints can't always afford to + establish a DTLS connection for every EST transaction. An EST-coaps + DTLS connection MAY remain open for sequential EST transactions, + which was not the case with [RFC7030]. For example, if a /crts + request is followed by a /sen request, both can use the same + authenticated DTLS connection. However, when a /crts request is + included in the set of sequential EST transactions, some additional + security considerations apply regarding the use of the Implicit and + Explicit TA database as explained in Section 9.1. + + Given that after a successful enrollment, it is more likely that a + new EST transaction will not take place for a significant amount of + time, the DTLS connections SHOULD only be kept alive for EST messages + that are relatively close to each other. These could include a /sen + immediately following a /crts when a device is getting bootstrapped. + In some cases, like NAT rebinding, keeping the state of a connection + is not possible when devices sleep for extended periods of time. In + such occasions, [RFC9146] negotiates a connection ID that can + eliminate the need for a new handshake and its additional cost; or, + DTLS session resumption provides a less costly alternative than + redoing a full DTLS handshake. + +4. Protocol Design + + EST-coaps uses CoAP to transfer EST messages, aided by Block-Wise + Transfer [RFC7959], to avoid IP fragmentation. The use of blocks for + the transfer of larger EST messages is specified in Section 4.6. + Figure 1 shows the layered EST-coaps architecture. + + The EST-coaps protocol design follows closely the EST design. The + supported message types in EST-coaps are: + + * CA certificate retrieval needed to receive the complete set of CA + certificates. + + * Simple enroll and re-enroll for a CA to sign client identity + public keys. + + * Certificate Signing Request (CSR) attribute messages that informs + the client of the fields to include in a CSR. + + * Server-side key generation messages to provide a client identity + private key when the client chooses so. + + While [RFC7030] permits a number of the EST functions to be used + without authentication, this specification requires that the client + MUST be authenticated for all functions. + +4.1. Discovery and URIs + + EST-coaps is targeted for low-resource networks with small packets. + Two types of installations are possible: (1) a rigid one, where the + address and the supported functions of the EST server(s) are known, + and (2) a flexible one, where the EST server and its supported + functions need to be discovered. + + For both types of installations, saving header space is important and + short EST-coaps URIs are specified in this document. These URIs are + shorter than the ones in [RFC7030]. Two example EST-coaps resource + path names are: + + coaps://example.com:/.well-known/est/ + coaps://example.com:/.well-known/est/ArbitraryLabel/ + + The short-est strings are defined in Table 1. Arbitrary Labels are + usually defined and used by EST CAs in order to route client requests + to the appropriate certificate profile. Implementers should consider + using short labels to minimize transmission overhead. + + The EST-coaps server URIs, obtained through discovery of the EST- + coaps resource(s) as shown below, are of the form: + + coaps://example.com:// + coaps://example.com://ArbitraryLabel/ + + Figure 5 in Section 3.2.2 of [RFC7030] enumerates the operations and + corresponding paths that are supported by EST. Table 1 provides the + mapping from the EST URI path to the shorter EST-coaps URI path. + + +=================+==============================+ + | EST | EST-coaps | + +=================+==============================+ + | /cacerts | /crts | + +-----------------+------------------------------+ + | /simpleenroll | /sen | + +-----------------+------------------------------+ + | /simplereenroll | /sren | + +-----------------+------------------------------+ + | /serverkeygen | /skg (PKCS #7) | + +-----------------+------------------------------+ + | /serverkeygen | /skc (application/pkix-cert) | + +-----------------+------------------------------+ + | /csrattrs | /att | + +-----------------+------------------------------+ + + Table 1: Short EST-coaps URI Path + + The /skg message is the EST /serverkeygen equivalent where the client + requests a certificate in PKCS #7 format and a private key. If the + client prefers a single application/pkix-cert certificate instead of + PKCS #7, it will make an /skc request. In both cases (i.e., /skg, + /skc), a private key MUST be returned. + + Clients and servers MUST support the short resource EST-coaps URIs. + + In the context of CoAP, the presence and location of (path to) the + EST resources are discovered by sending a GET request to "/.well- + known/core" including a resource type (RT) parameter with the value + "ace.est*" [RFC6690]. The example below shows the discovery over + CoAPS of the presence and location of EST-coaps resources. Linefeeds + are included only for readability. + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + ;rt="ace.est.crts";ct="62 281 287", + ;rt="ace.est.sen";ct="281 287", + ;rt="ace.est.sren";ct="281 287", + ;rt="ace.est.att";ct=285, + ;rt="ace.est.skg";ct=62, + ;rt="ace.est.skc";ct=62 + + The first three lines, describing ace.est.crts, ace.est.sen, and + ace.est.sren, of the discovery response above MUST be returned if the + server supports resource discovery. The last three lines are only + included if the corresponding EST functions are implemented (see + Table 2). The Content-Formats in the response allow the client to + request one that is supported by the server. These are the values + that would be sent in the client request with an Accept Option. + + Discoverable port numbers can be returned in the response payload. + An example response payload for non-default CoAPS server port 61617 + follows below. Linefeeds are included only for readability. + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + ;rt="ace.est.crts"; + ct="62 281 287", + ;rt="ace.est.sen"; + ct="281 287", + ;rt="ace.est.sren"; + ct="281 287", + ;rt="ace.est.att"; + ct=285, + ;rt="ace.est.skg"; + ct=62, + ;rt="ace.est.skc"; + ct=62 + + The server MUST support the default /.well-known/est root resource. + + The resource type value "ace.est" identifies a base resource in a + resource hierarchy on a CoAP server, where its sub-resources each + have one of the resource types "ace.est.*" as defined in this + specification. + + The server SHOULD support resource discovery when it supports non- + default URIs (like /est or /est/ArbitraryLabel) or ports. The client + SHOULD use resource discovery when it is unaware of the available + EST-coaps resources. + + Throughout this document, the example root resource of /est is used. + +4.2. Mandatory/Optional EST Functions + + This specification contains a set of required-to-implement functions, + optional functions, and not-specified functions. The unspecified + functions are deemed too expensive for low-resource devices in + payload and calculation times. + + Table 2 specifies the mandatory-to-implement or optional + implementation of the EST-coaps functions. Discovery of the + existence of optional functions is described in Section 4.1. + + +=================+==========================+ + | EST Functions | EST-coaps Implementation | + +=================+==========================+ + | /cacerts | MUST | + +-----------------+--------------------------+ + | /simpleenroll | MUST | + +-----------------+--------------------------+ + | /simplereenroll | MUST | + +-----------------+--------------------------+ + | /fullcmc | Not specified | + +-----------------+--------------------------+ + | /serverkeygen | OPTIONAL | + +-----------------+--------------------------+ + | /csrattrs | OPTIONAL | + +-----------------+--------------------------+ + + Table 2: List of EST-coaps Functions + +4.3. Payload Formats + + EST-coaps is designed for low-resource devices; hence, it does not + need to send Base64-encoded data. Simple binary is more efficient + (30% smaller payload for DER-encoded ASN.1) and well supported by + CoAP. Thus, the payload for a given media type follows the ASN.1 + structure of the media type and is transported in binary format. + + The Content-Format (HTTP Content-Type equivalent) of the CoAP message + determines which EST message is transported in the CoAP payload. The + media types specified in the HTTP Content-Type header field + (Section 3.2.4 of [RFC7030]) are specified by the Content-Format + Option (12) of CoAP. The combination of URI-Path and Content-Format + in EST-coaps MUST map to an allowed combination of URI and media type + in EST. The required Content-Formats for these requests and response + messages are defined in Section 8.1. The CoAP response codes are + defined in Section 4.5. + + Content-Format 281 (application/pkcs7-mime; smime-type=certs-only) + MUST be supported by EST-coaps servers for the /crts resource. + Content-Format 287 (application/pkix-cert) MAY be supported to carry + a single certificate instead of a PKCS #7 container. Content-Format + 62 (application/multipart-core) MUST be supported for the /crts + resource as specified below. + + The client uses a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + When an EST-coaps server receives a /crts request with a CoAP Accept + Option with value 287 (application/pkix-cert), it MUST return only + the single CA certificate that is the envisioned or actual issuing + CA for the currently authenticated client. An exception is when the + domain is configured to operate with multiple CA trust anchors + exclusively: in that case the server returns a 4.06 (Not Acceptable) + response to signal that the client MUST request a content-format that + supports retrieval of multiple CA certificates. + + A representation with Content-Format identifier 62 for the /crts + resource contains a collection of CA certificates. The multipart + collection MUST contain each CA certificate encoded as an + application/pkix-cert (287) representation. The order of CA + certificates MUST be in the CA hierarchy order, starting from the + issuer of the client's certificate first, up to the highest-level + domain CA, then optionally followed by any further CA certificates + that are not part of this hierarchy (which may be Third-party TAs as + defined in [RFC7030]). The highest-level domain CA may or may not be + a root CA certificate. + + The total number of CA certificates in a /crts response SHOULD be 1, + 2, or 3. A domain operator MAY configure a higher number if all + enrolled clients are known to support larger trust anchor sets. To + facilitate reliable transfer over constrained networks, the server + MUST support CoAP Block-Wise transfer for the /crts response and MUST + support the Size2 Option [RFC7959] to provide the total resource + length in bytes when requested by a client. + + As an example, for a two-level CA domain PKI, a /crts response using + Content-Format 62 may contain, in CBOR diagnostic notation: + + [ 287, h'3082...', 287, h'3082...' ] + + + Content-Format 286 is used in /sen, /sren, and /skg requests and 285 + in /att responses. + + A representation with Content-Format identifier 62 contains a + collection of representations along with their respective Content- + Format. The Content-Format identifies the media type application/ + multipart-core specified in [RFC8710]. For example, a collection, + containing two representations in response to an EST-coaps server- + side key generation /skg request, could include a private key in PKCS + #8 [RFC5958] with Content-Format identifier 284 (0x011C) and a single + certificate in a PKCS #7 container with Content-Format identifier 281 + (0x0119). Such a collection would look like + [284,h'0123456789abcdef', 281,h'fedcba9876543210'] in diagnostic + Concise Binary Object Representation (CBOR) notation. The + serialization of such CBOR content would be: + + 84 # array(4) + 19 011C # unsigned(284) + 48 # bytes(8) + 0123456789ABCDEF # "\x01#Eg\x89\xAB\xCD\xEF" + 19 0119 # unsigned(281) + 48 # bytes(8) + FEDCBA9876543210 # "\xFE\xDC\xBA\x98vT2\x10" + + Figure 2: Multipart /skg Response Serialization + + When the client makes an /skc request, the certificate returned with + the private key is a single X.509 certificate (not a PKCS #7 + container) with Content-Format identifier 287 (0x011F) instead of + 281. In cases where the private key is encrypted with Cryptographic + Message Syntax (CMS) (as explained in Section 4.8), the Content- + Format identifier is 280 (0x0118) instead of 284. The Content-Format + used in the response is summarized in Table 3. + + +==========+==================+==================+ + | Function | Response, Part 1 | Response, Part 2 | + +==========+==================+==================+ + | /skg | 284 | 281 | + +----------+------------------+------------------+ + | /skc | 280 | 287 | + +----------+------------------+------------------+ + + Table 3: Response Content-Formats for /skg and + /skc + + The key and certificate representations are DER-encoded ASN.1, in its + binary form. An example is shown in Appendix A.3. + + Content-Format 287 (application/pkix-cert) MUST be supported by an + EST-coaps server as a response payload for the /sen and /sren + resources. + +4.4. Message Bindings + + The general EST-coaps message characteristics are: + + * EST-coaps servers sometimes need to provide delayed responses, + which are preceded by an immediately returned empty ACK or an ACK + containing response code 5.03 as explained in Section 4.7. Thus, + it is RECOMMENDED for implementers to send EST-coaps requests in + Confirmable (CON) CoAP messages. + + * The CoAP Options used are Uri-Host, Uri-Path, Uri-Port, Content- + Format, Block1, Block2, and Accept. These CoAP Options are used + to communicate the HTTP fields specified in the EST REST messages. + The Uri-host and Uri-Port Options can be omitted from the CoAP + message sent on the wire. When omitted, they are logically + assumed to be the transport protocol destination address and port, + respectively. Explicit Uri-Host and Uri-Port Options are + typically used when an endpoint hosts multiple virtual servers and + uses the Options to route the requests accordingly. Other CoAP + Options should be handled in accordance with [RFC7252]. + + * EST URLs are HTTPS based (https://); in CoAP, these are assumed to + be translated to CoAPS (coaps://). + + Table 1 provides the mapping from the EST URI path to the EST-coaps + URI path. Appendix A includes some practical examples of EST + messages translated to CoAP. + +4.5. CoAP Response Codes + + Section 5.9 of [RFC7252] and Section 7 of [RFC8075] specify the + mapping of HTTP response codes to CoAP response codes. The success + code in response to an EST-coaps GET request (/crts, /att) is 2.05. + Similarly, 2.04 is used in successful response to EST-coaps POST + requests (/sen, /sren, /skg, /skc). + + EST makes use of HTTP 204 or 404 responses when a resource is not + available for the client. In EST-coaps, 2.04 is used in response to + a POST (/sen, /sren, /skg, /skc). 4.04 is used when the resource is + not available for the client. + + HTTP response code 202 with a Retry-After header field in [RFC7030] + has no equivalent in CoAP. HTTP 202 with Retry-After is used in EST + for delayed server responses. Section 4.7 specifies how EST-coaps + handles delayed messages with 5.03 responses with a Max-Age Option. + + Additionally, EST's HTTP 400, 401, 403, 404, and 503 status codes + have their equivalent CoAP 4.00, 4.01, 4.03, 4.04, and 5.03 response + codes in EST-coaps. + For a /crts GET request where the server cannot satisfy the Accept + Option (for example, when the client requests Content-Format 287 but + the domain requires return of multiple CA certificates), the server + returns 4.06 (Not Acceptable). + + Table 4 summarizes the EST-coaps response codes. + + +=============+=========================+==========================+ + | Operation | EST-coaps Response Code | Description | + +=============+=========================+==========================+ + | /crts, /att | 2.05 | Success. Certs included | + | | | in the response payload. | + +-------------+-------------------------+--------------------------+ + | /crts | 4.06 | Accept Option cannot be | + | | | satisfied (multi-TA). | + +-------------+-------------------------+--------------------------+ + | | 4.xx / 5.xx | Failure. | + +-------------+-------------------------+--------------------------+ + | /sen, /skg, | 2.04 | Success. Cert included | + | /sren, /skc | | in the response payload. | + +-------------+-------------------------+--------------------------+ + | | 5.03 | Retry in Max-Age Option | + | | | time. | + +-------------+-------------------------+--------------------------+ + | | 4.xx / 5.xx | Failure. | + +-------------+-------------------------+--------------------------+ + + Table 4: EST-coaps Response Codes + +4.6. Message Fragmentation + + DTLS defines fragmentation only for the handshake and not for secure + data exchange (DTLS records). [RFC6347] states that to avoid using + IP fragmentation, which involves error-prone datagram reconstitution, + invokers of the DTLS record layer should size DTLS records so that + they fit within any Path MTU estimates obtained from the record + layer. In addition, invokers residing on 6LoWPAN (IPv6 over Low- + Power Wireless Personal Area Networks) over IEEE 802.15.4 networks + [IEEE802.15.4] are recommended to size CoAP messages such that each + DTLS record will fit within one or two IEEE 802.15.4 frames. + + That is not always possible in EST-coaps. Even though ECC + certificates are small in size, they can vary greatly based on + signature algorithms, key sizes, and Object Identifier (OID) fields + used. For 256-bit curves, common Elliptic Curve Digital Signature + Algorithm (ECDSA) cert sizes are 500-1000 bytes, which could + fluctuate further based on the algorithms, OIDs, Subject Alternative + Names (SANs), and cert fields. For 384-bit curves, ECDSA + certificates increase in size and can sometimes reach 1.5KB. + Additionally, there are times when the EST cacerts response from the + server can include multiple certificates that amount to large + payloads. Section 4.6 of [RFC7252] (CoAP) describes the possible + payload sizes: "if nothing is known about the size of the headers, + good upper bounds are 1152 bytes for the message size and 1024 bytes + for the payload size". Section 4.6 of [RFC7252] also suggests that + IPv4 implementations may want to limit themselves to more + conservative IPv4 datagram sizes such as 576 bytes. Even with ECC, + EST-coaps messages can still exceed MTU sizes on the Internet or + 6LoWPAN [RFC4919] (Section 2 of [RFC7959]). EST-coaps needs to be + able to fragment messages into multiple DTLS datagrams. + + To perform fragmentation in CoAP, [RFC7959] specifies the Block1 + Option for fragmentation of the request payload and the Block2 Option + for fragmentation of the return payload of a CoAP flow. As explained + in Section 1 of [RFC7959], block-wise transfers should be used in + Confirmable CoAP messages to avoid the exacerbation of lost blocks. + EST-coaps servers MUST implement Block1 and Block2. EST-coaps + clients MUST implement Block2. EST-coaps clients MUST implement + Block1 only if they are expecting to send EST-coaps requests with a + packet size that exceeds the path MTU. + + [RFC7959] also defines Size1 and Size2 Options to provide size + information about the resource representation in a request and + response. The EST-coaps client and server MAY support Size1 and + Size2 Options. + + Examples of fragmented EST-coaps messages are shown in Appendix B. + +4.7. Delayed Responses + + Server responses can sometimes be delayed. According to + Section 5.2.2 of [RFC7252], a slow server can acknowledge the request + and respond later with the requested resource representation. In + particular, a slow server can respond to an EST-coaps enrollment + request with an empty ACK with code 0.00 before sending the + certificate to the client after a short delay. If the certificate + response is large, the server will need more than one Block2 block to + transfer it. + + This situation is shown in Figure 3. The client sends an enrollment + request that uses N1+1 Block1 blocks. The server uses an empty 0.00 + ACK to announce the delayed response, which is provided later with + 2.04 messages containing N2+1 Block2 Options. The first 2.04 is a + Confirmable message that is acknowledged by the client. Onwards, the + client acknowledges all subsequent Block2 blocks. The notation of + Figure 3 is explained in Appendix B.1. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + <-- (0.00 empty ACK) + | + ... Short delay before the certificate is ready ... + | + <-- (CON) (1:N1/0/256)(2:0/1/256)(2.04 Changed) + {Cert resp (frag# 1)} + (ACK) --> + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256) (2.04 Changed) {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) {Cert resp (frag# N2+1)} + + Figure 3: EST-coaps Enrollment with Short Wait + + If the server is very slow (for example, manual intervention is + required, which would take minutes), it SHOULD respond with an ACK + containing response code 5.03 (Service unavailable) and a Max-Age + Option to indicate the time the client SHOULD wait before sending + another request to obtain the content. After a delay of Max-Age, the + client SHOULD resend the identical CSR to the server. As long as the + server continues to respond with response code 5.03 (Service + Unavailable) with a Max-Age Option, the client will continue to delay + for Max-Age and then resend the enrollment request until the server + responds with the certificate or the client abandons the request due + to policy or other reasons. + + To demonstrate this scenario, Figure 4 shows a client sending an + enrollment request that uses N1+1 Block1 blocks to send the CSR to + the server. The server needs N2+1 Block2 blocks to respond but also + needs to take a long delay (minutes) to provide the response. + Consequently, the server uses a 5.03 ACK response with a Max-Age + Option. The client waits for a period of Max-Age as many times as it + receives the same 5.03 response and retransmits the enrollment + request until it receives a certificate in a fragmented 2.04 + response. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + <-- (ACK) (1:N1/0/256) (5.03 Service Unavailable) (Max-Age) + | + | + ... Client tries again after Max-Age with identical payload ... + | + | + POST [2001:db8::2:1]:61616/est/sen(CON)(1:0/1/256) + {CSR (frag# 1)}--> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + | + ... Immediate response when certificate is ready ... + | + <-- (ACK) (1:N1/0/256) (2:0/1/256) (2.04 Changed) + {Cert resp (frag# 1)} + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256) (2.04 Changed) {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) {Cert resp (frag# N2+1)} + + Figure 4: EST-coaps Enrollment with Long Wait + +4.8. Server-Side Key Generation + + Private keys can be generated on the server to support scenarios + where server-side key generation is needed. Such scenarios include + those where it is considered more secure to generate the long-lived, + random private key that identifies the client at the server, or where + the resources spent to generate a random private key at the client + are considered scarce, or where the security policy requires that the + certificate public and corresponding private keys are centrally + generated and controlled. As always, it is necessary to use proper + random numbers in various protocols such as (D)TLS (Section 9.1). + + When requesting server-side key generation, the client asks for the + server or proxy to generate the private key and the certificate, + which are transferred back to the client in the server-side key + generation response. In all respects, the server treats the CSR as + it would treat any enroll or re-enroll CSR; the only distinction here + is that the server MUST ignore the public key values and signature in + the CSR. These are included in the request only to allow reuse of + existing codebases for generating and parsing such requests. + + The client /skg request is for a certificate in a PKCS #7 container + and private key in two application/multipart-core elements. + Respectively, an /skc request is for a single application/pkix-cert + certificate and a private key. The private key Content-Format + requested by the client is indicated in the PKCS #10 CSR request. If + the request contains SMIMECapabilities and DecryptKeyIdentifier or + AsymmetricDecryptKeyIdentifier, the client is expecting Content- + Format 280 for the private key. Then, this private key is encrypted + symmetrically or asymmetrically per [RFC7030]. The symmetric key or + the asymmetric keypair establishment method is out of scope of this + specification. An /skg or /skc request with a CSR without + SMIMECapabilities expects an application/multipart-core with an + unencrypted PKCS #8 private key with Content-Format 284. + + The EST-coaps server-side key generation response is returned with + Content-Format application/multipart-core [RFC8710] containing a CBOR + array with four items (Section 4.3). The two representations (each + consisting of two CBOR array items) do not have to be in a particular + order since each representation is preceded by its Content-Format ID. + Depending on the request, the private key can be in unprotected PKCS + #8 format [RFC5958] (Content-Format 284) or protected inside of CMS + SignedData (Content-Format 280). The SignedData, placed in the + outermost container, is signed by the party that generated the + private key, which may be the EST server or the EST CA. SignedData + placed within the Enveloped Data does not need additional signing as + explained in Section 4.4.2 of [RFC7030]. In summary, the + symmetrically encrypted key is included in the encryptedKey attribute + in a KEKRecipientInfo structure. In the case where the asymmetric + encryption key is suitable for transport key operations, the + generated private key is encrypted with a symmetric key. The + symmetric key itself is encrypted by the client-defined (in the CSR) + asymmetric public key and is carried in an encryptedKey attribute in + a KeyTransRecipientInfo structure. Finally, if the asymmetric + encryption key is suitable for key agreement, the generated private + key is encrypted with a symmetric key. The symmetric key itself is + encrypted by the client defined (in the CSR) asymmetric public key + and is carried in a recipientEncryptedKeys attribute in a + KeyAgreeRecipientInfo. + + [RFC7030] recommends the use of additional encryption of the returned + private key. For the context of this specification, clients and + servers that choose to support server-side key generation MUST + support unprotected (PKCS #8) private keys (Content-Format 284). + Symmetric or asymmetric encryption of the private key (CMS + EnvelopedData, Content-Format 280) SHOULD be supported for + deployments where end-to-end encryption is needed between the client + and a server. Such cases could include architectures where an entity + between the client and the CA terminates the DTLS connection + (Registrar in Figure 5). Though [RFC7030] strongly recommends that + clients request the use of CMS encryption on top of the TLS channel's + protection, this document does not make such a recommendation; CMS + encryption can still be used when mandated by the use case. + +4.9. Renewal of CA Certificates + + An EST-coaps client that has an estimate of the current time + (internally, or via a time synchronization mechanism) SHOULD consider + the validity time of its trust anchor CA(s) and MAY begin requesting + new trust anchor certificate(s) using a /crts request when a CA has + 50% of its validity period (notAfter minus notBefore) remaining. + + A client without access to accurate time cannot determine whether + trust anchor CA(s) have expired and SHOULD poll periodically for new + trust anchor certificate(s) using a /crts request at an interval of + approximately one month. + + An EST-coaps server SHOULD include the CoAP ETag Option ([RFC7252], + Section 5.10.6) in every response to a /crts request, to enable + clients to perform low-overhead validation of whether their trust + anchor CA is still current. The EST-coaps client SHOULD store the + ETag from a /crts response and SHOULD use this value in an ETag + Option in its next GET /crts request. + +4.10. Re-enrollment Procedure + + For simple re-enrollment, the EST-coaps client MUST support the + following procedure. During this procedure the EST-coaps server MAY + re-enroll the client into a new domain or into a new sub-CA within a + larger domain. + + 1. The client connects with DTLS to the EST-coaps server and + authenticates with its present domain certificate as usual. The + EST-coaps server authenticates itself with its Registration + Authority (RA) certificate that is currently trusted by the + client, i.e., it chains to a trust anchor CA stored in the + client's Explicit Trust Anchor database. The client verifies + that the server is an RA of the domain as required by + Section 3.6.1 of [RFC7030] before proceeding. + + 2. The client performs the simple re-enrollment request (/sren) and, + upon success, obtains a new certificate. + + 3. The client verifies the new certificate against its Explicit + Trust Anchor database. If the new certificate chains + successfully to a trust anchor, the client MAY skip retrieving + the current CA certificates using a /crts request. If it does + not chain successfully, the client MUST retrieve the new domain + trust anchors using a /crts request. + + 4. If the client retrieved new trust anchor(s) in step 3, it MUST + verify that the new certificate obtained in step 2 chains to the + new trust anchor(s). If verification succeeds, the client + stores the new trust anchor(s) in its Explicit Trust Anchor + database, accepts the new certificate, and stops using its prior + certificate. If verification fails, the client MUST NOT update + its certificate, MUST NOT update its Explicit Trust Anchor + database, and MUST abort the re-enrollment procedure. + + Even when the client skips the /crts request in step 3, it SHOULD + still support renewal of trust anchors as specified in Section 4.9. + +4.10.1. Change of Domain Trust Anchor(s) + + Domain trust anchor(s) may change over time due to relocation of the + client to a new domain or subdomain, or due to a key update of a + trust anchor as described in [RFC4210], Section 4.4. From the + client's viewpoint, a trust anchor change is handled during EST-coaps + re-enrollment: a change of domain CA requires devices operating under + the old domain CA to acquire a new certificate issued by the new + domain CA. + + The mechanism described in [RFC7030], Section 4.1.3 and [RFC4210], + Section 4.4 for root CA key update requires four certificates: + OldWithOld, OldWithNew, NewWithOld, and NewWithNew. The OldWithOld + certificate is already stored in the client's Explicit Trust Anchor + database. The other certificates are provided to the client in a + /crts response during the re-enrollment procedure of Section 4.10. + +5. HTTPS-CoAPS Registrar + + In real-world deployments, the EST server will not always reside + within the CoAP boundary. The EST server can exist outside the + constrained network, in which case it will support TLS/HTTP instead + of CoAPS. In such environments, EST-coaps is used by the client + within the CoAP boundary and TLS is used to transport the EST + messages outside the CoAP boundary. A Registrar at the edge is + required to operate between the CoAP environment and the external + HTTP network as shown in Figure 5. + + Constrained Network + .------. .----------------------------. + | CA | |.--------------------------.| + '------' || || + | || || + .------. HTTP .------------------. CoAPS .-----------. || + | EST |<------->|EST-coaps-to-HTTPS|<------->| EST Client| || + |Server|over TLS | Registrar | '-----------' || + '------' '------------------' || + || || + |'--------------------------'| + '----------------------------' + + Figure 5: EST-coaps-to-HTTPS Registrar at the CoAP Boundary + + The EST-coaps-to-HTTPS Registrar MUST terminate EST-coaps downstream + and initiate EST connections over TLS upstream. The Registrar MUST + authenticate and optionally authorize the client requests while it + MUST be authenticated by the EST server or CA. The trust + relationship between the Registrar and the EST server SHOULD be pre- + established for the Registrar to proxy these connections on behalf of + various clients. + + When enforcing Proof-of-Possession (POP) linking, the tls-unique or + tls-exporter value of the session for DTLS 1.2 and DTLS 1.3, + respectively, is used to prove that the private key corresponding to + the public key is in the possession of the client and was used to + establish the connection as explained in Section 3. The POP linking + information is lost between the EST-coaps client and the EST server + when a Registrar is present. The EST server becomes aware of the + presence of a Registrar from its TLS client certificate that includes + the id-kp-cmcRA extended key usage (EKU) extension [RFC6402]. As + explained in Section 3.7 of [RFC7030], the "EST server SHOULD apply + authorization policy consistent with an RA client ... the EST server + could be configured to accept POP linking information that does not + match the current TLS session because the authenticated EST client RA + has verified this information when acting as an EST server". + + Table 1 contains the URI mappings between EST-coaps and EST that the + Registrar MUST adhere to. Section 4.5 of this specification and + Section 7 of [RFC8075] define the mappings between EST-coaps and HTTP + response codes that determine how the Registrar MUST translate CoAP + response codes from/to HTTP status codes. The mapping from CoAP + Content-Format to HTTP Content-Type is defined in Section 8.1. + Additionally, a conversion from CBOR major type 2 to Base64 encoding + MUST take place at the Registrar. If CMS end-to-end encryption is + employed for the private key, the encrypted CMS EnvelopedData blob + MUST be converted at the Registrar to binary CBOR type 2 downstream + to the client. This is a format conversion that does not require + decryption of the CMS EnvelopedData. + + A deviation from the mappings in Table 1 could take place if clients + that leverage server-side key generation preferred for the enrolled + keys to be generated by the Registrar in the case the CA does not + support server-side key generation. Such a Registrar is responsible + for generating a new CSR signed by a new key that will be returned to + the client along with the certificate from the CA. In these cases, + the Registrar MUST use random number generation with proper entropy. + + Due to fragmentation of large messages into blocks, an EST-coaps-to- + HTTP Registrar MUST reassemble the blocks before translating the + binary content to Base64 and consecutively relay the message + upstream. + + The EST-coaps-to-HTTP Registrar MUST support resource discovery + according to the rules in Section 4.1. + +6. Parameters + + This section addresses transmission parameters described in Sections + 4.7 and 4.8 of [RFC7252]. EST does not impose any unique values on + the CoAP parameters in [RFC7252], but the setting of the CoAP + parameter values may have consequence for the setting of the EST + parameter values. + + Implementations should follow the default CoAP configuration + parameters [RFC7252]. However, depending on the implementation + scenario, retransmissions and timeouts can also occur on other + networking layers, governed by other configuration parameters. When + a change in a server parameter has taken place, the parameter values + in the communicating endpoints MUST be adjusted as necessary. + Examples of how parameters could be adjusted include higher-layer + congestion protocols, provisioning agents, and configurations + included in firmware updates. + + Some further comments about some specific parameters, mainly from + Table 2 in [RFC7252], include the following: + + NSTART: A parameter that controls the number of simultaneous + outstanding interactions that a client maintains to a given + server. An EST-coaps client is expected to control at most one + interaction with a given server, which is the default NSTART value + defined in [RFC7252]. + + DEFAULT_LEISURE: A setting that is only relevant in multicast + scenarios and is outside the scope of EST-coaps. + + PROBING_RATE: A parameter that specifies the rate of resending Non- + confirmable messages. In the rare situations that Non-confirmable + messages are used, the default PROBING_RATE value defined in + [RFC7252] applies. + + Finally, the Table 3 parameters in [RFC7252] are mainly derived from + Table 2. Directly changing parameters on one table would affect + parameters on the other. + +7. Deployment Limitations + + Although EST-coaps paves the way for the utilization of EST by + constrained devices in constrained networks, some classes of devices + [RFC7228] will not have enough resources to handle the payloads that + come with EST-coaps. The specification of EST-coaps is intended to + ensure that EST works for networks of constrained devices that choose + to limit their communications stack to DTLS/CoAP. It is up to the + network designer to decide which devices execute the EST protocol and + which do not. + +8. IANA Considerations + +8.1. Content-Formats Registry + + IANA has registered the following Content-Formats given in Table 5 in + the "CoAP Content-Formats" subregistry within the "CoRE Parameters" + registry [CORE-PARAMS]. These have been registered in the IETF + Review or IESG Approval range (256-9999). + + +=================================+=====+====================+ + | Media Type | ID | Reference | + +=================================+=====+====================+ + | application/pkcs7-mime; smime- | 280 | [RFC7030] | + | type=server-generated-key | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkcs7-mime; smime- | 281 | [RFC8551] RFC 9148 | + | type=certs-only | | | + +---------------------------------+-----+--------------------+ + | application/pkcs8 | 284 | [RFC5958] | + | | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/csrattrs | 285 | [RFC7030] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkcs10 | 286 | [RFC5967] | + | | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkix-cert | 287 | [RFC2585] RFC 9148 | + +---------------------------------+-----+--------------------+ + + Table 5: New CoAP Content-Formats + +8.2. Resource Type Registry + + IANA has registered the following Resource Type (rt=) Link Target + Attributes given in Table 6 in the "Resource Type (rt=) Link Target + Attribute Values" subregistry under the "Constrained RESTful + Environments (CoRE) Parameters" registry. + + +==============+===================================+===========+ + | Value | Description | Reference | + +==============+===================================+===========+ + | ace.est | Base resource of all EST-coaps | This doc | + | | resources | | + +--------------+-----------------------------------+-----------+ + | ace.est.crts | This resource depicts the support | RFC 9148 | + | | of EST GET cacerts. | | + +--------------+-----------------------------------+-----------+ + | ace.est.sen | This resource depicts the support | RFC 9148 | + | | of EST simple enroll. | | + +--------------+-----------------------------------+-----------+ + | ace.est.sren | This resource depicts the support | RFC 9148 | + | | of EST simple reenroll. | | + +--------------+-----------------------------------+-----------+ + | ace.est.att | This resource depicts the support | RFC 9148 | + | | of EST GET CSR attributes. | | + +--------------+-----------------------------------+-----------+ + | ace.est.skg | This resource depicts the support | RFC 9148 | + | | of EST server-side key generation | | + | | with the returned certificate in | | + | | a PKCS #7 container. | | + +--------------+-----------------------------------+-----------+ + | ace.est.skc | This resource depicts the support | RFC 9148 | + | | of EST server-side key generation | | + | | with the returned certificate in | | + | | application/pkix-cert format. | | + +--------------+-----------------------------------+-----------+ + + Table 6: New Resource Type (rt=) Link Target Attributes + +8.3. Well-Known URIs Registry + + IANA has added an additional reference to the est URI in the "Well- + Known URIs" registry: + + URI Suffix: est + + Change Controller: IETF + + References: [RFC7030] RFC 9148 + + Status: permanent + + Related Information: + + Date Registered: 2013-08-16 + + Date Modified: 2020-04-29 + +9. Security Considerations + +9.1. EST Server Considerations + + The security considerations in Section 6 of [RFC7030] are only + partially valid for the purposes of this document. As HTTP Basic + Authentication is not supported, the considerations expressed for + using passwords do not apply. The other portions of the security + considerations in [RFC7030] continue to apply. + + Modern security protocols require random numbers to be available + during the protocol run, for example, for nonces and ephemeral (EC) + Diffie-Hellman key generation. This capability to generate random + numbers is also needed when the constrained device generates the + private key (that corresponds to the public key enrolled in the CSR). + When server-side key generation is used, the constrained device + depends on the server to generate the private key randomly, but it + still needs locally generated random numbers for use in security + protocols, as explained in Section 12 of [RFC7925]. Additionally, + the transport of keys generated at the server is inherently risky. + For those deploying server-side key generation, analysis SHOULD be + done to establish whether server-side key generation increases or + decreases the probability of digital identity theft. + + It is important to note that, as pointed out in [PsQs], sources + contributing to the randomness pool used to generate random numbers + on laptops or desktop PCs, such as mouse movement, timing of + keystrokes, or air turbulence on the movement of hard drive heads, + are not available on many constrained devices. Other sources have to + be used or dedicated hardware has to be added. Selecting hardware + for an IoT device that is capable of producing high-quality random + numbers is therefore important [RSA-FACT]. + + As discussed in Section 6 of [RFC7030], it is + + | RECOMMENDED that the Implicit Trust Anchor database used for EST + | server authentication be carefully managed to reduce the chance of + | a third-party CA with poor certification practices from being + | trusted. Disabling the Implicit Trust Anchor database after + | successfully receiving the Distribution of CA certificates + | response ([RFC7030], Section 6) limits any vulnerability to the + | first TLS exchange. + + Alternatively, in a case where a /sen request immediately follows a + /crts, a client MAY choose to keep the connection authenticated by + the Implicit TA open for efficiency reasons (Section 3). A client + that interleaves EST-coaps /crts request with other requests in the + same DTLS connection SHOULD revalidate the server certificate chain + against the updated Explicit TA from the /crts response before + proceeding with the subsequent requests. If the server certificate + chain does not authenticate against the database, the client SHOULD + close the connection without completing the rest of the requests. + The updated Explicit TA MUST continue to be used in new DTLS + connections. + + In cases where the Initial Device Identifier (IDevID) used to + authenticate the client is expired, the server MAY still authenticate + the client because IDevIDs are expected to live as long as the device + itself (Section 3). In such occasions, checking the certificate + revocation status or authorizing the client using another method is + important for the server to raise its confidence that the client can + be trusted. + + In accordance with [RFC7030], TLS cipher suites that include + "_EXPORT_" and "_DES_" in their names MUST NOT be used. More + recommendations for secure use of TLS and DTLS are included in + [BCP195]. + + As described in Certificate Management over CMS (CMC), Section 6.7 of + [RFC5272], "For keys that can be used as signature keys, signing the + certification request with the private key serves as a POP on that + key pair". In (D)TLS 1.2, the inclusion of tls-unique in the + certificate request links the proof-of-possession to the (D)TLS + proof-of-identity. This implies but does not prove that only the + authenticated client currently has access to the private key. + + What's more, CMC POP linking uses tls-unique as it is defined in + [RFC5929]. The 3SHAKE attack [TRIPLESHAKE] poses a risk by allowing + an on-path active attacker to leverage session resumption and + renegotiation to inject itself between a client and server even when + channel binding is in use. Implementers should use the Extended + Master Secret Extension in DTLS [RFC7627] to prevent such attacks. + In the context of this specification, an attacker could invalidate + the purpose of the POP linking challengePassword in the client + request by resuming an EST-coaps connection. Even though the + practical risk of such an attack to EST-coaps is not devastating, we + would rather use a more secure channel-binding mechanism. In this + specification, we still depend on the tls-unique mechanism defined in + [RFC5929] for DTLS 1.2 because a 3SHAKE attack does not expose + messages exchanged with EST-coaps. But for DTLS 1.3, + [TLS13-CHANNEL-BINDINGS] is used instead to derive a 32-byte tls- + exporter binding in place of the tls-unique value in the CSR. That + would alleviate the risks from the 3SHAKE attack [TRIPLESHAKE]. + + Interpreters of ASN.1 structures should be aware of the use of + invalid ASN.1 length fields and should take appropriate measures to + guard against buffer overflows, stack overruns in particular, and + malicious content in general. + +9.2. HTTPS-CoAPS Registrar Considerations + + The Registrar proposed in Section 5 must be deployed with care and + only when direct client-server connections are not possible. When + POP linking is used, the Registrar terminating the DTLS connection + establishes a new TLS connection with the upstream CA. Thus, it is + impossible for POP linking to be enforced end to end for the EST + transaction. The EST server could be configured to accept POP + linking information that does not match the current TLS session + because the authenticated EST Registrar is assumed to have verified + POP linking downstream to the client. + + The introduction of an EST-coaps-to-HTTP Registrar assumes the client + can authenticate the Registrar using its implicit or explicit TA + database. It also assumes the Registrar has a trust relationship + with the upstream EST server in order to act on behalf of the + clients. When a client uses the Implicit TA database for certificate + validation, it SHOULD confirm if the server is acting as an RA by the + presence of the id-kp-cmcRA EKU [RFC6402] in the server certificate. + + In a server-side key generation case, if no end-to-end encryption is + used, the Registrar may be able see the private key as it acts as a + man in the middle. Thus, the client puts its trust on the Registrar + not exposing the private key. + + Clients that leverage server-side key generation without end-to-end + encryption of the private key (Section 4.8) have no knowledge as to + whether the Registrar will be generating the private key and + enrolling the certificates with the CA or if the CA will be + responsible for generating the key. In such cases, the existence of + a Registrar requires the client to put its trust on the Registrar + when it is generating the private key. + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC2585] Housley, R. and P. Hoffman, "Internet X.509 Public Key + Infrastructure Operational Protocols: FTP and HTTP", + RFC 2585, DOI 10.17487/RFC2585, May 1999, + . + + [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security + (TLS) Protocol Version 1.2", RFC 5246, + DOI 10.17487/RFC5246, August 2008, + . + + [RFC5958] Turner, S., "Asymmetric Key Packages", RFC 5958, + DOI 10.17487/RFC5958, August 2010, + . + + [RFC5967] Turner, S., "The application/pkcs10 Media Type", RFC 5967, + DOI 10.17487/RFC5967, August 2010, + . + + [RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer + Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347, + January 2012, . + + [RFC6690] Shelby, Z., "Constrained RESTful Environments (CoRE) Link + Format", RFC 6690, DOI 10.17487/RFC6690, August 2012, + . + + [RFC7030] Pritikin, M., Ed., Yee, P., Ed., and D. Harkins, Ed., + "Enrollment over Secure Transport", RFC 7030, + DOI 10.17487/RFC7030, October 2013, + . + + [RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained + Application Protocol (CoAP)", RFC 7252, + DOI 10.17487/RFC7252, June 2014, + . + + [RFC7925] Tschofenig, H., Ed. and T. Fossati, "Transport Layer + Security (TLS) / Datagram Transport Layer Security (DTLS) + Profiles for the Internet of Things", RFC 7925, + DOI 10.17487/RFC7925, July 2016, + . + + [RFC7959] Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in + the Constrained Application Protocol (CoAP)", RFC 7959, + DOI 10.17487/RFC7959, August 2016, + . + + [RFC8075] Castellani, A., Loreto, S., Rahman, A., Fossati, T., and + E. Dijk, "Guidelines for Mapping Implementations: HTTP to + the Constrained Application Protocol (CoAP)", RFC 8075, + DOI 10.17487/RFC8075, February 2017, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + + [RFC8422] Nir, Y., Josefsson, S., and M. Pegourie-Gonnard, "Elliptic + Curve Cryptography (ECC) Cipher Suites for Transport Layer + Security (TLS) Versions 1.2 and Earlier", RFC 8422, + DOI 10.17487/RFC8422, August 2018, + . + + [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol + Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, + . + + [RFC8551] Schaad, J., Ramsdell, B., and S. Turner, "Secure/ + Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 + Message Specification", RFC 8551, DOI 10.17487/RFC8551, + April 2019, . + + [RFC8710] Fossati, T., Hartke, K., and C. Bormann, "Multipart + Content-Format for the Constrained Application Protocol + (CoAP)", RFC 8710, DOI 10.17487/RFC8710, February 2020, + . + + [RFC9147] Rescorla, E., Tschofenig, H., and N. Modadugu, "The + Datagram Transport Layer Security (DTLS) Protocol Version + 1.3", RFC 9147, DOI 10.17487/RFC9147, April 2022, + . + +10.2. Informative References + + [BCP195] Sheffer, Y., Holz, R., and P. Saint-Andre, + "Recommendations for Secure Use of Transport Layer + Security (TLS) and Datagram Transport Layer Security + (DTLS)", BCP 195, RFC 7525, May 2015. + + + + [CORE-PARAMS] + IANA, "Constrained RESTful Environments (CoRE) + Parameters", + . + + [IEEE802.15.4] + IEEE, "IEEE 802.15.4-2020 - IEEE Standard for Low-Rate + Wireless Networks", May 2020. + + [IEEE802.1AR] + IEEE, "IEEE Standard for Local and metropolitan area + networks - Secure Device Identity", December 2009. + + [PKI-GUIDE] + Moskowitz, R., Birkholz, H., Xia, L., and M. Richardson, + "Guide for building an ECC pki", Work in Progress, + Internet-Draft, draft-moskowitz-ecdsa-pki-10, 31 January + 2021, . + + [PsQs] Heninger, N., Durumeric, Z., Wustrow, E., and J. Alex + Halderman, "Mining Your Ps and Qs: Detection of Widespread + Weak Keys in Network Devices", USENIX Security Symposium + 2012, ISBN 978-931971-95-9, August 2012. + + [RFC4919] Kushalnagar, N., Montenegro, G., and C. Schumacher, "IPv6 + over Low-Power Wireless Personal Area Networks (6LoWPANs): + Overview, Assumptions, Problem Statement, and Goals", + RFC 4919, DOI 10.17487/RFC4919, August 2007, + . + + [RFC5272] Schaad, J. and M. Myers, "Certificate Management over CMS + (CMC)", RFC 5272, DOI 10.17487/RFC5272, June 2008, + . + + [RFC5929] Altman, J., Williams, N., and L. Zhu, "Channel Bindings + for TLS", RFC 5929, DOI 10.17487/RFC5929, July 2010, + . + + [RFC6402] Schaad, J., "Certificate Management over CMS (CMC) + Updates", RFC 6402, DOI 10.17487/RFC6402, November 2011, + . + + [RFC7228] Bormann, C., Ersue, M., and A. Keranen, "Terminology for + Constrained-Node Networks", RFC 7228, + DOI 10.17487/RFC7228, May 2014, + . + + [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer + Protocol (HTTP/1.1): Message Syntax and Routing", + RFC 7230, DOI 10.17487/RFC7230, June 2014, + . + + [RFC7251] McGrew, D., Bailey, D., Campagna, M., and R. Dugal, "AES- + CCM Elliptic Curve Cryptography (ECC) Cipher Suites for + TLS", RFC 7251, DOI 10.17487/RFC7251, June 2014, + . + + [RFC7299] Housley, R., "Object Identifier Registry for the PKIX + Working Group", RFC 7299, DOI 10.17487/RFC7299, July 2014, + . + + [RFC7627] Bhargavan, K., Ed., Delignat-Lavaud, A., Pironti, A., + Langley, A., and M. Ray, "Transport Layer Security (TLS) + Session Hash and Extended Master Secret Extension", + RFC 7627, DOI 10.17487/RFC7627, September 2015, + . + + [RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves + for Security", RFC 7748, DOI 10.17487/RFC7748, January + 2016, . + + [RFC9146] Rescorla, E., Ed., Tschofenig, H., Ed., Fossati, T., and + A. Kraus, "Connection Identifier for DTLS 1.2", RFC 9146, + DOI 10.17487/RFC9146, March 2022, + . + + [RSA-FACT] Bernstein, D., Chang, Y., Cheng, C., Chou, L., Heninger, + N., Lange, T., and N. Someren, "Factoring RSA keys from + certified smart cards: Coppersmith in the wild", Advances + in Cryptology - ASIACRYPT 2013, August 2013. + + [TLS13-CHANNEL-BINDINGS] + Whited, S., "Channel Bindings for TLS 1.3", Work in + Progress, Internet-Draft, draft-ietf-kitten-tls-channel- + bindings-for-tls13-15, 4 March 2022, + . + + [TRIPLESHAKE] + Bhargavan, B., Delignat-Lavaud, A., Fournet, C., Pironti, + A., and P. Strub, "Triple Handshakes and Cookie Cutters: + Breaking and Fixing Authentication over TLS", + ISBN 978-1-4799-4686-0, DOI 10.1109/SP.2014.14, May 2014, + . + +Appendix A. EST Messages to EST-coaps + + This section shows similar examples to the ones presented in + Appendix A of [RFC7030]. The payloads in the examples are the hex- + encoded binary, generated with 'xxd -p', of the PKI certificates + created following [PKI-GUIDE]. Hex is used for visualization + purposes because a binary representation cannot be rendered well in + text. The hexadecimal representations would not be transported in + hex, but in binary. The payloads are shown unencrypted. In + practice, the message content would be transferred over an encrypted + DTLS channel. + + The certificate responses included in the examples contain Content- + Format 281 (application/pkcs7). If the client had requested Content- + Format 287 (application/pkix-cert), the server would respond with a + single DER binary certificate. That certificate would be in a + multipart-core container specifically in the case of a response to a + /est/skc query. + + These examples assume a short resource path of "/est". Even though + omitted from the examples for brevity, before making the EST-coaps + requests, a client would learn about the server supported EST-coaps + resources with a GET request for /.well-known/core?rt=ace.est* as + explained in Section 4.1. + + The corresponding CoAP headers are only shown in Appendix A.1. + Creating CoAP headers is assumed to be generally understood. + + The message content is presented in plain text in Appendix C. + +A.1. cacerts + + In EST-coaps, a cacerts message can be the following: + + GET example.com:9085/est/crts + (Accept: 281) + + The corresponding CoAP header fields are shown below. The use of + block and DTLS are shown in Appendix B. + + Ver = 1 + T = 0 (CON) + Code = 0x01 (0.01 is GET) + Token = 0x9a (client generated) + Options + Option (Uri-Host) + Option Delta = 0x3 (option# 3) + Option Length = 0xB + Option Value = "example.com" + Option (Uri-Port) + Option Delta = 0x4 (option# 3+4=7) + Option Length = 0x2 + Option Value = 9085 + Option (Uri-Path) + Option Delta = 0x4 (option# 7+4=11) + Option Length = 0x3 + Option Value = "est" + Option (Uri-Path) + Option Delta = 0x0 (option# 11+0=11) + Option Length = 0x4 + Option Value = "crts" + Option (Accept) + Option Delta = 0x6 (option# 11+6=17) + Option Length = 0x2 + Option Value = 281 + Payload = [Empty] + + As specified in Section 5.10.1 of [RFC7252], the Uri-Host and Uri- + Port Options can be omitted if they coincide with the transport + protocol destination address and port, respectively. + + A 2.05 Content response with a cert in EST-coaps will then be the + following: + + 2.05 Content (Content-Format: 281) + {payload with certificate in binary format} + + With the following CoAP fields: + + Ver = 1 + T = 2 (ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option (Content-Format) + Option Delta = 0xC (option# 12) + Option Length = 0x2 + Option Value = 281 + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 3082027a06092a864886f70d010702a082026b308202670201013100300b + 06092a864886f70d010701a082024d30820249308201efa0030201020208 + 0b8bb0fe604f6a1e300a06082a8648ce3d0403023067310b300906035504 + 0613025553310b300906035504080c024341310b300906035504070c024c + 4131143012060355040a0c0b4578616d706c6520496e6331163014060355 + 040b0c0d63657274696669636174696f6e3110300e06035504030c07526f + 6f74204341301e170d3139303133313131323730335a170d333930313236 + 3131323730335a3067310b3009060355040613025553310b300906035504 + 080c024341310b300906035504070c024c4131143012060355040a0c0b45 + 78616d706c6520496e6331163014060355040b0c0d636572746966696361 + 74696f6e3110300e06035504030c07526f6f742043413059301306072a86 + 48ce3d020106082a8648ce3d030107034200040c1b1e82ba8cc72680973f + 97edb8a0c72ab0d405f05d4fe29b997a14ccce89008313d09666b6ce375c + 595fcc8e37f8e4354497011be90e56794bd91ad951ab45a3818430818130 + 1d0603551d0e041604141df1208944d77b5f1d9dcb51ee244a523f3ef5de + 301f0603551d230418301680141df1208944d77b5f1d9dcb51ee244a523f + 3ef5de300f0603551d130101ff040530030101ff300e0603551d0f0101ff + 040403020106301e0603551d110417301581136365727469667940657861 + 6d706c652e636f6d300a06082a8648ce3d040302034800304502202b891d + d411d07a6d6f621947635ba4c43165296b3f633726f02e51ecf464bd4002 + 2100b4be8a80d08675f041fbc719acf3b39dedc85dc92b3035868cb2daa8 + f05db196a1003100 + + The payload is shown in plain text in Appendix C.1. + +A.2. enroll / reenroll + + During the (re-)enroll exchange, the EST-coaps client uses a CSR + (Content-Format 286) request in the POST request payload. The Accept + Option tells the server that the client is expecting Content-Format + 281 (PKCS #7) in the response. As shown in Appendix C.2, the CSR + contains a challengePassword, which is used for POP linking + (Section 3). + + POST [2001:db8::2:321]:61616/est/sen + (Token: 0x45) + (Accept: 281) + (Content-Format: 286) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3082018b30820131020100305c310b3009060355040613025553310b3009 + 06035504080c024341310b300906035504070c024c413114301206035504 + 0a0c0b6578616d706c6520496e63310c300a060355040b0c03496f54310f + 300d060355040513065774313233343059301306072a8648ce3d02010608 + 2a8648ce3d03010703420004c8b421f11c25e47e3ac57123bf2d9fdc494f + 028bc351cc80c03f150bf50cff958d75419d81a6a245dffae790be95cf75 + f602f9152618f816a2b23b5638e59fd9a073303406092a864886f70d0109 + 0731270c2576437630292a264a4b4a3bc3a2c280c2992f3e3c2e2c3d6b6e + 7634332323403d204e787e60303b06092a864886f70d01090e312e302c30 + 2a0603551d1104233021a01f06082b06010505070804a013301106092b06 + 010401b43b0a01040401020304300a06082a8648ce3d0403020348003045 + 02210092563a546463bd9ecff170d0fd1f2ef0d3d012160e5ee90cffedab + ec9b9a38920220179f10a3436109051abad17590a09bc87c4dce5453a6fc + 1135a1e84eed754377 + + After verification of the CSR by the server, a 2.04 Changed response + with the issued certificate will be returned to the client. + + 2.04 Changed + (Token: 0x45) + (Content-Format: 281) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3082026e06092a864886f70d010702a082025f3082025b0201013100300b + 06092a864886f70d010701a08202413082023d308201e2a0030201020208 + 7e7661d7b54e4632300a06082a8648ce3d040302305d310b300906035504 + 0613025553310b300906035504080c02434131143012060355040a0c0b45 + 78616d706c6520496e6331163014060355040b0c0d636572746966696361 + 74696f6e3113301106035504030c0a3830322e3141522043413020170d31 + 39303133313131323931365a180f39393939313233313233353935395a30 + 5c310b3009060355040613025553310b300906035504080c024341310b30 + 0906035504070c024c4131143012060355040a0c0b6578616d706c652049 + 6e63310c300a060355040b0c03496f54310f300d06035504051306577431 + 3233343059301306072a8648ce3d020106082a8648ce3d03010703420004 + c8b421f11c25e47e3ac57123bf2d9fdc494f028bc351cc80c03f150bf50c + ff958d75419d81a6a245dffae790be95cf75f602f9152618f816a2b23b56 + 38e59fd9a3818a30818730090603551d1304023000301d0603551d0e0416 + 041496600d8716bf7fd0e752d0ac760777ad665d02a0301f0603551d2304 + 183016801468d16551f951bfc82a431d0d9f08bc2d205b1160300e060355 + 1d0f0101ff0404030205a0302a0603551d1104233021a01f06082b060105 + 05070804a013301106092b06010401b43b0a01040401020304300a06082a + 8648ce3d0403020349003046022100c0d81996d2507d693f3c48eaa5ee94 + 91bda6db214099d98117c63b361374cd86022100a774989f4c321a5cf25d + 832a4d336a08ad67df20f1506421188a0ade6d349236a1003100 + + The request and response is shown in plain text in Appendix C.2. + +A.3. serverkeygen + + In a serverkeygen exchange, the CoAP POST request looks like the + following: + + POST 192.0.2.1:8085/est/skg + (Token: 0xa5) + (Accept: 62) + (Content-Format: 286) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3081d03078020100301631143012060355040a0c0b736b67206578616d70 + 6c653059301306072a8648ce3d020106082a8648ce3d03010703420004c8 + b421f11c25e47e3ac57123bf2d9fdc494f028bc351cc80c03f150bf50cff + 958d75419d81a6a245dffae790be95cf75f602f9152618f816a2b23b5638 + e59fd9a000300a06082a8648ce3d040302034800304502207c553981b1fe + 349249d8a3f50a0346336b7dfaa099cf74e1ec7a37a0a760485902210084 + 79295398774b2ff8e7e82abb0c17eaef344a5088fa69fd63ee611850c34b + 0a + + The response would follow [RFC8710] and could look like the + following: + + 2.04 Changed + (Token: 0xa5) + (Content-Format: 62) + + [ The hexadecimal representations below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 84 # array(4) + 19 011C # unsigned(284) + 58 8A # bytes(138) + 308187020100301306072a8648ce3d020106082a8648ce3d030107046d30 + 6b020101042061336a86ac6e7af4a96f632830ad4e6aa0837679206094d7 + 679a01ca8c6f0c37a14403420004c8b421f11c25e47e3ac57123bf2d9fdc + 494f028bc351cc80c03f150bf50cff958d75419d81a6a245dffae790be95 + cf75f602f9152618f816a2b23b5638e59fd9 + 19 0119 # unsigned(281) + 59 01D3 # bytes(467) + 308201cf06092a864886f70d010702a08201c0308201bc0201013100300b + 06092a864886f70d010701a08201a23082019e30820144a0030201020209 + 00b3313e8f3fc9538e300a06082a8648ce3d040302301631143012060355 + 040a0c0b736b67206578616d706c65301e170d3139303930343037343430 + 335a170d3339303833303037343430335a301631143012060355040a0c0b + 736b67206578616d706c653059301306072a8648ce3d020106082a8648ce + 3d03010703420004c8b421f11c25e47e3ac57123bf2d9fdc494f028bc351 + cc80c03f150bf50cff958d75419d81a6a245dffae790be95cf75f602f915 + 2618f816a2b23b5638e59fd9a37b307930090603551d1304023000302c06 + 096086480186f842010d041f161d4f70656e53534c2047656e6572617465 + 64204365727469666963617465301d0603551d0e0416041496600d8716bf + 7fd0e752d0ac760777ad665d02a0301f0603551d2304183016801496600d + 8716bf7fd0e752d0ac760777ad665d02a0300a06082a8648ce3d04030203 + 48003045022100e95bfa25a08976652246f2d96143da39fce0dc4c9b26b9 + cce1f24164cc2b12b602201351fd8eea65764e3459d324e4345ff5b2a915 + 38c04976111796b3698bf6379ca1003100 + + The private key in the response above is without CMS EnvelopedData + and has no additional encryption beyond DTLS (Section 4.8). + + The request and response is shown in plain text in Appendix C.3. + +A.4. csrattrs + + The following is a csrattrs exchange: + + REQ: + GET example.com:61616/est/att + + RES: + 2.05 Content + (Content-Format: 285) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 307c06072b06010101011630220603883701311b131950617273652053455 + 420617320322e3939392e31206461746106092a864886f70d010907302c06 + 0388370231250603883703060388370413195061727365205345542061732 + 0322e3939392e32206461746106092b240303020801010b06096086480165 + 03040202 + + A 2.05 Content response should contain attributes that are relevant + for the authenticated client. This example is copied from + Appendix A.2 of [RFC7030], where the base64 representation is + replaced with a hexadecimal representation of the equivalent binary + format. The EST-coaps server returns attributes that the client can + ignore if they are unknown to the client. + +Appendix B. EST-coaps Block Message Examples + + Two examples are presented in this section: + + 1. A cacerts exchange shows the use of Block2 and the block headers. + + 2. An enroll exchange shows the Block1 and Block2 size negotiation + for request and response payloads. + + The payloads are shown unencrypted. In practice, the message + contents would be binary formatted and transferred over an encrypted + DTLS tunnel. The corresponding CoAP headers are only shown in + Appendix B.1. Creating CoAP headers is assumed to be generally + known. + +B.1. cacerts + + This section provides a detailed example of the messages using DTLS + and CoAP Option Block2. The example block length is taken as 64, + which gives an SZX value of 2. + + The following is an example of a cacerts exchange over DTLS. The + content length of the cacerts response in Appendix A.1 of [RFC7030] + contains 639 bytes in binary in this example. The CoAP message adds + around 10 bytes in this example, and the DTLS record around 29 bytes. + To avoid IP fragmentation, the CoAP Block Option is used and an MTU + of 127 is assumed to stay within one IEEE 802.15.4 packet. To stay + below the MTU of 127, the payload is split in 9 packets with a + payload of 64 bytes each, followed by a last tenth packet of 63 + bytes. The client sends an IPv6 packet containing a UDP datagram + with DTLS record protection that encapsulates a CoAP request 10 times + (one fragment of the request per block). The server returns an IPv6 + packet containing a UDP datagram with the DTLS record that + encapsulates the CoAP response. The CoAP request-response exchange + with block option is shown below. Block Option is shown in a + decomposed way (block-option:NUM/M/size) indicating the kind of Block + Option (2 in this case) followed by a colon, and then the block + number (NUM), the more bit (M = 0 in Block2 response means it is last + block), and block size with exponent (2^(SZX+4)) separated by + slashes. The Length 64 is used with SZX=2. The CoAP Request is sent + Confirmable (CON), and the Content-Format of the response, even + though not shown, is 281 (application/pkcs7-mime; smime-type=certs- + only). The transfer of the 10 blocks with partially filled block + NUM=9 is shown below. + + GET example.com:9085/est/crts (2:0/0/64) --> + <-- (2:0/1/64) 2.05 Content + GET example.com:9085/est/crts (2:1/0/64) --> + <-- (2:1/1/64) 2.05 Content + | + | + | + GET example.com:9085/est/crts (2:9/0/64) --> + <-- (2:9/0/64) 2.05 Content + + The header of the GET request looks like the following: + + Ver = 1 + T = 0 (CON) + Code = 0x01 (0.1 GET) + Token = 0x9a (client generated) + Options + Option (Uri-Host) + Option Delta = 0x3 (option# 3) + Option Length = 0xB + Option Value = "example.com" + Option (Uri-Port) + Option Delta = 0x4 (option# 3+4=7) + Option Length = 0x2 + Option Value = 9085 + Option (Uri-Path) + Option Delta = 0x4 (option# 7+4=11) + Option Length = 0x3 + Option Value = "est" + Option (Uri-Path)Uri-Path) + Option Delta = 0x0 (option# 11+0=11) + Option Length = 0x4 + Option Value = "crts" + Option (Accept) + Option Delta = 0x6 (option# 11+6=17) + Option Length = 0x2 + Option Value = 281 + Payload = [Empty] + + The Uri-Host and Uri-Port Options can be omitted if they coincide + with the transport protocol destination address and port, + respectively. Explicit Uri-Host and Uri-Port Options are typically + used when an endpoint hosts multiple virtual servers and uses the + Options to route the requests accordingly. + + To provide further details on the CoAP headers, the first two and the + last blocks are written out below. The header of the first Block2 + response looks like the following: + + Ver = 1 + T = 2 (ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option# 12+11=23 Block2) + Option Length = 0x1 + Option Value = 0x0A (block#=0, M=1, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 3082027b06092a864886f70d010702a082026c308202680201013100300b + 06092a864886f70d010701a082024e3082024a308201f0a0030201020209 + 009189bc + + The header of the second Block2 response looks like the following: + + Ver = 1 + T = 2 (means ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option 12+11=23 Block2) + Option Length = 0x1 + Option Value = 0x1A (block#=1, M=1, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + df9c99244b300a06082a8648ce3d0403023067310b300906035504061302 + 5553310b300906035504080c024341310b300906035504070c024c413114 + 30120603 + + The header of the tenth and final Block2 response looks like the + following: + + Ver = 1 + T = 2 (means ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option# 12+11=23 Block2 ) + Option Length = 0x1 + Option Value = 0x92 (block#=9, M=0, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 2ec0b4af52d46f3b7ecc9687ddf267bcec368f7b7f1353272f022047a28a + e5c7306163b3c3834bab3c103f743070594c089aaa0ac870cd13b902caa1 + 003100 + +B.2. enroll / reenroll + + In this example, the requested Block2 size of 256 bytes, required by + the client, is transferred to the server in the very first request + message. The block size of 256 is equal to (2^(SZX+4)), which gives + SZX=4. The notation for block numbering is the same as in + Appendix B.1. The header fields and the payload are omitted for + brevity. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(1:N1/0/256) + {CSR(frag# N1+1)}--> + | + ...........Immediate response ......... + | + <-- (ACK) (1:N1/0/256)(2:0/1/256)(2.04 Changed) + {Cert resp (frag# 1)} + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256)(2.04 Changed) + {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:321]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) + {Cert resp (frag# N2+1)} + + Figure 6: EST-coaps Enrollment with Multiple Blocks + + N1+1 blocks have been transferred from client to server, and N2+1 + blocks have been transferred from server to client. + +Appendix C. Message Content Breakdown + + This appendix presents the hexadecimal dumps of the binary payloads + in plain text shown in Appendix A. + +C.1. cacerts + + The cacerts response containing one root CA certificate is presented + in plain text in the following: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 831953162763987486 (0xb8bb0fe604f6a1e) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=CA, L=LA, O=Example Inc, + OU=certification, CN=Root CA + Validity + Not Before: Jan 31 11:27:03 2019 GMT + Not After : Jan 26 11:27:03 2039 GMT + Subject: C=US, ST=CA, L=LA, O=Example Inc, + OU=certification, CN=Root CA + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:0c:1b:1e:82:ba:8c:c7:26:80:97:3f:97:ed:b8: + a0:c7:2a:b0:d4:05:f0:5d:4f:e2:9b:99:7a:14:cc: + ce:89:00:83:13:d0:96:66:b6:ce:37:5c:59:5f:cc: + 8e:37:f8:e4:35:44:97:01:1b:e9:0e:56:79:4b:d9: + 1a:d9:51:ab:45 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + 1D:F1:20:89:44:D7:7B:5F:1D:9D:CB:51:EE:24:4A:52:3F:3E:F5:DE + X509v3 Authority Key Identifier: + keyid: + 1D:F1:20:89:44:D7:7B:5F:1D:9D:CB:51:EE:24:4A:52:3F:3E:F5:DE + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + email:certify@example.com + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:2b:89:1d:d4:11:d0:7a:6d:6f:62:19:47:63:5b: + a4:c4:31:65:29:6b:3f:63:37:26:f0:2e:51:ec:f4:64:bd:40: + 02:21:00:b4:be:8a:80:d0:86:75:f0:41:fb:c7:19:ac:f3:b3: + 9d:ed:c8:5d:c9:2b:30:35:86:8c:b2:da:a8:f0:5d:b1:96 + +C.2. enroll / reenroll + + The enrollment request is presented in plain text in the following: + + Certificate Request: + Data: + Version: 0 (0x0) + Subject: C=US, ST=CA, L=LA, O=example Inc, + OU=IoT/serialNumber=Wt1234 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Attributes: + challengePassword: <256-bit POP linking value> + Requested Extensions: + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:92:56:3a:54:64:63:bd:9e:cf:f1:70:d0:fd: + 1f:2e:f0:d3:d0:12:16:0e:5e:e9:0c:ff:ed:ab:ec:9b:9a:38: + 92:02:20:17:9f:10:a3:43:61:09:05:1a:ba:d1:75:90:a0:9b: + c8:7c:4d:ce:54:53:a6:fc:11:35:a1:e8:4e:ed:75:43:77 + + The CSR contains a challengePassword, which is used for POP linking + (Section 3). The CSR also contains an id-on-hardwareModuleName + hardware identifier to customize the returned certificate to the + requesting device (See [RFC7299] and [PKI-GUIDE]). + + The issued certificate presented in plain text in the following: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 9112578475118446130 (0x7e7661d7b54e4632) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=CA, O=Example Inc, + OU=certification, CN=802.1AR CA + Validity + Not Before: Jan 31 11:29:16 2019 GMT + Not After : Dec 31 23:59:59 9999 GMT + Subject: C=US, ST=CA, L=LA, O=example Inc, + OU=IoT/serialNumber=Wt1234 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + X509v3 Authority Key Identifier: + keyid: + 68:D1:65:51:F9:51:BF:C8:2A:43:1D:0D:9F:08:BC:2D:20:5B:11:60 + + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:c0:d8:19:96:d2:50:7d:69:3f:3c:48:ea:a5: + ee:94:91:bd:a6:db:21:40:99:d9:81:17:c6:3b:36:13:74:cd: + 86:02:21:00:a7:74:98:9f:4c:32:1a:5c:f2:5d:83:2a:4d:33: + 6a:08:ad:67:df:20:f1:50:64:21:18:8a:0a:de:6d:34:92:36 + +C.3. serverkeygen + + The following is the server-side key generation request presented in + plain text: + + Certificate Request: + Data: + Version: 0 (0x0) + Subject: O=skg example + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Attributes: + a0:00 + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:7c:55:39:81:b1:fe:34:92:49:d8:a3:f5:0a:03: + 46:33:6b:7d:fa:a0:99:cf:74:e1:ec:7a:37:a0:a7:60:48:59: + 02:21:00:84:79:29:53:98:77:4b:2f:f8:e7:e8:2a:bb:0c:17: + ea:ef:34:4a:50:88:fa:69:fd:63:ee:61:18:50:c3:4b:0a + + The following is the private key content of the server-side key + generation response presented in plain text: + + Private-Key: (256 bit) + priv: + 61:33:6a:86:ac:6e:7a:f4:a9:6f:63:28:30:ad:4e: + 6a:a0:83:76:79:20:60:94:d7:67:9a:01:ca:8c:6f: + 0c:37 + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + + The following is the certificate in the server-side key generation + response payload presented in plain text: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b3:31:3e:8f:3f:c9:53:8e + Signature Algorithm: ecdsa-with-SHA256 + Issuer: O=skg example + Validity + Not Before: Sep 4 07:44:03 2019 GMT + Not After : Aug 30 07:44:03 2039 GMT + Subject: O=skg example + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + X509v3 Authority Key Identifier: + keyid: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:e9:5b:fa:25:a0:89:76:65:22:46:f2:d9:61: + 43:da:39:fc:e0:dc:4c:9b:26:b9:cc:e1:f2:41:64:cc:2b:12: + b6:02:20:13:51:fd:8e:ea:65:76:4e:34:59:d3:24:e4:34:5f: + f5:b2:a9:15:38:c0:49:76:11:17:96:b3:69:8b:f6:37:9c + +Acknowledgements + + The authors are very grateful to Klaus Hartke for his detailed + explanations on the use of Block with DTLS and his support for the + Content-Format specification. The authors would like to thank Esko + Dijk and Michael Verschoor for the valuable discussions that helped + in shaping the solution. They would also like to thank Peter + Panburana for his feedback on technical details of the solution. + Constructive comments were received from Benjamin Kaduk, Eliot Lear, + Jim Schaad, Hannes Tschofenig, Julien Vermillard, John Manuel, Oliver + Pfaff, Pete Beal, and Carsten Bormann. + + Interop tests were done by Oliver Pfaff, Thomas Werner, Oskar + Camezind, Bjorn Elmers, and Joel Hoglund. + + Robert Moskowitz provided code to create the examples. + +Contributors + + Martin Furuhed contributed to the EST-coaps specification by + providing feedback based on the Nexus EST-over-CoAPS server + implementation that started in 2015. Sandeep Kumar kick-started this + specification and was instrumental in drawing attention to the + importance of the subject. + +Authors' Addresses + + Peter van der Stok + Consultant + Email: stokcons@bbhmail.nl + + + Panos Kampanakis + Cisco Systems + Email: pkampana@cisco.com + + + Michael C. Richardson + Sandelman Software Works + Email: mcr+ietf@sandelman.ca + URI: https://www.sandelman.ca/ + + + Shahid Raza + RISE Research Institutes of Sweden + Isafjordsgatan 22 + SE-16440 Kista, Stockholm + Sweden + Email: shahid.raza@ri.se diff --git a/docs/rfc9148-bis-source/rfc9148.txt b/docs/rfc9148-bis-source/rfc9148.txt new file mode 100644 index 0000000000..bc7da5cc1b --- /dev/null +++ b/docs/rfc9148-bis-source/rfc9148.txt @@ -0,0 +1,2108 @@ + + + + +Internet Engineering Task Force (IETF) P. van der Stok +Request for Comments: 9148 Consultant +Category: Standards Track P. Kampanakis +ISSN: 2070-1721 Cisco Systems + M. Richardson + SSW + S. Raza + RISE Research Institutes of Sweden + April 2022 + + +EST-coaps: Enrollment over Secure Transport with the Secure Constrained + Application Protocol + +Abstract + + Enrollment over Secure Transport (EST) is used as a certificate + provisioning protocol over HTTPS. Low-resource devices often use the + lightweight Constrained Application Protocol (CoAP) for message + exchanges. This document defines how to transport EST payloads over + secure CoAP (EST-coaps), which allows constrained devices to use + existing EST functionality for provisioning certificates. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + https://www.rfc-editor.org/info/rfc9148. + +Copyright Notice + + Copyright (c) 2022 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Revised BSD License text as described in Section 4.e of the + Trust Legal Provisions and are provided without warranty as described + in the Revised BSD License. + +Table of Contents + + 1. Introduction + 2. Terminology + 3. DTLS and Conformance to RFC 7925 Profiles + 4. Protocol Design + 4.1. Discovery and URIs + 4.2. Mandatory/Optional EST Functions + 4.3. Payload Formats + 4.4. Message Bindings + 4.5. CoAP Response Codes + 4.6. Message Fragmentation + 4.7. Delayed Responses + 4.8. Server-Side Key Generation + 5. HTTPS-CoAPS Registrar + 6. Parameters + 7. Deployment Limitations + 8. IANA Considerations + 8.1. Content-Formats Registry + 8.2. Resource Type Registry + 8.3. Well-Known URIs Registry + 9. Security Considerations + 9.1. EST Server Considerations + 9.2. HTTPS-CoAPS Registrar Considerations + 10. References + 10.1. Normative References + 10.2. Informative References + Appendix A. EST Messages to EST-coaps + A.1. cacerts + A.2. enroll / reenroll + A.3. serverkeygen + A.4. csrattrs + Appendix B. EST-coaps Block Message Examples + B.1. cacerts + B.2. enroll / reenroll + Appendix C. Message Content Breakdown + C.1. cacerts + C.2. enroll / reenroll + C.3. serverkeygen + Acknowledgements + Contributors + Authors' Addresses + +1. Introduction + + "Classical" Enrollment over Secure Transport (EST) [RFC7030] is used + for authenticated/authorized endpoint certificate enrollment (and + optionally key provisioning) through a Certification Authority (CA) + or Registration Authority (RA). EST transports messages over HTTPS. + + This document defines a new transport for EST based on the + Constrained Application Protocol (CoAP) since some Internet of Things + (IoT) devices use CoAP instead of HTTP. Therefore, this + specification utilizes DTLS [RFC6347] and CoAP [RFC7252] instead of + TLS [RFC8446] and HTTP [RFC7230]. + + EST responses can be relatively large, and for this reason, this + specification also uses CoAP Block-Wise Transfer [RFC7959] to offer a + fragmentation mechanism of EST messages at the CoAP layer. + + This document also profiles the use of EST to support certificate- + based client authentication only. Neither HTTP Basic nor Digest + authentication (as described in Section 3.2.3 of [RFC7030]) is + supported. + +2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + Many of the concepts in this document are taken from [RFC7030]. + Consequently, much text is directly traceable to [RFC7030]. + +3. DTLS and Conformance to RFC 7925 Profiles + + This section describes how EST-coaps conforms to the profiles of low- + resource devices described in [RFC7925]. EST-coaps can transport + certificates and private keys. Certificates are responses to + (re-)enrollment requests or requests for a trusted certificate list. + Private keys can be transported as responses to a server-side key + generation request as described in Section 4.4 of [RFC7030] (and + subsections) and discussed in Section 4.8 of this document. + + EST-coaps depends on a secure transport mechanism that secures the + exchanged CoAP messages. DTLS is one such secure protocol. No other + changes are necessary regarding the secure transport of EST messages. + + +------------------------------------------------+ + | EST request/response messages | + +------------------------------------------------+ + | CoAP for message transfer and signaling | + +------------------------------------------------+ + | Secure Transport | + +------------------------------------------------+ + + Figure 1: EST-coaps Protocol Layers + + In accordance with Sections 3.3 and 4.4 of [RFC7925], the mandatory + cipher suite for DTLS in EST-coaps is + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251]. Curve secp256r1 MUST + be supported [RFC8422]; this curve is equivalent to the NIST P-256 + curve. After the publication of [RFC7748], support for Curve25519 + will likely be required in the future by (D)TLS profiles for the + Internet of Things [RFC7925]. + + DTLS 1.2 implementations must use the Supported Elliptic Curves and + Supported Point Formats Extensions in [RFC8422]. Uncompressed point + format must also be supported. DTLS 1.3 [RFC9147] implementations + differ from DTLS 1.2 because they do not support point format + negotiation in favor of a single point format for each curve. Thus, + support for DTLS 1.3 does not mandate point format extensions and + negotiation. In addition, in DTLS 1.3, the Supported Elliptic Curves + extension has been renamed to Supported Groups. + + CoAP was designed to avoid IP fragmentation. DTLS is used to secure + CoAP messages. However, fragmentation is still possible at the DTLS + layer during the DTLS handshake even when using Elliptic Curve + Cryptography (ECC) cipher suites. If fragmentation is necessary, + "DTLS provides a mechanism for fragmenting a handshake message over a + number of records, each of which can be transmitted separately, thus + avoiding IP fragmentation" [RFC6347]. + + The authentication of the EST-coaps server by the EST-coaps client is + based on certificate authentication in the DTLS handshake. The EST- + coaps client MUST be configured with at least an Implicit Trust + Anchor database, which will enable the authentication of the server + the first time before updating its trust anchor (Explicit TA) + [RFC7030]. + + The authentication of the EST-coaps client MUST be with a client + certificate in the DTLS handshake. This can either be: + + * A previously issued client certificate (e.g., an existing + certificate issued by the EST CA); this could be a common case for + simple re-enrollment of clients. + + * A previously installed certificate (e.g., manufacturer IDevID + [IEEE802.1AR] or a certificate issued by some other party). + IDevID's are expected to have a very long life, as long as the + device, but under some conditions could expire. In that case, the + server MAY authenticate a client certificate against its trust + store though the certificate is expired (Section 9). + + EST-coaps supports the certificate types and TAs that are specified + for EST in Section 3 of [RFC7030]. + + As described in Section 2.1 of [RFC5272], proof-of-identity refers to + a value that can be used to prove that an end entity or client is in + the possession of and can use the private key corresponding to the + certified public key. Additionally, channel-binding information can + link proof-of-identity with an established connection. Connection- + based proof-of-possession is OPTIONAL for EST-coaps clients and + servers. When proof-of-possession is desired, a set of actions are + required regarding the use of tls-unique, described in Section 3.5 of + [RFC7030]. The tls-unique information consists of the contents of + the first Finished message in the (D)TLS handshake between server and + client [RFC5929]. The client adds the Finished message as a + challengePassword in the attributes section of the PKCS #10 + CertificationRequest [RFC5967] to prove that the client is indeed in + control of the private key at the time of the (D)TLS session + establishment. In the case of handshake message fragmentation, if + proof-of-possession is desired, the Finished message added as the + challengePassword in the Certificate Signing Request (CSR) is + calculated as specified by (D)TLS. We summarize it here for + convenience. For DTLS 1.2, in the event of handshake message + fragmentation, the hash of the handshake messages used in the Message + Authentication Code (MAC) calculation of the Finished message must be + computed on each reassembled message, as if each message had not been + fragmented (Section 4.2.6 of [RFC6347]). The Finished message is + calculated as shown in Section 7.4.9 of [RFC5246]. + + For (D)TLS 1.3, Appendix C.5 of [RFC8446] describes the lack of + channel bindings similar to tls-unique. [TLS13-CHANNEL-BINDINGS] can + be used instead to derive a 32-byte tls-exporter binding from the + (D)TLS 1.3 master secret by using a PRF negotiated in the (D)TLS 1.3 + handshake, "EXPORTER-Channel-Binding" with no terminating NUL as the + label, the ClientHello.random and ServerHello.random, and a zero- + length context string. When proof-of-possession is desired, the + client adds the tls-exporter value as a challengePassword in the + attributes section of the PKCS #10 CertificationRequest [RFC5967] to + prove that the client is indeed in control of the private key at the + time of the (D)TLS session establishment. + + In a constrained CoAP environment, endpoints can't always afford to + establish a DTLS connection for every EST transaction. An EST-coaps + DTLS connection MAY remain open for sequential EST transactions, + which was not the case with [RFC7030]. For example, if a /crts + request is followed by a /sen request, both can use the same + authenticated DTLS connection. However, when a /crts request is + included in the set of sequential EST transactions, some additional + security considerations apply regarding the use of the Implicit and + Explicit TA database as explained in Section 9.1. + + Given that after a successful enrollment, it is more likely that a + new EST transaction will not take place for a significant amount of + time, the DTLS connections SHOULD only be kept alive for EST messages + that are relatively close to each other. These could include a /sen + immediately following a /crts when a device is getting bootstrapped. + In some cases, like NAT rebinding, keeping the state of a connection + is not possible when devices sleep for extended periods of time. In + such occasions, [RFC9146] negotiates a connection ID that can + eliminate the need for a new handshake and its additional cost; or, + DTLS session resumption provides a less costly alternative than + redoing a full DTLS handshake. + +4. Protocol Design + + EST-coaps uses CoAP to transfer EST messages, aided by Block-Wise + Transfer [RFC7959], to avoid IP fragmentation. The use of blocks for + the transfer of larger EST messages is specified in Section 4.6. + Figure 1 shows the layered EST-coaps architecture. + + The EST-coaps protocol design follows closely the EST design. The + supported message types in EST-coaps are: + + * CA certificate retrieval needed to receive the complete set of CA + certificates. + + * Simple enroll and re-enroll for a CA to sign client identity + public keys. + + * Certificate Signing Request (CSR) attribute messages that informs + the client of the fields to include in a CSR. + + * Server-side key generation messages to provide a client identity + private key when the client chooses so. + + While [RFC7030] permits a number of the EST functions to be used + without authentication, this specification requires that the client + MUST be authenticated for all functions. + +4.1. Discovery and URIs + + EST-coaps is targeted for low-resource networks with small packets. + Two types of installations are possible: (1) a rigid one, where the + address and the supported functions of the EST server(s) are known, + and (2) a flexible one, where the EST server and its supported + functions need to be discovered. + + For both types of installations, saving header space is important and + short EST-coaps URIs are specified in this document. These URIs are + shorter than the ones in [RFC7030]. Two example EST-coaps resource + path names are: + + coaps://example.com:/.well-known/est/ + coaps://example.com:/.well-known/est/ArbitraryLabel/ + + The short-est strings are defined in Table 1. Arbitrary Labels are + usually defined and used by EST CAs in order to route client requests + to the appropriate certificate profile. Implementers should consider + using short labels to minimize transmission overhead. + + The EST-coaps server URIs, obtained through discovery of the EST- + coaps resource(s) as shown below, are of the form: + + coaps://example.com:// + coaps://example.com://ArbitraryLabel/ + + Figure 5 in Section 3.2.2 of [RFC7030] enumerates the operations and + corresponding paths that are supported by EST. Table 1 provides the + mapping from the EST URI path to the shorter EST-coaps URI path. + + +=================+==============================+ + | EST | EST-coaps | + +=================+==============================+ + | /cacerts | /crts | + +-----------------+------------------------------+ + | /simpleenroll | /sen | + +-----------------+------------------------------+ + | /simplereenroll | /sren | + +-----------------+------------------------------+ + | /serverkeygen | /skg (PKCS #7) | + +-----------------+------------------------------+ + | /serverkeygen | /skc (application/pkix-cert) | + +-----------------+------------------------------+ + | /csrattrs | /att | + +-----------------+------------------------------+ + + Table 1: Short EST-coaps URI Path + + The /skg message is the EST /serverkeygen equivalent where the client + requests a certificate in PKCS #7 format and a private key. If the + client prefers a single application/pkix-cert certificate instead of + PKCS #7, it will make an /skc request. In both cases (i.e., /skg, + /skc), a private key MUST be returned. + + Clients and servers MUST support the short resource EST-coaps URIs. + + In the context of CoAP, the presence and location of (path to) the + EST resources are discovered by sending a GET request to "/.well- + known/core" including a resource type (RT) parameter with the value + "ace.est*" [RFC6690]. The example below shows the discovery over + CoAPS of the presence and location of EST-coaps resources. Linefeeds + are included only for readability. + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + ;rt="ace.est.crts";ct="281 287", + ;rt="ace.est.sen";ct="281 287", + ;rt="ace.est.sren";ct="281 287", + ;rt="ace.est.att";ct=285, + ;rt="ace.est.skg";ct=62, + ;rt="ace.est.skc";ct=62 + + The first three lines, describing ace.est.crts, ace.est.sen, and + ace.est.sren, of the discovery response above MUST be returned if the + server supports resource discovery. The last three lines are only + included if the corresponding EST functions are implemented (see + Table 2). The Content-Formats in the response allow the client to + request one that is supported by the server. These are the values + that would be sent in the client request with an Accept Option. + + Discoverable port numbers can be returned in the response payload. + An example response payload for non-default CoAPS server port 61617 + follows below. Linefeeds are included only for readability. + + REQ: GET /.well-known/core?rt=ace.est* + + RES: 2.05 Content + ;rt="ace.est.crts"; + ct="281 287", + ;rt="ace.est.sen"; + ct="281 287", + ;rt="ace.est.sren"; + ct="281 287", + ;rt="ace.est.att"; + ct=285, + ;rt="ace.est.skg"; + ct=62, + ;rt="ace.est.skc"; + ct=62 + + The server MUST support the default /.well-known/est root resource. + The server SHOULD support resource discovery when it supports non- + default URIs (like /est or /est/ArbitraryLabel) or ports. The client + SHOULD use resource discovery when it is unaware of the available + EST-coaps resources. + + Throughout this document, the example root resource of /est is used. + +4.2. Mandatory/Optional EST Functions + + This specification contains a set of required-to-implement functions, + optional functions, and not-specified functions. The unspecified + functions are deemed too expensive for low-resource devices in + payload and calculation times. + + Table 2 specifies the mandatory-to-implement or optional + implementation of the EST-coaps functions. Discovery of the + existence of optional functions is described in Section 4.1. + + +=================+==========================+ + | EST Functions | EST-coaps Implementation | + +=================+==========================+ + | /cacerts | MUST | + +-----------------+--------------------------+ + | /simpleenroll | MUST | + +-----------------+--------------------------+ + | /simplereenroll | MUST | + +-----------------+--------------------------+ + | /fullcmc | Not specified | + +-----------------+--------------------------+ + | /serverkeygen | OPTIONAL | + +-----------------+--------------------------+ + | /csrattrs | OPTIONAL | + +-----------------+--------------------------+ + + Table 2: List of EST-coaps Functions + +4.3. Payload Formats + + EST-coaps is designed for low-resource devices; hence, it does not + need to send Base64-encoded data. Simple binary is more efficient + (30% smaller payload for DER-encoded ASN.1) and well supported by + CoAP. Thus, the payload for a given media type follows the ASN.1 + structure of the media type and is transported in binary format. + + The Content-Format (HTTP Content-Type equivalent) of the CoAP message + determines which EST message is transported in the CoAP payload. The + media types specified in the HTTP Content-Type header field + (Section 3.2.4 of [RFC7030]) are specified by the Content-Format + Option (12) of CoAP. The combination of URI-Path and Content-Format + in EST-coaps MUST map to an allowed combination of URI and media type + in EST. The required Content-Formats for these requests and response + messages are defined in Section 8.1. The CoAP response codes are + defined in Section 4.5. + + Content-Format 287 can be used in place of 281 to carry a single + certificate instead of a PKCS #7 container in a /crts, /sen, /sren, + or /skg response. Content-Format 281 MUST be supported by EST-coaps + servers. Servers MAY also support Content-Format 287. It is up to + the client to support only Content-Format 281, 287 or both. The + client will use a CoAP Accept Option in the request to express the + preferred response Content-Format. If an Accept Option is not + included in the request, the client is not expressing any preference + and the server SHOULD choose format 281. + + Content-Format 286 is used in /sen, /sren, and /skg requests and 285 + in /att responses. + + A representation with Content-Format identifier 62 contains a + collection of representations along with their respective Content- + Format. The Content-Format identifies the media type application/ + multipart-core specified in [RFC8710]. For example, a collection, + containing two representations in response to an EST-coaps server- + side key generation /skg request, could include a private key in PKCS + #8 [RFC5958] with Content-Format identifier 284 (0x011C) and a single + certificate in a PKCS #7 container with Content-Format identifier 281 + (0x0119). Such a collection would look like + [284,h'0123456789abcdef', 281,h'fedcba9876543210'] in diagnostic + Concise Binary Object Representation (CBOR) notation. The + serialization of such CBOR content would be: + + 84 # array(4) + 19 011C # unsigned(284) + 48 # bytes(8) + 0123456789ABCDEF # "\x01#Eg\x89\xAB\xCD\xEF" + 19 0119 # unsigned(281) + 48 # bytes(8) + FEDCBA9876543210 # "\xFE\xDC\xBA\x98vT2\x10" + + Figure 2: Multipart /skg Response Serialization + + When the client makes an /skc request, the certificate returned with + the private key is a single X.509 certificate (not a PKCS #7 + container) with Content-Format identifier 287 (0x011F) instead of + 281. In cases where the private key is encrypted with Cryptographic + Message Syntax (CMS) (as explained in Section 4.8), the Content- + Format identifier is 280 (0x0118) instead of 284. The Content-Format + used in the response is summarized in Table 3. + + +==========+==================+==================+ + | Function | Response, Part 1 | Response, Part 2 | + +==========+==================+==================+ + | /skg | 284 | 281 | + +----------+------------------+------------------+ + | /skc | 280 | 287 | + +----------+------------------+------------------+ + + Table 3: Response Content-Formats for /skg and + /skc + + The key and certificate representations are DER-encoded ASN.1, in its + binary form. An example is shown in Appendix A.3. + +4.4. Message Bindings + + The general EST-coaps message characteristics are: + + * EST-coaps servers sometimes need to provide delayed responses, + which are preceded by an immediately returned empty ACK or an ACK + containing response code 5.03 as explained in Section 4.7. Thus, + it is RECOMMENDED for implementers to send EST-coaps requests in + Confirmable (CON) CoAP messages. + + * The CoAP Options used are Uri-Host, Uri-Path, Uri-Port, Content- + Format, Block1, Block2, and Accept. These CoAP Options are used + to communicate the HTTP fields specified in the EST REST messages. + The Uri-host and Uri-Port Options can be omitted from the CoAP + message sent on the wire. When omitted, they are logically + assumed to be the transport protocol destination address and port, + respectively. Explicit Uri-Host and Uri-Port Options are + typically used when an endpoint hosts multiple virtual servers and + uses the Options to route the requests accordingly. Other CoAP + Options should be handled in accordance with [RFC7252]. + + * EST URLs are HTTPS based (https://); in CoAP, these are assumed to + be translated to CoAPS (coaps://). + + Table 1 provides the mapping from the EST URI path to the EST-coaps + URI path. Appendix A includes some practical examples of EST + messages translated to CoAP. + +4.5. CoAP Response Codes + + Section 5.9 of [RFC7252] and Section 7 of [RFC8075] specify the + mapping of HTTP response codes to CoAP response codes. The success + code in response to an EST-coaps GET request (/crts, /att) is 2.05. + Similarly, 2.04 is used in successful response to EST-coaps POST + requests (/sen, /sren, /skg, /skc). + + EST makes use of HTTP 204 or 404 responses when a resource is not + available for the client. In EST-coaps, 2.04 is used in response to + a POST (/sen, /sren, /skg, /skc). 4.04 is used when the resource is + not available for the client. + + HTTP response code 202 with a Retry-After header field in [RFC7030] + has no equivalent in CoAP. HTTP 202 with Retry-After is used in EST + for delayed server responses. Section 4.7 specifies how EST-coaps + handles delayed messages with 5.03 responses with a Max-Age Option. + + Additionally, EST's HTTP 400, 401, 403, 404, and 503 status codes + have their equivalent CoAP 4.00, 4.01, 4.03, 4.04, and 5.03 response + codes in EST-coaps. Table 4 summarizes the EST-coaps response codes. + + +=============+=========================+==========================+ + | Operation | EST-coaps Response Code | Description | + +=============+=========================+==========================+ + | /crts, /att | 2.05 | Success. Certs included | + | | | in the response payload. | + +-------------+-------------------------+--------------------------+ + | | 4.xx / 5.xx | Failure. | + +-------------+-------------------------+--------------------------+ + | /sen, /skg, | 2.04 | Success. Cert included | + | /sren, /skc | | in the response payload. | + +-------------+-------------------------+--------------------------+ + | | 5.03 | Retry in Max-Age Option | + | | | time. | + +-------------+-------------------------+--------------------------+ + | | 4.xx / 5.xx | Failure. | + +-------------+-------------------------+--------------------------+ + + Table 4: EST-coaps Response Codes + +4.6. Message Fragmentation + + DTLS defines fragmentation only for the handshake and not for secure + data exchange (DTLS records). [RFC6347] states that to avoid using + IP fragmentation, which involves error-prone datagram reconstitution, + invokers of the DTLS record layer should size DTLS records so that + they fit within any Path MTU estimates obtained from the record + layer. In addition, invokers residing on 6LoWPAN (IPv6 over Low- + Power Wireless Personal Area Networks) over IEEE 802.15.4 networks + [IEEE802.15.4] are recommended to size CoAP messages such that each + DTLS record will fit within one or two IEEE 802.15.4 frames. + + That is not always possible in EST-coaps. Even though ECC + certificates are small in size, they can vary greatly based on + signature algorithms, key sizes, and Object Identifier (OID) fields + used. For 256-bit curves, common Elliptic Curve Digital Signature + Algorithm (ECDSA) cert sizes are 500-1000 bytes, which could + fluctuate further based on the algorithms, OIDs, Subject Alternative + Names (SANs), and cert fields. For 384-bit curves, ECDSA + certificates increase in size and can sometimes reach 1.5KB. + Additionally, there are times when the EST cacerts response from the + server can include multiple certificates that amount to large + payloads. Section 4.6 of [RFC7252] (CoAP) describes the possible + payload sizes: "if nothing is known about the size of the headers, + good upper bounds are 1152 bytes for the message size and 1024 bytes + for the payload size". Section 4.6 of [RFC7252] also suggests that + IPv4 implementations may want to limit themselves to more + conservative IPv4 datagram sizes such as 576 bytes. Even with ECC, + EST-coaps messages can still exceed MTU sizes on the Internet or + 6LoWPAN [RFC4919] (Section 2 of [RFC7959]). EST-coaps needs to be + able to fragment messages into multiple DTLS datagrams. + + To perform fragmentation in CoAP, [RFC7959] specifies the Block1 + Option for fragmentation of the request payload and the Block2 Option + for fragmentation of the return payload of a CoAP flow. As explained + in Section 1 of [RFC7959], block-wise transfers should be used in + Confirmable CoAP messages to avoid the exacerbation of lost blocks. + EST-coaps servers MUST implement Block1 and Block2. EST-coaps + clients MUST implement Block2. EST-coaps clients MUST implement + Block1 only if they are expecting to send EST-coaps requests with a + packet size that exceeds the path MTU. + + [RFC7959] also defines Size1 and Size2 Options to provide size + information about the resource representation in a request and + response. The EST-coaps client and server MAY support Size1 and + Size2 Options. + + Examples of fragmented EST-coaps messages are shown in Appendix B. + +4.7. Delayed Responses + + Server responses can sometimes be delayed. According to + Section 5.2.2 of [RFC7252], a slow server can acknowledge the request + and respond later with the requested resource representation. In + particular, a slow server can respond to an EST-coaps enrollment + request with an empty ACK with code 0.00 before sending the + certificate to the client after a short delay. If the certificate + response is large, the server will need more than one Block2 block to + transfer it. + + This situation is shown in Figure 3. The client sends an enrollment + request that uses N1+1 Block1 blocks. The server uses an empty 0.00 + ACK to announce the delayed response, which is provided later with + 2.04 messages containing N2+1 Block2 Options. The first 2.04 is a + Confirmable message that is acknowledged by the client. Onwards, the + client acknowledges all subsequent Block2 blocks. The notation of + Figure 3 is explained in Appendix B.1. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + <-- (0.00 empty ACK) + | + ... Short delay before the certificate is ready ... + | + <-- (CON) (1:N1/0/256)(2:0/1/256)(2.04 Changed) + {Cert resp (frag# 1)} + (ACK) --> + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256) (2.04 Changed) {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) {Cert resp (frag# N2+1)} + + Figure 3: EST-coaps Enrollment with Short Wait + + If the server is very slow (for example, manual intervention is + required, which would take minutes), it SHOULD respond with an ACK + containing response code 5.03 (Service unavailable) and a Max-Age + Option to indicate the time the client SHOULD wait before sending + another request to obtain the content. After a delay of Max-Age, the + client SHOULD resend the identical CSR to the server. As long as the + server continues to respond with response code 5.03 (Service + Unavailable) with a Max-Age Option, the client will continue to delay + for Max-Age and then resend the enrollment request until the server + responds with the certificate or the client abandons the request due + to policy or other reasons. + + To demonstrate this scenario, Figure 4 shows a client sending an + enrollment request that uses N1+1 Block1 blocks to send the CSR to + the server. The server needs N2+1 Block2 blocks to respond but also + needs to take a long delay (minutes) to provide the response. + Consequently, the server uses a 5.03 ACK response with a Max-Age + Option. The client waits for a period of Max-Age as many times as it + receives the same 5.03 response and retransmits the enrollment + request until it receives a certificate in a fragmented 2.04 + response. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + <-- (ACK) (1:N1/0/256) (5.03 Service Unavailable) (Max-Age) + | + | + ... Client tries again after Max-Age with identical payload ... + | + | + POST [2001:db8::2:1]:61616/est/sen(CON)(1:0/1/256) + {CSR (frag# 1)}--> + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen(CON)(1:N1/0/256) + {CSR (frag# N1+1)}--> + | + ... Immediate response when certificate is ready ... + | + <-- (ACK) (1:N1/0/256) (2:0/1/256) (2.04 Changed) + {Cert resp (frag# 1)} + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256) (2.04 Changed) {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) {Cert resp (frag# N2+1)} + + Figure 4: EST-coaps Enrollment with Long Wait + +4.8. Server-Side Key Generation + + Private keys can be generated on the server to support scenarios + where server-side key generation is needed. Such scenarios include + those where it is considered more secure to generate the long-lived, + random private key that identifies the client at the server, or where + the resources spent to generate a random private key at the client + are considered scarce, or where the security policy requires that the + certificate public and corresponding private keys are centrally + generated and controlled. As always, it is necessary to use proper + random numbers in various protocols such as (D)TLS (Section 9.1). + + When requesting server-side key generation, the client asks for the + server or proxy to generate the private key and the certificate, + which are transferred back to the client in the server-side key + generation response. In all respects, the server treats the CSR as + it would treat any enroll or re-enroll CSR; the only distinction here + is that the server MUST ignore the public key values and signature in + the CSR. These are included in the request only to allow reuse of + existing codebases for generating and parsing such requests. + + The client /skg request is for a certificate in a PKCS #7 container + and private key in two application/multipart-core elements. + Respectively, an /skc request is for a single application/pkix-cert + certificate and a private key. The private key Content-Format + requested by the client is indicated in the PKCS #10 CSR request. If + the request contains SMIMECapabilities and DecryptKeyIdentifier or + AsymmetricDecryptKeyIdentifier, the client is expecting Content- + Format 280 for the private key. Then, this private key is encrypted + symmetrically or asymmetrically per [RFC7030]. The symmetric key or + the asymmetric keypair establishment method is out of scope of this + specification. An /skg or /skc request with a CSR without + SMIMECapabilities expects an application/multipart-core with an + unencrypted PKCS #8 private key with Content-Format 284. + + The EST-coaps server-side key generation response is returned with + Content-Format application/multipart-core [RFC8710] containing a CBOR + array with four items (Section 4.3). The two representations (each + consisting of two CBOR array items) do not have to be in a particular + order since each representation is preceded by its Content-Format ID. + Depending on the request, the private key can be in unprotected PKCS + #8 format [RFC5958] (Content-Format 284) or protected inside of CMS + SignedData (Content-Format 280). The SignedData, placed in the + outermost container, is signed by the party that generated the + private key, which may be the EST server or the EST CA. SignedData + placed within the Enveloped Data does not need additional signing as + explained in Section 4.4.2 of [RFC7030]. In summary, the + symmetrically encrypted key is included in the encryptedKey attribute + in a KEKRecipientInfo structure. In the case where the asymmetric + encryption key is suitable for transport key operations, the + generated private key is encrypted with a symmetric key. The + symmetric key itself is encrypted by the client-defined (in the CSR) + asymmetric public key and is carried in an encryptedKey attribute in + a KeyTransRecipientInfo structure. Finally, if the asymmetric + encryption key is suitable for key agreement, the generated private + key is encrypted with a symmetric key. The symmetric key itself is + encrypted by the client defined (in the CSR) asymmetric public key + and is carried in a recipientEncryptedKeys attribute in a + KeyAgreeRecipientInfo. + + [RFC7030] recommends the use of additional encryption of the returned + private key. For the context of this specification, clients and + servers that choose to support server-side key generation MUST + support unprotected (PKCS #8) private keys (Content-Format 284). + Symmetric or asymmetric encryption of the private key (CMS + EnvelopedData, Content-Format 280) SHOULD be supported for + deployments where end-to-end encryption is needed between the client + and a server. Such cases could include architectures where an entity + between the client and the CA terminates the DTLS connection + (Registrar in Figure 5). Though [RFC7030] strongly recommends that + clients request the use of CMS encryption on top of the TLS channel's + protection, this document does not make such a recommendation; CMS + encryption can still be used when mandated by the use case. + +5. HTTPS-CoAPS Registrar + + In real-world deployments, the EST server will not always reside + within the CoAP boundary. The EST server can exist outside the + constrained network, in which case it will support TLS/HTTP instead + of CoAPS. In such environments, EST-coaps is used by the client + within the CoAP boundary and TLS is used to transport the EST + messages outside the CoAP boundary. A Registrar at the edge is + required to operate between the CoAP environment and the external + HTTP network as shown in Figure 5. + + Constrained Network + .------. .----------------------------. + | CA | |.--------------------------.| + '------' || || + | || || + .------. HTTP .------------------. CoAPS .-----------. || + | EST |<------->|EST-coaps-to-HTTPS|<------->| EST Client| || + |Server|over TLS | Registrar | '-----------' || + '------' '------------------' || + || || + |'--------------------------'| + '----------------------------' + + Figure 5: EST-coaps-to-HTTPS Registrar at the CoAP Boundary + + The EST-coaps-to-HTTPS Registrar MUST terminate EST-coaps downstream + and initiate EST connections over TLS upstream. The Registrar MUST + authenticate and optionally authorize the client requests while it + MUST be authenticated by the EST server or CA. The trust + relationship between the Registrar and the EST server SHOULD be pre- + established for the Registrar to proxy these connections on behalf of + various clients. + + When enforcing Proof-of-Possession (POP) linking, the tls-unique or + tls-exporter value of the session for DTLS 1.2 and DTLS 1.3, + respectively, is used to prove that the private key corresponding to + the public key is in the possession of the client and was used to + establish the connection as explained in Section 3. The POP linking + information is lost between the EST-coaps client and the EST server + when a Registrar is present. The EST server becomes aware of the + presence of a Registrar from its TLS client certificate that includes + the id-kp-cmcRA extended key usage (EKU) extension [RFC6402]. As + explained in Section 3.7 of [RFC7030], the "EST server SHOULD apply + authorization policy consistent with an RA client ... the EST server + could be configured to accept POP linking information that does not + match the current TLS session because the authenticated EST client RA + has verified this information when acting as an EST server". + + Table 1 contains the URI mappings between EST-coaps and EST that the + Registrar MUST adhere to. Section 4.5 of this specification and + Section 7 of [RFC8075] define the mappings between EST-coaps and HTTP + response codes that determine how the Registrar MUST translate CoAP + response codes from/to HTTP status codes. The mapping from CoAP + Content-Format to HTTP Content-Type is defined in Section 8.1. + Additionally, a conversion from CBOR major type 2 to Base64 encoding + MUST take place at the Registrar. If CMS end-to-end encryption is + employed for the private key, the encrypted CMS EnvelopedData blob + MUST be converted at the Registrar to binary CBOR type 2 downstream + to the client. This is a format conversion that does not require + decryption of the CMS EnvelopedData. + + A deviation from the mappings in Table 1 could take place if clients + that leverage server-side key generation preferred for the enrolled + keys to be generated by the Registrar in the case the CA does not + support server-side key generation. Such a Registrar is responsible + for generating a new CSR signed by a new key that will be returned to + the client along with the certificate from the CA. In these cases, + the Registrar MUST use random number generation with proper entropy. + + Due to fragmentation of large messages into blocks, an EST-coaps-to- + HTTP Registrar MUST reassemble the blocks before translating the + binary content to Base64 and consecutively relay the message + upstream. + + The EST-coaps-to-HTTP Registrar MUST support resource discovery + according to the rules in Section 4.1. + +6. Parameters + + This section addresses transmission parameters described in Sections + 4.7 and 4.8 of [RFC7252]. EST does not impose any unique values on + the CoAP parameters in [RFC7252], but the setting of the CoAP + parameter values may have consequence for the setting of the EST + parameter values. + + Implementations should follow the default CoAP configuration + parameters [RFC7252]. However, depending on the implementation + scenario, retransmissions and timeouts can also occur on other + networking layers, governed by other configuration parameters. When + a change in a server parameter has taken place, the parameter values + in the communicating endpoints MUST be adjusted as necessary. + Examples of how parameters could be adjusted include higher-layer + congestion protocols, provisioning agents, and configurations + included in firmware updates. + + Some further comments about some specific parameters, mainly from + Table 2 in [RFC7252], include the following: + + NSTART: A parameter that controls the number of simultaneous + outstanding interactions that a client maintains to a given + server. An EST-coaps client is expected to control at most one + interaction with a given server, which is the default NSTART value + defined in [RFC7252]. + + DEFAULT_LEISURE: A setting that is only relevant in multicast + scenarios and is outside the scope of EST-coaps. + + PROBING_RATE: A parameter that specifies the rate of resending Non- + confirmable messages. In the rare situations that Non-confirmable + messages are used, the default PROBING_RATE value defined in + [RFC7252] applies. + + Finally, the Table 3 parameters in [RFC7252] are mainly derived from + Table 2. Directly changing parameters on one table would affect + parameters on the other. + +7. Deployment Limitations + + Although EST-coaps paves the way for the utilization of EST by + constrained devices in constrained networks, some classes of devices + [RFC7228] will not have enough resources to handle the payloads that + come with EST-coaps. The specification of EST-coaps is intended to + ensure that EST works for networks of constrained devices that choose + to limit their communications stack to DTLS/CoAP. It is up to the + network designer to decide which devices execute the EST protocol and + which do not. + +8. IANA Considerations + +8.1. Content-Formats Registry + + IANA has registered the following Content-Formats given in Table 5 in + the "CoAP Content-Formats" subregistry within the "CoRE Parameters" + registry [CORE-PARAMS]. These have been registered in the IETF + Review or IESG Approval range (256-9999). + + +=================================+=====+====================+ + | Media Type | ID | Reference | + +=================================+=====+====================+ + | application/pkcs7-mime; smime- | 280 | [RFC7030] | + | type=server-generated-key | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkcs7-mime; smime- | 281 | [RFC8551] RFC 9148 | + | type=certs-only | | | + +---------------------------------+-----+--------------------+ + | application/pkcs8 | 284 | [RFC5958] | + | | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/csrattrs | 285 | [RFC7030] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkcs10 | 286 | [RFC5967] | + | | | [RFC8551] RFC 9148 | + +---------------------------------+-----+--------------------+ + | application/pkix-cert | 287 | [RFC2585] RFC 9148 | + +---------------------------------+-----+--------------------+ + + Table 5: New CoAP Content-Formats + +8.2. Resource Type Registry + + IANA has registered the following Resource Type (rt=) Link Target + Attributes given in Table 6 in the "Resource Type (rt=) Link Target + Attribute Values" subregistry under the "Constrained RESTful + Environments (CoRE) Parameters" registry. + + +==============+===================================+===========+ + | Value | Description | Reference | + +==============+===================================+===========+ + | ace.est.crts | This resource depicts the support | RFC 9148 | + | | of EST GET cacerts. | | + +--------------+-----------------------------------+-----------+ + | ace.est.sen | This resource depicts the support | RFC 9148 | + | | of EST simple enroll. | | + +--------------+-----------------------------------+-----------+ + | ace.est.sren | This resource depicts the support | RFC 9148 | + | | of EST simple reenroll. | | + +--------------+-----------------------------------+-----------+ + | ace.est.att | This resource depicts the support | RFC 9148 | + | | of EST GET CSR attributes. | | + +--------------+-----------------------------------+-----------+ + | ace.est.skg | This resource depicts the support | RFC 9148 | + | | of EST server-side key generation | | + | | with the returned certificate in | | + | | a PKCS #7 container. | | + +--------------+-----------------------------------+-----------+ + | ace.est.skc | This resource depicts the support | RFC 9148 | + | | of EST server-side key generation | | + | | with the returned certificate in | | + | | application/pkix-cert format. | | + +--------------+-----------------------------------+-----------+ + + Table 6: New Resource Type (rt=) Link Target Attributes + +8.3. Well-Known URIs Registry + + IANA has added an additional reference to the est URI in the "Well- + Known URIs" registry: + + URI Suffix: est + + Change Controller: IETF + + References: [RFC7030] RFC 9148 + + Status: permanent + + Related Information: + + Date Registered: 2013-08-16 + + Date Modified: 2020-04-29 + +9. Security Considerations + +9.1. EST Server Considerations + + The security considerations in Section 6 of [RFC7030] are only + partially valid for the purposes of this document. As HTTP Basic + Authentication is not supported, the considerations expressed for + using passwords do not apply. The other portions of the security + considerations in [RFC7030] continue to apply. + + Modern security protocols require random numbers to be available + during the protocol run, for example, for nonces and ephemeral (EC) + Diffie-Hellman key generation. This capability to generate random + numbers is also needed when the constrained device generates the + private key (that corresponds to the public key enrolled in the CSR). + When server-side key generation is used, the constrained device + depends on the server to generate the private key randomly, but it + still needs locally generated random numbers for use in security + protocols, as explained in Section 12 of [RFC7925]. Additionally, + the transport of keys generated at the server is inherently risky. + For those deploying server-side key generation, analysis SHOULD be + done to establish whether server-side key generation increases or + decreases the probability of digital identity theft. + + It is important to note that, as pointed out in [PsQs], sources + contributing to the randomness pool used to generate random numbers + on laptops or desktop PCs, such as mouse movement, timing of + keystrokes, or air turbulence on the movement of hard drive heads, + are not available on many constrained devices. Other sources have to + be used or dedicated hardware has to be added. Selecting hardware + for an IoT device that is capable of producing high-quality random + numbers is therefore important [RSA-FACT]. + + As discussed in Section 6 of [RFC7030], it is + + | RECOMMENDED that the Implicit Trust Anchor database used for EST + | server authentication be carefully managed to reduce the chance of + | a third-party CA with poor certification practices from being + | trusted. Disabling the Implicit Trust Anchor database after + | successfully receiving the Distribution of CA certificates + | response ([RFC7030], Section 6) limits any vulnerability to the + | first TLS exchange. + + Alternatively, in a case where a /sen request immediately follows a + /crts, a client MAY choose to keep the connection authenticated by + the Implicit TA open for efficiency reasons (Section 3). A client + that interleaves EST-coaps /crts request with other requests in the + same DTLS connection SHOULD revalidate the server certificate chain + against the updated Explicit TA from the /crts response before + proceeding with the subsequent requests. If the server certificate + chain does not authenticate against the database, the client SHOULD + close the connection without completing the rest of the requests. + The updated Explicit TA MUST continue to be used in new DTLS + connections. + + In cases where the Initial Device Identifier (IDevID) used to + authenticate the client is expired, the server MAY still authenticate + the client because IDevIDs are expected to live as long as the device + itself (Section 3). In such occasions, checking the certificate + revocation status or authorizing the client using another method is + important for the server to raise its confidence that the client can + be trusted. + + In accordance with [RFC7030], TLS cipher suites that include + "_EXPORT_" and "_DES_" in their names MUST NOT be used. More + recommendations for secure use of TLS and DTLS are included in + [BCP195]. + + As described in Certificate Management over CMS (CMC), Section 6.7 of + [RFC5272], "For keys that can be used as signature keys, signing the + certification request with the private key serves as a POP on that + key pair". In (D)TLS 1.2, the inclusion of tls-unique in the + certificate request links the proof-of-possession to the (D)TLS + proof-of-identity. This implies but does not prove that only the + authenticated client currently has access to the private key. + + What's more, CMC POP linking uses tls-unique as it is defined in + [RFC5929]. The 3SHAKE attack [TRIPLESHAKE] poses a risk by allowing + an on-path active attacker to leverage session resumption and + renegotiation to inject itself between a client and server even when + channel binding is in use. Implementers should use the Extended + Master Secret Extension in DTLS [RFC7627] to prevent such attacks. + In the context of this specification, an attacker could invalidate + the purpose of the POP linking challengePassword in the client + request by resuming an EST-coaps connection. Even though the + practical risk of such an attack to EST-coaps is not devastating, we + would rather use a more secure channel-binding mechanism. In this + specification, we still depend on the tls-unique mechanism defined in + [RFC5929] for DTLS 1.2 because a 3SHAKE attack does not expose + messages exchanged with EST-coaps. But for DTLS 1.3, + [TLS13-CHANNEL-BINDINGS] is used instead to derive a 32-byte tls- + exporter binding in place of the tls-unique value in the CSR. That + would alleviate the risks from the 3SHAKE attack [TRIPLESHAKE]. + + Interpreters of ASN.1 structures should be aware of the use of + invalid ASN.1 length fields and should take appropriate measures to + guard against buffer overflows, stack overruns in particular, and + malicious content in general. + +9.2. HTTPS-CoAPS Registrar Considerations + + The Registrar proposed in Section 5 must be deployed with care and + only when direct client-server connections are not possible. When + POP linking is used, the Registrar terminating the DTLS connection + establishes a new TLS connection with the upstream CA. Thus, it is + impossible for POP linking to be enforced end to end for the EST + transaction. The EST server could be configured to accept POP + linking information that does not match the current TLS session + because the authenticated EST Registrar is assumed to have verified + POP linking downstream to the client. + + The introduction of an EST-coaps-to-HTTP Registrar assumes the client + can authenticate the Registrar using its implicit or explicit TA + database. It also assumes the Registrar has a trust relationship + with the upstream EST server in order to act on behalf of the + clients. When a client uses the Implicit TA database for certificate + validation, it SHOULD confirm if the server is acting as an RA by the + presence of the id-kp-cmcRA EKU [RFC6402] in the server certificate. + + In a server-side key generation case, if no end-to-end encryption is + used, the Registrar may be able see the private key as it acts as a + man in the middle. Thus, the client puts its trust on the Registrar + not exposing the private key. + + Clients that leverage server-side key generation without end-to-end + encryption of the private key (Section 4.8) have no knowledge as to + whether the Registrar will be generating the private key and + enrolling the certificates with the CA or if the CA will be + responsible for generating the key. In such cases, the existence of + a Registrar requires the client to put its trust on the Registrar + when it is generating the private key. + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC2585] Housley, R. and P. Hoffman, "Internet X.509 Public Key + Infrastructure Operational Protocols: FTP and HTTP", + RFC 2585, DOI 10.17487/RFC2585, May 1999, + . + + [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security + (TLS) Protocol Version 1.2", RFC 5246, + DOI 10.17487/RFC5246, August 2008, + . + + [RFC5958] Turner, S., "Asymmetric Key Packages", RFC 5958, + DOI 10.17487/RFC5958, August 2010, + . + + [RFC5967] Turner, S., "The application/pkcs10 Media Type", RFC 5967, + DOI 10.17487/RFC5967, August 2010, + . + + [RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer + Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347, + January 2012, . + + [RFC6690] Shelby, Z., "Constrained RESTful Environments (CoRE) Link + Format", RFC 6690, DOI 10.17487/RFC6690, August 2012, + . + + [RFC7030] Pritikin, M., Ed., Yee, P., Ed., and D. Harkins, Ed., + "Enrollment over Secure Transport", RFC 7030, + DOI 10.17487/RFC7030, October 2013, + . + + [RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained + Application Protocol (CoAP)", RFC 7252, + DOI 10.17487/RFC7252, June 2014, + . + + [RFC7925] Tschofenig, H., Ed. and T. Fossati, "Transport Layer + Security (TLS) / Datagram Transport Layer Security (DTLS) + Profiles for the Internet of Things", RFC 7925, + DOI 10.17487/RFC7925, July 2016, + . + + [RFC7959] Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in + the Constrained Application Protocol (CoAP)", RFC 7959, + DOI 10.17487/RFC7959, August 2016, + . + + [RFC8075] Castellani, A., Loreto, S., Rahman, A., Fossati, T., and + E. Dijk, "Guidelines for Mapping Implementations: HTTP to + the Constrained Application Protocol (CoAP)", RFC 8075, + DOI 10.17487/RFC8075, February 2017, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + + [RFC8422] Nir, Y., Josefsson, S., and M. Pegourie-Gonnard, "Elliptic + Curve Cryptography (ECC) Cipher Suites for Transport Layer + Security (TLS) Versions 1.2 and Earlier", RFC 8422, + DOI 10.17487/RFC8422, August 2018, + . + + [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol + Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, + . + + [RFC8551] Schaad, J., Ramsdell, B., and S. Turner, "Secure/ + Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 + Message Specification", RFC 8551, DOI 10.17487/RFC8551, + April 2019, . + + [RFC8710] Fossati, T., Hartke, K., and C. Bormann, "Multipart + Content-Format for the Constrained Application Protocol + (CoAP)", RFC 8710, DOI 10.17487/RFC8710, February 2020, + . + + [RFC9147] Rescorla, E., Tschofenig, H., and N. Modadugu, "The + Datagram Transport Layer Security (DTLS) Protocol Version + 1.3", RFC 9147, DOI 10.17487/RFC9147, April 2022, + . + +10.2. Informative References + + [BCP195] Sheffer, Y., Holz, R., and P. Saint-Andre, + "Recommendations for Secure Use of Transport Layer + Security (TLS) and Datagram Transport Layer Security + (DTLS)", BCP 195, RFC 7525, May 2015. + + + + [CORE-PARAMS] + IANA, "Constrained RESTful Environments (CoRE) + Parameters", + . + + [IEEE802.15.4] + IEEE, "IEEE 802.15.4-2020 - IEEE Standard for Low-Rate + Wireless Networks", May 2020. + + [IEEE802.1AR] + IEEE, "IEEE Standard for Local and metropolitan area + networks - Secure Device Identity", December 2009. + + [PKI-GUIDE] + Moskowitz, R., Birkholz, H., Xia, L., and M. Richardson, + "Guide for building an ECC pki", Work in Progress, + Internet-Draft, draft-moskowitz-ecdsa-pki-10, 31 January + 2021, . + + [PsQs] Heninger, N., Durumeric, Z., Wustrow, E., and J. Alex + Halderman, "Mining Your Ps and Qs: Detection of Widespread + Weak Keys in Network Devices", USENIX Security Symposium + 2012, ISBN 978-931971-95-9, August 2012. + + [RFC4919] Kushalnagar, N., Montenegro, G., and C. Schumacher, "IPv6 + over Low-Power Wireless Personal Area Networks (6LoWPANs): + Overview, Assumptions, Problem Statement, and Goals", + RFC 4919, DOI 10.17487/RFC4919, August 2007, + . + + [RFC5272] Schaad, J. and M. Myers, "Certificate Management over CMS + (CMC)", RFC 5272, DOI 10.17487/RFC5272, June 2008, + . + + [RFC5929] Altman, J., Williams, N., and L. Zhu, "Channel Bindings + for TLS", RFC 5929, DOI 10.17487/RFC5929, July 2010, + . + + [RFC6402] Schaad, J., "Certificate Management over CMS (CMC) + Updates", RFC 6402, DOI 10.17487/RFC6402, November 2011, + . + + [RFC7228] Bormann, C., Ersue, M., and A. Keranen, "Terminology for + Constrained-Node Networks", RFC 7228, + DOI 10.17487/RFC7228, May 2014, + . + + [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer + Protocol (HTTP/1.1): Message Syntax and Routing", + RFC 7230, DOI 10.17487/RFC7230, June 2014, + . + + [RFC7251] McGrew, D., Bailey, D., Campagna, M., and R. Dugal, "AES- + CCM Elliptic Curve Cryptography (ECC) Cipher Suites for + TLS", RFC 7251, DOI 10.17487/RFC7251, June 2014, + . + + [RFC7299] Housley, R., "Object Identifier Registry for the PKIX + Working Group", RFC 7299, DOI 10.17487/RFC7299, July 2014, + . + + [RFC7627] Bhargavan, K., Ed., Delignat-Lavaud, A., Pironti, A., + Langley, A., and M. Ray, "Transport Layer Security (TLS) + Session Hash and Extended Master Secret Extension", + RFC 7627, DOI 10.17487/RFC7627, September 2015, + . + + [RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves + for Security", RFC 7748, DOI 10.17487/RFC7748, January + 2016, . + + [RFC9146] Rescorla, E., Ed., Tschofenig, H., Ed., Fossati, T., and + A. Kraus, "Connection Identifier for DTLS 1.2", RFC 9146, + DOI 10.17487/RFC9146, March 2022, + . + + [RSA-FACT] Bernstein, D., Chang, Y., Cheng, C., Chou, L., Heninger, + N., Lange, T., and N. Someren, "Factoring RSA keys from + certified smart cards: Coppersmith in the wild", Advances + in Cryptology - ASIACRYPT 2013, August 2013. + + [TLS13-CHANNEL-BINDINGS] + Whited, S., "Channel Bindings for TLS 1.3", Work in + Progress, Internet-Draft, draft-ietf-kitten-tls-channel- + bindings-for-tls13-15, 4 March 2022, + . + + [TRIPLESHAKE] + Bhargavan, B., Delignat-Lavaud, A., Fournet, C., Pironti, + A., and P. Strub, "Triple Handshakes and Cookie Cutters: + Breaking and Fixing Authentication over TLS", + ISBN 978-1-4799-4686-0, DOI 10.1109/SP.2014.14, May 2014, + . + +Appendix A. EST Messages to EST-coaps + + This section shows similar examples to the ones presented in + Appendix A of [RFC7030]. The payloads in the examples are the hex- + encoded binary, generated with 'xxd -p', of the PKI certificates + created following [PKI-GUIDE]. Hex is used for visualization + purposes because a binary representation cannot be rendered well in + text. The hexadecimal representations would not be transported in + hex, but in binary. The payloads are shown unencrypted. In + practice, the message content would be transferred over an encrypted + DTLS channel. + + The certificate responses included in the examples contain Content- + Format 281 (application/pkcs7). If the client had requested Content- + Format 287 (application/pkix-cert), the server would respond with a + single DER binary certificate. That certificate would be in a + multipart-core container specifically in the case of a response to a + /est/skc query. + + These examples assume a short resource path of "/est". Even though + omitted from the examples for brevity, before making the EST-coaps + requests, a client would learn about the server supported EST-coaps + resources with a GET request for /.well-known/core?rt=ace.est* as + explained in Section 4.1. + + The corresponding CoAP headers are only shown in Appendix A.1. + Creating CoAP headers is assumed to be generally understood. + + The message content is presented in plain text in Appendix C. + +A.1. cacerts + + In EST-coaps, a cacerts message can be the following: + + GET example.com:9085/est/crts + (Accept: 281) + + The corresponding CoAP header fields are shown below. The use of + block and DTLS are shown in Appendix B. + + Ver = 1 + T = 0 (CON) + Code = 0x01 (0.01 is GET) + Token = 0x9a (client generated) + Options + Option (Uri-Host) + Option Delta = 0x3 (option# 3) + Option Length = 0xB + Option Value = "example.com" + Option (Uri-Port) + Option Delta = 0x4 (option# 3+4=7) + Option Length = 0x2 + Option Value = 9085 + Option (Uri-Path) + Option Delta = 0x4 (option# 7+4=11) + Option Length = 0x3 + Option Value = "est" + Option (Uri-Path) + Option Delta = 0x0 (option# 11+0=11) + Option Length = 0x4 + Option Value = "crts" + Option (Accept) + Option Delta = 0x6 (option# 11+6=17) + Option Length = 0x2 + Option Value = 281 + Payload = [Empty] + + As specified in Section 5.10.1 of [RFC7252], the Uri-Host and Uri- + Port Options can be omitted if they coincide with the transport + protocol destination address and port, respectively. + + A 2.05 Content response with a cert in EST-coaps will then be the + following: + + 2.05 Content (Content-Format: 281) + {payload with certificate in binary format} + + With the following CoAP fields: + + Ver = 1 + T = 2 (ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option (Content-Format) + Option Delta = 0xC (option# 12) + Option Length = 0x2 + Option Value = 281 + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 3082027a06092a864886f70d010702a082026b308202670201013100300b + 06092a864886f70d010701a082024d30820249308201efa0030201020208 + 0b8bb0fe604f6a1e300a06082a8648ce3d0403023067310b300906035504 + 0613025553310b300906035504080c024341310b300906035504070c024c + 4131143012060355040a0c0b4578616d706c6520496e6331163014060355 + 040b0c0d63657274696669636174696f6e3110300e06035504030c07526f + 6f74204341301e170d3139303133313131323730335a170d333930313236 + 3131323730335a3067310b3009060355040613025553310b300906035504 + 080c024341310b300906035504070c024c4131143012060355040a0c0b45 + 78616d706c6520496e6331163014060355040b0c0d636572746966696361 + 74696f6e3110300e06035504030c07526f6f742043413059301306072a86 + 48ce3d020106082a8648ce3d030107034200040c1b1e82ba8cc72680973f + 97edb8a0c72ab0d405f05d4fe29b997a14ccce89008313d09666b6ce375c + 595fcc8e37f8e4354497011be90e56794bd91ad951ab45a3818430818130 + 1d0603551d0e041604141df1208944d77b5f1d9dcb51ee244a523f3ef5de + 301f0603551d230418301680141df1208944d77b5f1d9dcb51ee244a523f + 3ef5de300f0603551d130101ff040530030101ff300e0603551d0f0101ff + 040403020106301e0603551d110417301581136365727469667940657861 + 6d706c652e636f6d300a06082a8648ce3d040302034800304502202b891d + d411d07a6d6f621947635ba4c43165296b3f633726f02e51ecf464bd4002 + 2100b4be8a80d08675f041fbc719acf3b39dedc85dc92b3035868cb2daa8 + f05db196a1003100 + + The payload is shown in plain text in Appendix C.1. + +A.2. enroll / reenroll + + During the (re-)enroll exchange, the EST-coaps client uses a CSR + (Content-Format 286) request in the POST request payload. The Accept + Option tells the server that the client is expecting Content-Format + 281 (PKCS #7) in the response. As shown in Appendix C.2, the CSR + contains a challengePassword, which is used for POP linking + (Section 3). + + POST [2001:db8::2:321]:61616/est/sen + (Token: 0x45) + (Accept: 281) + (Content-Format: 286) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3082018b30820131020100305c310b3009060355040613025553310b3009 + 06035504080c024341310b300906035504070c024c413114301206035504 + 0a0c0b6578616d706c6520496e63310c300a060355040b0c03496f54310f + 300d060355040513065774313233343059301306072a8648ce3d02010608 + 2a8648ce3d03010703420004c8b421f11c25e47e3ac57123bf2d9fdc494f + 028bc351cc80c03f150bf50cff958d75419d81a6a245dffae790be95cf75 + f602f9152618f816a2b23b5638e59fd9a073303406092a864886f70d0109 + 0731270c2576437630292a264a4b4a3bc3a2c280c2992f3e3c2e2c3d6b6e + 7634332323403d204e787e60303b06092a864886f70d01090e312e302c30 + 2a0603551d1104233021a01f06082b06010505070804a013301106092b06 + 010401b43b0a01040401020304300a06082a8648ce3d0403020348003045 + 02210092563a546463bd9ecff170d0fd1f2ef0d3d012160e5ee90cffedab + ec9b9a38920220179f10a3436109051abad17590a09bc87c4dce5453a6fc + 1135a1e84eed754377 + + After verification of the CSR by the server, a 2.04 Changed response + with the issued certificate will be returned to the client. + + 2.04 Changed + (Token: 0x45) + (Content-Format: 281) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3082026e06092a864886f70d010702a082025f3082025b0201013100300b + 06092a864886f70d010701a08202413082023d308201e2a0030201020208 + 7e7661d7b54e4632300a06082a8648ce3d040302305d310b300906035504 + 0613025553310b300906035504080c02434131143012060355040a0c0b45 + 78616d706c6520496e6331163014060355040b0c0d636572746966696361 + 74696f6e3113301106035504030c0a3830322e3141522043413020170d31 + 39303133313131323931365a180f39393939313233313233353935395a30 + 5c310b3009060355040613025553310b300906035504080c024341310b30 + 0906035504070c024c4131143012060355040a0c0b6578616d706c652049 + 6e63310c300a060355040b0c03496f54310f300d06035504051306577431 + 3233343059301306072a8648ce3d020106082a8648ce3d03010703420004 + c8b421f11c25e47e3ac57123bf2d9fdc494f028bc351cc80c03f150bf50c + ff958d75419d81a6a245dffae790be95cf75f602f9152618f816a2b23b56 + 38e59fd9a3818a30818730090603551d1304023000301d0603551d0e0416 + 041496600d8716bf7fd0e752d0ac760777ad665d02a0301f0603551d2304 + 183016801468d16551f951bfc82a431d0d9f08bc2d205b1160300e060355 + 1d0f0101ff0404030205a0302a0603551d1104233021a01f06082b060105 + 05070804a013301106092b06010401b43b0a01040401020304300a06082a + 8648ce3d0403020349003046022100c0d81996d2507d693f3c48eaa5ee94 + 91bda6db214099d98117c63b361374cd86022100a774989f4c321a5cf25d + 832a4d336a08ad67df20f1506421188a0ade6d349236a1003100 + + The request and response is shown in plain text in Appendix C.2. + +A.3. serverkeygen + + In a serverkeygen exchange, the CoAP POST request looks like the + following: + + POST 192.0.2.1:8085/est/skg + (Token: 0xa5) + (Accept: 62) + (Content-Format: 286) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 3081d03078020100301631143012060355040a0c0b736b67206578616d70 + 6c653059301306072a8648ce3d020106082a8648ce3d03010703420004c8 + b421f11c25e47e3ac57123bf2d9fdc494f028bc351cc80c03f150bf50cff + 958d75419d81a6a245dffae790be95cf75f602f9152618f816a2b23b5638 + e59fd9a000300a06082a8648ce3d040302034800304502207c553981b1fe + 349249d8a3f50a0346336b7dfaa099cf74e1ec7a37a0a760485902210084 + 79295398774b2ff8e7e82abb0c17eaef344a5088fa69fd63ee611850c34b + 0a + + The response would follow [RFC8710] and could look like the + following: + + 2.04 Changed + (Token: 0xa5) + (Content-Format: 62) + + [ The hexadecimal representations below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 84 # array(4) + 19 011C # unsigned(284) + 58 8A # bytes(138) + 308187020100301306072a8648ce3d020106082a8648ce3d030107046d30 + 6b020101042061336a86ac6e7af4a96f632830ad4e6aa0837679206094d7 + 679a01ca8c6f0c37a14403420004c8b421f11c25e47e3ac57123bf2d9fdc + 494f028bc351cc80c03f150bf50cff958d75419d81a6a245dffae790be95 + cf75f602f9152618f816a2b23b5638e59fd9 + 19 0119 # unsigned(281) + 59 01D3 # bytes(467) + 308201cf06092a864886f70d010702a08201c0308201bc0201013100300b + 06092a864886f70d010701a08201a23082019e30820144a0030201020209 + 00b3313e8f3fc9538e300a06082a8648ce3d040302301631143012060355 + 040a0c0b736b67206578616d706c65301e170d3139303930343037343430 + 335a170d3339303833303037343430335a301631143012060355040a0c0b + 736b67206578616d706c653059301306072a8648ce3d020106082a8648ce + 3d03010703420004c8b421f11c25e47e3ac57123bf2d9fdc494f028bc351 + cc80c03f150bf50cff958d75419d81a6a245dffae790be95cf75f602f915 + 2618f816a2b23b5638e59fd9a37b307930090603551d1304023000302c06 + 096086480186f842010d041f161d4f70656e53534c2047656e6572617465 + 64204365727469666963617465301d0603551d0e0416041496600d8716bf + 7fd0e752d0ac760777ad665d02a0301f0603551d2304183016801496600d + 8716bf7fd0e752d0ac760777ad665d02a0300a06082a8648ce3d04030203 + 48003045022100e95bfa25a08976652246f2d96143da39fce0dc4c9b26b9 + cce1f24164cc2b12b602201351fd8eea65764e3459d324e4345ff5b2a915 + 38c04976111796b3698bf6379ca1003100 + + The private key in the response above is without CMS EnvelopedData + and has no additional encryption beyond DTLS (Section 4.8). + + The request and response is shown in plain text in Appendix C.3. + +A.4. csrattrs + + The following is a csrattrs exchange: + + REQ: + GET example.com:61616/est/att + + RES: + 2.05 Content + (Content-Format: 285) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + 307c06072b06010101011630220603883701311b131950617273652053455 + 420617320322e3939392e31206461746106092a864886f70d010907302c06 + 0388370231250603883703060388370413195061727365205345542061732 + 0322e3939392e32206461746106092b240303020801010b06096086480165 + 03040202 + + A 2.05 Content response should contain attributes that are relevant + for the authenticated client. This example is copied from + Appendix A.2 of [RFC7030], where the base64 representation is + replaced with a hexadecimal representation of the equivalent binary + format. The EST-coaps server returns attributes that the client can + ignore if they are unknown to the client. + +Appendix B. EST-coaps Block Message Examples + + Two examples are presented in this section: + + 1. A cacerts exchange shows the use of Block2 and the block headers. + + 2. An enroll exchange shows the Block1 and Block2 size negotiation + for request and response payloads. + + The payloads are shown unencrypted. In practice, the message + contents would be binary formatted and transferred over an encrypted + DTLS tunnel. The corresponding CoAP headers are only shown in + Appendix B.1. Creating CoAP headers is assumed to be generally + known. + +B.1. cacerts + + This section provides a detailed example of the messages using DTLS + and CoAP Option Block2. The example block length is taken as 64, + which gives an SZX value of 2. + + The following is an example of a cacerts exchange over DTLS. The + content length of the cacerts response in Appendix A.1 of [RFC7030] + contains 639 bytes in binary in this example. The CoAP message adds + around 10 bytes in this example, and the DTLS record around 29 bytes. + To avoid IP fragmentation, the CoAP Block Option is used and an MTU + of 127 is assumed to stay within one IEEE 802.15.4 packet. To stay + below the MTU of 127, the payload is split in 9 packets with a + payload of 64 bytes each, followed by a last tenth packet of 63 + bytes. The client sends an IPv6 packet containing a UDP datagram + with DTLS record protection that encapsulates a CoAP request 10 times + (one fragment of the request per block). The server returns an IPv6 + packet containing a UDP datagram with the DTLS record that + encapsulates the CoAP response. The CoAP request-response exchange + with block option is shown below. Block Option is shown in a + decomposed way (block-option:NUM/M/size) indicating the kind of Block + Option (2 in this case) followed by a colon, and then the block + number (NUM), the more bit (M = 0 in Block2 response means it is last + block), and block size with exponent (2^(SZX+4)) separated by + slashes. The Length 64 is used with SZX=2. The CoAP Request is sent + Confirmable (CON), and the Content-Format of the response, even + though not shown, is 281 (application/pkcs7-mime; smime-type=certs- + only). The transfer of the 10 blocks with partially filled block + NUM=9 is shown below. + + GET example.com:9085/est/crts (2:0/0/64) --> + <-- (2:0/1/64) 2.05 Content + GET example.com:9085/est/crts (2:1/0/64) --> + <-- (2:1/1/64) 2.05 Content + | + | + | + GET example.com:9085/est/crts (2:9/0/64) --> + <-- (2:9/0/64) 2.05 Content + + The header of the GET request looks like the following: + + Ver = 1 + T = 0 (CON) + Code = 0x01 (0.1 GET) + Token = 0x9a (client generated) + Options + Option (Uri-Host) + Option Delta = 0x3 (option# 3) + Option Length = 0xB + Option Value = "example.com" + Option (Uri-Port) + Option Delta = 0x4 (option# 3+4=7) + Option Length = 0x2 + Option Value = 9085 + Option (Uri-Path) + Option Delta = 0x4 (option# 7+4=11) + Option Length = 0x3 + Option Value = "est" + Option (Uri-Path)Uri-Path) + Option Delta = 0x0 (option# 11+0=11) + Option Length = 0x4 + Option Value = "crts" + Option (Accept) + Option Delta = 0x6 (option# 11+6=17) + Option Length = 0x2 + Option Value = 281 + Payload = [Empty] + + The Uri-Host and Uri-Port Options can be omitted if they coincide + with the transport protocol destination address and port, + respectively. Explicit Uri-Host and Uri-Port Options are typically + used when an endpoint hosts multiple virtual servers and uses the + Options to route the requests accordingly. + + To provide further details on the CoAP headers, the first two and the + last blocks are written out below. The header of the first Block2 + response looks like the following: + + Ver = 1 + T = 2 (ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option# 12+11=23 Block2) + Option Length = 0x1 + Option Value = 0x0A (block#=0, M=1, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 3082027b06092a864886f70d010702a082026c308202680201013100300b + 06092a864886f70d010701a082024e3082024a308201f0a0030201020209 + 009189bc + + The header of the second Block2 response looks like the following: + + Ver = 1 + T = 2 (means ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option 12+11=23 Block2) + Option Length = 0x1 + Option Value = 0x1A (block#=1, M=1, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + df9c99244b300a06082a8648ce3d0403023067310b300906035504061302 + 5553310b300906035504080c024341310b300906035504070c024c413114 + 30120603 + + The header of the tenth and final Block2 response looks like the + following: + + Ver = 1 + T = 2 (means ACK) + Code = 0x45 (2.05 Content) + Token = 0x9a (copied from request by server) + Options + Option + Option Delta = 0xC (option# 12 Content-Format) + Option Length = 0x2 + Option Value = 281 + Option + Option Delta = 0xB (option# 12+11=23 Block2 ) + Option Length = 0x1 + Option Value = 0x92 (block#=9, M=0, SZX=2) + + [ The hexadecimal representation below would NOT be transported + in hex, but in binary. Hex is used because a binary representation + cannot be rendered well in text. ] + + Payload = + 2ec0b4af52d46f3b7ecc9687ddf267bcec368f7b7f1353272f022047a28a + e5c7306163b3c3834bab3c103f743070594c089aaa0ac870cd13b902caa1 + 003100 + +B.2. enroll / reenroll + + In this example, the requested Block2 size of 256 bytes, required by + the client, is transferred to the server in the very first request + message. The block size of 256 is equal to (2^(SZX+4)), which gives + SZX=4. The notation for block numbering is the same as in + Appendix B.1. The header fields and the payload are omitted for + brevity. + + POST [2001:db8::2:1]:61616/est/sen (CON)(1:0/1/256) + {CSR (frag# 1)} --> + + <-- (ACK) (1:0/1/256) (2.31 Continue) + POST [2001:db8::2:1]:61616/est/sen (CON)(1:1/1/256) + {CSR (frag# 2)} --> + <-- (ACK) (1:1/1/256) (2.31 Continue) + . + . + . + POST [2001:db8::2:1]:61616/est/sen (CON)(1:N1/0/256) + {CSR(frag# N1+1)}--> + | + ...........Immediate response ......... + | + <-- (ACK) (1:N1/0/256)(2:0/1/256)(2.04 Changed) + {Cert resp (frag# 1)} + POST [2001:db8::2:1]:61616/est/sen (CON)(2:1/0/256) --> + <-- (ACK) (2:1/1/256)(2.04 Changed) + {Cert resp (frag# 2)} + . + . + . + POST [2001:db8::2:321]:61616/est/sen (CON)(2:N2/0/256) --> + <-- (ACK) (2:N2/0/256) (2.04 Changed) + {Cert resp (frag# N2+1)} + + Figure 6: EST-coaps Enrollment with Multiple Blocks + + N1+1 blocks have been transferred from client to server, and N2+1 + blocks have been transferred from server to client. + +Appendix C. Message Content Breakdown + + This appendix presents the hexadecimal dumps of the binary payloads + in plain text shown in Appendix A. + +C.1. cacerts + + The cacerts response containing one root CA certificate is presented + in plain text in the following: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 831953162763987486 (0xb8bb0fe604f6a1e) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=CA, L=LA, O=Example Inc, + OU=certification, CN=Root CA + Validity + Not Before: Jan 31 11:27:03 2019 GMT + Not After : Jan 26 11:27:03 2039 GMT + Subject: C=US, ST=CA, L=LA, O=Example Inc, + OU=certification, CN=Root CA + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:0c:1b:1e:82:ba:8c:c7:26:80:97:3f:97:ed:b8: + a0:c7:2a:b0:d4:05:f0:5d:4f:e2:9b:99:7a:14:cc: + ce:89:00:83:13:d0:96:66:b6:ce:37:5c:59:5f:cc: + 8e:37:f8:e4:35:44:97:01:1b:e9:0e:56:79:4b:d9: + 1a:d9:51:ab:45 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + 1D:F1:20:89:44:D7:7B:5F:1D:9D:CB:51:EE:24:4A:52:3F:3E:F5:DE + X509v3 Authority Key Identifier: + keyid: + 1D:F1:20:89:44:D7:7B:5F:1D:9D:CB:51:EE:24:4A:52:3F:3E:F5:DE + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + email:certify@example.com + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:2b:89:1d:d4:11:d0:7a:6d:6f:62:19:47:63:5b: + a4:c4:31:65:29:6b:3f:63:37:26:f0:2e:51:ec:f4:64:bd:40: + 02:21:00:b4:be:8a:80:d0:86:75:f0:41:fb:c7:19:ac:f3:b3: + 9d:ed:c8:5d:c9:2b:30:35:86:8c:b2:da:a8:f0:5d:b1:96 + +C.2. enroll / reenroll + + The enrollment request is presented in plain text in the following: + + Certificate Request: + Data: + Version: 0 (0x0) + Subject: C=US, ST=CA, L=LA, O=example Inc, + OU=IoT/serialNumber=Wt1234 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Attributes: + challengePassword: <256-bit POP linking value> + Requested Extensions: + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:92:56:3a:54:64:63:bd:9e:cf:f1:70:d0:fd: + 1f:2e:f0:d3:d0:12:16:0e:5e:e9:0c:ff:ed:ab:ec:9b:9a:38: + 92:02:20:17:9f:10:a3:43:61:09:05:1a:ba:d1:75:90:a0:9b: + c8:7c:4d:ce:54:53:a6:fc:11:35:a1:e8:4e:ed:75:43:77 + + The CSR contains a challengePassword, which is used for POP linking + (Section 3). The CSR also contains an id-on-hardwareModuleName + hardware identifier to customize the returned certificate to the + requesting device (See [RFC7299] and [PKI-GUIDE]). + + The issued certificate presented in plain text in the following: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 9112578475118446130 (0x7e7661d7b54e4632) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=CA, O=Example Inc, + OU=certification, CN=802.1AR CA + Validity + Not Before: Jan 31 11:29:16 2019 GMT + Not After : Dec 31 23:59:59 9999 GMT + Subject: C=US, ST=CA, L=LA, O=example Inc, + OU=IoT/serialNumber=Wt1234 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + X509v3 Authority Key Identifier: + keyid: + 68:D1:65:51:F9:51:BF:C8:2A:43:1D:0D:9F:08:BC:2D:20:5B:11:60 + + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:c0:d8:19:96:d2:50:7d:69:3f:3c:48:ea:a5: + ee:94:91:bd:a6:db:21:40:99:d9:81:17:c6:3b:36:13:74:cd: + 86:02:21:00:a7:74:98:9f:4c:32:1a:5c:f2:5d:83:2a:4d:33: + 6a:08:ad:67:df:20:f1:50:64:21:18:8a:0a:de:6d:34:92:36 + +C.3. serverkeygen + + The following is the server-side key generation request presented in + plain text: + + Certificate Request: + Data: + Version: 0 (0x0) + Subject: O=skg example + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Attributes: + a0:00 + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:7c:55:39:81:b1:fe:34:92:49:d8:a3:f5:0a:03: + 46:33:6b:7d:fa:a0:99:cf:74:e1:ec:7a:37:a0:a7:60:48:59: + 02:21:00:84:79:29:53:98:77:4b:2f:f8:e7:e8:2a:bb:0c:17: + ea:ef:34:4a:50:88:fa:69:fd:63:ee:61:18:50:c3:4b:0a + + The following is the private key content of the server-side key + generation response presented in plain text: + + Private-Key: (256 bit) + priv: + 61:33:6a:86:ac:6e:7a:f4:a9:6f:63:28:30:ad:4e: + 6a:a0:83:76:79:20:60:94:d7:67:9a:01:ca:8c:6f: + 0c:37 + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + + The following is the certificate in the server-side key generation + response payload presented in plain text: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b3:31:3e:8f:3f:c9:53:8e + Signature Algorithm: ecdsa-with-SHA256 + Issuer: O=skg example + Validity + Not Before: Sep 4 07:44:03 2019 GMT + Not After : Aug 30 07:44:03 2039 GMT + Subject: O=skg example + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c8:b4:21:f1:1c:25:e4:7e:3a:c5:71:23:bf:2d: + 9f:dc:49:4f:02:8b:c3:51:cc:80:c0:3f:15:0b:f5: + 0c:ff:95:8d:75:41:9d:81:a6:a2:45:df:fa:e7:90: + be:95:cf:75:f6:02:f9:15:26:18:f8:16:a2:b2:3b: + 56:38:e5:9f:d9 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + X509v3 Authority Key Identifier: + keyid: + 96:60:0D:87:16:BF:7F:D0:E7:52:D0:AC:76:07:77:AD:66:5D:02:A0 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:e9:5b:fa:25:a0:89:76:65:22:46:f2:d9:61: + 43:da:39:fc:e0:dc:4c:9b:26:b9:cc:e1:f2:41:64:cc:2b:12: + b6:02:20:13:51:fd:8e:ea:65:76:4e:34:59:d3:24:e4:34:5f: + f5:b2:a9:15:38:c0:49:76:11:17:96:b3:69:8b:f6:37:9c + +Acknowledgements + + The authors are very grateful to Klaus Hartke for his detailed + explanations on the use of Block with DTLS and his support for the + Content-Format specification. The authors would like to thank Esko + Dijk and Michael Verschoor for the valuable discussions that helped + in shaping the solution. They would also like to thank Peter + Panburana for his feedback on technical details of the solution. + Constructive comments were received from Benjamin Kaduk, Eliot Lear, + Jim Schaad, Hannes Tschofenig, Julien Vermillard, John Manuel, Oliver + Pfaff, Pete Beal, and Carsten Bormann. + + Interop tests were done by Oliver Pfaff, Thomas Werner, Oskar + Camezind, Bjorn Elmers, and Joel Hoglund. + + Robert Moskowitz provided code to create the examples. + +Contributors + + Martin Furuhed contributed to the EST-coaps specification by + providing feedback based on the Nexus EST-over-CoAPS server + implementation that started in 2015. Sandeep Kumar kick-started this + specification and was instrumental in drawing attention to the + importance of the subject. + +Authors' Addresses + + Peter van der Stok + Consultant + Email: stokcons@bbhmail.nl + + + Panos Kampanakis + Cisco Systems + Email: pkampana@cisco.com + + + Michael C. Richardson + Sandelman Software Works + Email: mcr+ietf@sandelman.ca + URI: https://www.sandelman.ca/ + + + Shahid Raza + RISE Research Institutes of Sweden + Isafjordsgatan 22 + SE-16440 Kista, Stockholm + Sweden + Email: shahid.raza@ri.se