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" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..d51afe060c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,31 @@ +## 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). + +### 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. 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..316ed48406 --- /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, + userScalable: true, + 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/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 diff --git a/docs/rfc9148-bis-source/README.md b/docs/rfc9148-bis-source/README.md new file mode 100644 index 0000000000..c9d23326d7 --- /dev/null +++ b/docs/rfc9148-bis-source/README.md @@ -0,0 +1,50 @@ +# 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.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-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) | + +## 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. **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 + +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/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/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-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-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.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 +================================================================================ 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) + + + + + + + +
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 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..eed4359a79 --- /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, onboarding email after 5 seconds): + +```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 5 seconds without holding a server open, then sends an onboarding 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 # signup onboarding workflow (5s delay) + 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..25d65068d7 --- /dev/null +++ b/examples/workflow-email-onboarding/package-lock.json @@ -0,0 +1,12929 @@ +{ + "name": "workflow-email-onboarding", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "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", + "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/@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", + "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..fc1c68d4b7 --- /dev/null +++ b/examples/workflow-email-onboarding/package.json @@ -0,0 +1,27 @@ +{ + "name": "workflow-email-onboarding", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@vercel/speed-insights": "^2.0.0", + "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..a67b5d1810 --- /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 { handleUserSignup } 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(handleUserSignup, [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 0000000000..718d6fea48 Binary files /dev/null and b/examples/workflow-email-onboarding/src/app/favicon.ico differ 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..0809044664 --- /dev/null +++ b/examples/workflow-email-onboarding/src/app/layout.tsx @@ -0,0 +1,34 @@ +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({ + 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..b4bc180486 --- /dev/null +++ b/examples/workflow-email-onboarding/src/workflows/steps.ts @@ -0,0 +1,124 @@ +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(user: Pick) { + "use step"; + + 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: [user.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 sendOnboardingEmail(user: Pick) { + "use step"; + + 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: [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) { + 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..3ade241bf9 --- /dev/null +++ b/examples/workflow-email-onboarding/src/workflows/user-signup.ts @@ -0,0 +1,23 @@ +import { sleep } from "workflow"; +import { + createUser, + sendOnboardingEmail, + sendWelcomeEmail, +} from "@/workflows/steps"; + +export async function handleUserSignup(email: string) { + "use workflow"; + + console.log(`Starting signup workflow for ${email}`); + + const user = await createUser(email); + await sendWelcomeEmail(user); + + await sleep("5s"); + + await sendOnboardingEmail(user); + + console.log("Workflow is complete! Run 'npx workflow web' to inspect your run"); + + return { userId: user.id, status: "onboarded" 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"] +} 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/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" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..737830f969 --- /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", "docs", "examples"] +} diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000000..db2dc4288e --- /dev/null +++ b/vercel.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": "nextjs", + "buildCommand": "npm run build", + "installCommand": "npm install" +}