From 62181f92588581ed34a2e99e733252c3725fc0b9 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 14 Jul 2026 15:25:34 -0400 Subject: [PATCH 1/2] feat: serve Shiny apps as MCP Apps (SEP-1865) (#4407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(mcp): JSON-RPC endpoint skeleton for MCP Apps * feat(mcp): mount /mcp handler in app handler chain when enabled * feat(mcp): postMessage tunnel connection and _shiny_* tools * feat(mcp): ui://shiny/app single-file resource with inlined assets * feat(mcp): postMessage bridge bundle overriding Shiny.createSocket * fix(mcp): use .globals for sweeper flag (assignInMyNamespace fails in later callback) * docs(mcp): NEWS entry for experimental MCP Apps support * docs(mcp): mirror MCP Apps plans, research notes, and demo app into mcp/ * feat(mcp): _shiny_http tool tunnels HTTP side channels in-process * feat(mcp): inline dynamic htmlDependencies for MCP tunnel sessions * feat(mcp): tunnel XHR side channels, downloads, host theme + context (Phase 2 client) * docs(mcp): Phase 2 NEWS + mirror plan/demo/screenshot into mcp/ * feat(mcp): inline CSS url() assets as data URIs for the sandbox * feat(mcp): exported session API — mcpToolInput, mcpUpdateModelContext, mcpSendMessage, mcpHostContext, isMcpSession * feat(mcp): author-declared MCP tools via options(shiny.mcp.tools) * feat(mcp): stdio transport for local desktop hosts * feat(mcp): direct-connect WebSocket fast path + display mode requests * docs(mcp): direct-connect/display-mode NEWS, mcptools upstream notes, QUESTIONS.md * docs(mcp): use real PR number in NEWS * docs(mcp): record decisions in QUESTIONS.md; explain direct-connect default * fix(mcp): declare processx/pkgload test deps; run stdio subprocess against installed shiny under R CMD check * feat(mcp): path-aware direct-connect base (shiny.mcp.origin, X-RSC-Request, rsconnect records) * feat(mcp): discover deployed URL from Quarto _publish.yml and Posit Publisher records * fix: pkgdown index for mcp-session; wrap-tolerant reactlog Suggests test; drop Quarto _publish.yml source * `npm run build` (GitHub Actions) * fix(mcp): use RStudio-Connect-App-Base-Url for the direct-connect base Verified against a real connect.posit.it deployment: Connect does not send X-RSC-Request to Shiny content, and rsconnect excludes its own rsconnect/ records from the bundle. The header Connect actually sends with every proxied request is RStudio-Connect-App-Base-Url, which is already the app's external base URL. Honor it first (X-RSC-Request kept for API content). * feat(mcp): shinyapps.io direct-connect base via X-Redx-Frontend-Name Verified against a real shinyapps.io deployment: the proxy passes POST /mcp through unauthenticated, sends RStudio-Connect-App-Base-Url with an EMPTY value, and identifies the external base as X-Redx-Frontend-Name (schemeless host + path). Combine that with X-Forwarded-Proto for the direct base, and prefer X-Forwarded-Host over the internal Host for the generic origin fallback and deployment-record host matching. * feat(mcp): appId namespacing so a gateway can serve multiple apps options(shiny.mcp.appId=) prefixes the internal _shiny_* tunnel tools (demo_shiny_connect, ...) and publishes the UI resource as ui://shiny/; the bridge reads appId from __shinyMcpConfig__ and prefixes its tool calls to match. mcp/gateway/shiny-mcp-gateway.mjs (zero-dep Node, stdio or HTTP) merges several app endpoints into one MCP server, so a single connector exposes many Shiny apps. E2E verified in basic-host with two apps behind one gateway, including full tunnel reactivity. * docs(mcp): add mcp/architecture.md describing the system as built * docs(mcp): compare with JamesHWade/shinymcp * fix(mcp/gateway): cookie stickiness, cold-start wake retry, drain on close shinyapps.io rejects POST to a sleeping app with 405 (only GET cold-starts an instance) and pins clients to an instance via a session cookie. The gateway now keeps a per-backend cookie jar, and on a failed POST wakes the app with a GET to its base URL and retries with backoff. Also drain in-flight requests before exiting when stdin closes. * chore(mcp): commit demo-app deployment records (no secrets; exercise the DCF direct-base path) * fix(mcp): inline render-time deps from direct createWebDependency() calls {htmlwidgets} (and friends) call createWebDependency() directly for the dependencies attached to a widget's render payload, bypassing the processDeps() MCP hook — so a dynamically shown plotly widget arrived with URL-based crosstalk/CSS deps that 404 inside the sandbox ("crosstalk is not defined"). createWebDependency() now diverts file-based deps to mcpInlineDependency() when the current reactive domain is an MCP session; href-only deps fall through to avoid recursion. Demo: cars app gains a checkbox-gated plotly plot, E2E-verified in basic-host (Plotly + crosstalk load on demand, 32 points rendered). * test(mcp): write download bytes with writeBin for Windows writeLines() opens the file path in text mode, so on Windows the CSV's \n bytes became \r\n and the _shiny_http download body assertion failed (only Windows R-CMD-check was red). writeBin(charToRaw(...)) writes the exact bytes on every platform. * chore: ignore .playwright-mcp scratch dir (git + R build) --------- Co-authored-by: schloerke --- .Rbuildignore | 2 + .gitignore | 1 + DESCRIPTION | 7 + NAMESPACE | 6 + NEWS.md | 40 + R/html-deps.R | 22 +- R/mcp-app.R | 266 ++++ R/mcp-server.R | 532 +++++++ R/mcp-session.R | 242 +++ R/mcp-stdio.R | 113 ++ R/mcp-tunnel.R | 428 ++++++ R/server.R | 332 +++-- inst/www/shared/shiny-mcp-bridge.js | 106 ++ man/mcp-session.Rd | 173 +++ mcp/QUESTIONS.md | 93 ++ mcp/README-mcp-host.md | 110 ++ mcp/README.md | 142 ++ mcp/architecture.md | 255 ++++ mcp/comparison-shinymcp.md | 155 ++ mcp/demo-app/app.R | 125 ++ .../barret/shiny-mcp-demo.dcf | 10 + .../shinyapps.io/barret/shiny-mcp-demo.dcf | 10 + mcp/demo-app2/app.R | 103 ++ .../shinyapps.io/barret/shiny-mcp-cars.dcf | 10 + mcp/design-spec.md | 167 +++ mcp/gateway/README.md | 67 + mcp/gateway/shiny-mcp-gateway.mjs | 282 ++++ mcp/implementation-plan-phase1.md | 1270 ++++++++++++++++ mcp/implementation-plan-phase2.md | 53 + mcp/mcptools-upstream-notes.md | 60 + mcp/research-notes.md | 170 +++ mcp/run-mcp-host.sh | 48 + mcp/screenshot-e2e-basic-host.png | Bin 0 -> 49296 bytes mcp/screenshot-e2e-css-fonts.png | Bin 0 -> 67693 bytes mcp/screenshot-e2e-gateway.png | Bin 0 -> 79787 bytes mcp/screenshot-e2e-phase2.png | Bin 0 -> 62244 bytes mcp/screenshot-e2e-session-api.png | Bin 0 -> 83161 bytes package-lock.json | 1305 ++++++++++++++++- package.json | 4 +- srcts/build/mcp-bridge.ts | 26 + srcts/src/mcp/__tests__/hybridSocket.test.ts | 137 ++ srcts/src/mcp/__tests__/tunnelSocket.test.ts | 113 ++ srcts/src/mcp/__tests__/tunnelXhr.test.ts | 145 ++ srcts/src/mcp/hybridSocket.ts | 143 ++ srcts/src/mcp/index.ts | 342 +++++ srcts/src/mcp/tunnelSocket.ts | 126 ++ srcts/src/mcp/tunnelXhr.ts | 300 ++++ srcts/types/build/mcp-bridge.d.ts | 1 + srcts/types/src/mcp/hybridSocket.d.ts | 42 + srcts/types/src/mcp/index.d.ts | 1 + srcts/types/src/mcp/tunnelSocket.d.ts | 29 + srcts/types/src/mcp/tunnelXhr.d.ts | 8 + tests/testthat/helper-mcp.R | 62 + tests/testthat/test-mcp-app.R | 308 ++++ tests/testthat/test-mcp-server.R | 373 +++++ tests/testthat/test-mcp-session.R | 180 +++ tests/testthat/test-mcp-stdio.R | 153 ++ tests/testthat/test-mcp-tunnel.R | 261 ++++ tests/testthat/test-reactlog.R | 8 +- tools/documentation/pkgdown.yml | 4 + 60 files changed, 9298 insertions(+), 173 deletions(-) create mode 100644 R/mcp-app.R create mode 100644 R/mcp-server.R create mode 100644 R/mcp-session.R create mode 100644 R/mcp-stdio.R create mode 100644 R/mcp-tunnel.R create mode 100644 inst/www/shared/shiny-mcp-bridge.js create mode 100644 man/mcp-session.Rd create mode 100644 mcp/QUESTIONS.md create mode 100644 mcp/README-mcp-host.md create mode 100644 mcp/README.md create mode 100644 mcp/architecture.md create mode 100644 mcp/comparison-shinymcp.md create mode 100644 mcp/demo-app/app.R create mode 100644 mcp/demo-app/rsconnect/connect.posit.it/barret/shiny-mcp-demo.dcf create mode 100644 mcp/demo-app/rsconnect/shinyapps.io/barret/shiny-mcp-demo.dcf create mode 100644 mcp/demo-app2/app.R create mode 100644 mcp/demo-app2/rsconnect/shinyapps.io/barret/shiny-mcp-cars.dcf create mode 100644 mcp/design-spec.md create mode 100644 mcp/gateway/README.md create mode 100644 mcp/gateway/shiny-mcp-gateway.mjs create mode 100644 mcp/implementation-plan-phase1.md create mode 100644 mcp/implementation-plan-phase2.md create mode 100644 mcp/mcptools-upstream-notes.md create mode 100644 mcp/research-notes.md create mode 100755 mcp/run-mcp-host.sh create mode 100644 mcp/screenshot-e2e-basic-host.png create mode 100644 mcp/screenshot-e2e-css-fonts.png create mode 100644 mcp/screenshot-e2e-gateway.png create mode 100644 mcp/screenshot-e2e-phase2.png create mode 100644 mcp/screenshot-e2e-session-api.png create mode 100644 srcts/build/mcp-bridge.ts create mode 100644 srcts/src/mcp/__tests__/hybridSocket.test.ts create mode 100644 srcts/src/mcp/__tests__/tunnelSocket.test.ts create mode 100644 srcts/src/mcp/__tests__/tunnelXhr.test.ts create mode 100644 srcts/src/mcp/hybridSocket.ts create mode 100644 srcts/src/mcp/index.ts create mode 100644 srcts/src/mcp/tunnelSocket.ts create mode 100644 srcts/src/mcp/tunnelXhr.ts create mode 100644 srcts/types/build/mcp-bridge.d.ts create mode 100644 srcts/types/src/mcp/hybridSocket.d.ts create mode 100644 srcts/types/src/mcp/index.d.ts create mode 100644 srcts/types/src/mcp/tunnelSocket.d.ts create mode 100644 srcts/types/src/mcp/tunnelXhr.d.ts create mode 100644 tests/testthat/helper-mcp.R create mode 100644 tests/testthat/test-mcp-app.R create mode 100644 tests/testthat/test-mcp-server.R create mode 100644 tests/testthat/test-mcp-session.R create mode 100644 tests/testthat/test-mcp-stdio.R create mode 100644 tests/testthat/test-mcp-tunnel.R diff --git a/.Rbuildignore b/.Rbuildignore index ab0fb78c5a..2d8fa415c3 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -38,3 +38,5 @@ ^LICENSE\.md$ ^docs$ ^\.context$ +^mcp$ +^\.playwright-mcp$ diff --git a/.gitignore b/.gitignore index 54b9db8297..635a25f158 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ madge.svg .claude/settings.local.json /docs/ .context +.playwright-mcp/ diff --git a/DESCRIPTION b/DESCRIPTION index 3baabc015b..38ccf7fce7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -113,6 +113,8 @@ Suggests: markdown, mirai, otelsdk (>= 0.2.0), + pkgload, + processx, ragg, reactlog (>= 1.0.0), rmarkdown, @@ -177,6 +179,11 @@ Collate: 'insert-ui.R' 'jqueryui.R' 'knitr.R' + 'mcp-app.R' + 'mcp-server.R' + 'mcp-session.R' + 'mcp-stdio.R' + 'mcp-tunnel.R' 'middleware-shiny.R' 'middleware.R' 'timer.R' diff --git a/NAMESPACE b/NAMESPACE index a091f0fefa..711b377b54 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -160,6 +160,7 @@ export(is.reactive) export(is.reactivevalues) export(is.shiny.appobj) export(is.singleton) +export(isMcpSession) export(isRunning) export(isTruthy) export(isolate) @@ -171,6 +172,11 @@ export(makeReactiveBinding) export(markRenderFunction) export(markdown) export(maskReactiveContext) +export(mcpHostContext) +export(mcpRequestDisplayMode) +export(mcpSendMessage) +export(mcpToolInput) +export(mcpUpdateModelContext) export(memoryCache) export(modalButton) export(modalDialog) diff --git a/NEWS.md b/NEWS.md index aef4194c5d..c1dcfefd9c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,45 @@ # shiny (development version) +* Experimental support for serving a Shiny app as an MCP App (the Model + Context Protocol Apps extension, SEP-1865). Setting `options(shiny.mcp = + TRUE)` before the app starts mounts an MCP endpoint at `/mcp` on the app's + own port; MCP hosts that support the Apps extension (Claude, Claude + Desktop, VS Code Copilot, MCPJam, ...) can then call the app's tool and + render the live, fully reactive application in a sandboxed iframe, with + Shiny's websocket traffic tunneled over the host's postMessage channel. + HTTP side channels (file upload/download, server-side DataTables and + selectize, and dynamically inserted HTML dependencies) are tunneled too, + the host's theme and style variables are applied to the app, and assets + referenced by `url()` in stylesheets (e.g. icon webfonts) are embedded as + data URIs so they render inside the sandbox. Customize the model-visible + tool with `options(shiny.mcp.tool = list(name=, description=, + inputSchema=))`. New session API: `isMcpSession()`, `mcpToolInput()`, + `mcpHostContext()`, `mcpUpdateModelContext()`, and `mcpSendMessage()` let + apps react to the model's tool arguments and host theme, keep the model's + context up to date, and send messages to the conversation. Apps can also + expose additional model-callable R functions with + `options(shiny.mcp.tools = list(list(name=, description=, inputSchema=, + handler=)))`. Adding `options(shiny.mcp.stdio = TRUE)` also speaks MCP + over stdin/stdout, so local desktop hosts can launch the app process + directly, e.g. `claude mcp add my-app -- Rscript -e + "options(shiny.mcp=TRUE, shiny.mcp.stdio=TRUE); + shiny::runApp('app', launch.browser=FALSE)"` (not supported on Windows; + stdout is reserved for the protocol). On hosts that honor the declared + content security policy, the app connects over a real WebSocket for + native-latency reactivity and falls back to the tunnel automatically + (disable with `options(shiny.mcp.direct = FALSE)`). The websocket base + URL is path-aware, so apps deployed under a sub-path (e.g. Posit + Connect's `/content/`) connect directly too — derived from + `options(shiny.mcp.origin=)`, Connect's `RStudio-Connect-App-Base-Url` + (or `X-RSC-Request`) header, shinyapps.io's `X-Redx-Frontend-Name` + header, or a + deployment record next to the app (rsconnect `.dcf` or Posit Publisher + `.toml`). Apps can also request + fullscreen/picture-in-picture with `mcpRequestDisplayMode()`. Setting a + unique `options(shiny.mcp.appId=)` per app namespaces each app's + internal tools and resource URI so a gateway can merge several Shiny + apps into a single MCP server (one connector, many apps). (#4407) + * `{watcher}` is now a required dependency and is always used for autoreload file watching, so it no longer needs to be installed separately. The legacy polling-based file watcher has been removed. (#4403) # shiny 1.14.0 diff --git a/R/html-deps.R b/R/html-deps.R index 014bb0b4b9..4fee53ddb3 100644 --- a/R/html-deps.R +++ b/R/html-deps.R @@ -24,6 +24,19 @@ createWebDependency <- function(dependency, scrubFile = TRUE) { if (!inherits(dependency, "html_dependency")) stop("Unexpected non-html_dependency type") + # Packages like {htmlwidgets} call createWebDependency() directly for + # render-time dependencies, bypassing processDeps(). Inside an MCP Apps + # sandbox those URLs can't be fetched, so divert file-based dependencies + # to the inline representation. (href-only dependencies fall through: + # mcpInlineDependency() would send them right back here.) + if ( + !is.null(dependency$src$file) && + is.null(dependency$src$href) && + isMcpSession(getDefaultReactiveDomain()) + ) { + return(mcpInlineDependency(dependency)) + } + if (is.null(dependency$src$href)) { prefix <- paste(dependency$name, "-", dependency$version, sep = "") addResourcePath(prefix, dependency$src$file) @@ -46,9 +59,16 @@ processDeps <- function(tags, session) { tags <- utils::getFromNamespace("tagify", "htmltools")(tags) ui <- takeSingletons(tags, session$singletons, desingleton = FALSE)$ui ui <- surroundSingletons(ui) + # Sessions running inside an MCP Apps sandbox can't fetch dependency + # files over HTTP, so inline them instead (see mcp-app.R). + processDep <- if (isMcpSession(session)) { + mcpInlineDependency + } else { + createWebDependency + } dependencies <- lapply( resolveDependencies(findDependencies(ui, tagify = FALSE)), - createWebDependency + processDep ) names(dependencies) <- NULL diff --git a/R/mcp-app.R b/R/mcp-app.R new file mode 100644 index 0000000000..1a59919c16 --- /dev/null +++ b/R/mcp-app.R @@ -0,0 +1,266 @@ +# Builds the `ui://shiny/app` MCP Apps resource: the app's rendered UI page +# as a single self-contained HTML document. MCP hosts render this HTML in a +# sandboxed iframe with a deny-by-default Content Security Policy (and some +# hosts currently ignore declared CSP domains entirely), so every script and +# stylesheet must be inlined and the MCP bridge script (which replaces +# Shiny's websocket with the postMessage tunnel) is injected at the end of +# . + +# Convert a file-based htmlDependency into one whose scripts/stylesheets are +# inline " + )) + } + } + for (f in dependency$stylesheet %||% character(0)) { + path <- file.path(root, f) + if (file.exists(path)) { + parts <- c(parts, inlineStylesheetFile(path)) + } + } + if (!is.null(dependency$head)) { + parts <- c(parts, dependency$head) + } + + htmltools::htmlDependency( + name = dependency$name, + version = dependency$version, + src = c(href = "_mcp_inline"), + head = paste(parts, collapse = "\n"), + all_files = FALSE + ) +} + +mcpFakePageRequest <- function() { + req <- new.env(parent = emptyenv()) + req$REQUEST_METHOD <- "GET" + req$PATH_INFO <- "/" + req$QUERY_STRING <- "" + req$HTTP_HOST <- "127.0.0.1" + req +} + +renderMcpAppHtml <- function(uiHandler, config = NULL) { + resp <- uiHandler(mcpFakePageRequest()) + if (is.null(resp) || !inherits(resp, "httpResponse")) { + stop("Unable to render the app UI for the MCP app resource") + } + html <- resp$content + if (is.raw(html)) { + html <- rawToChar(html) + Encoding(html) <- "UTF-8" + } + html <- inlineHtmlAssets(html) + + scripts <- mcpBridgeScript() + if (length(config) > 0) { + config_json <- jsonlite::toJSON( + config, + auto_unbox = TRUE, null = "null", force = TRUE + ) + scripts <- paste0( + "\n", + scripts + ) + } + sub("", paste0(scripts, "\n"), html, fixed = TRUE) +} + +mcpBridgeScript <- function() { + path <- system_file("www/shared/shiny-mcp-bridge.js", package = "shiny") + js <- readAssetText(path) + paste0( + "" + ) +} + +readAssetText <- function(file) { + txt <- readChar(file, file.info(file)$size, useBytes = TRUE) + Encoding(txt) <- "UTF-8" + txt +} + +# Rewrite relative `url(...)` references in a stylesheet to data: URIs, +# resolving them against the stylesheet's directory on disk. Once a +# stylesheet is inlined into the single-file MCP app resource, its relative +# URLs (fonts, background images — e.g. fontawesome's ../webfonts/*.woff2) +# would resolve against the sandbox origin and 404. The referenced files are +# part of the app's own dependencies, so embedding them is safe. +# +# Left untouched: data:/blob: URIs, absolute and protocol-relative URLs, +# fragment-only refs (SVG paint servers like url(#gradient)), and paths that +# don't resolve to an existing file. +rewriteCssUrls <- function(css, cssDir) { + # perl = TRUE: TRE fails on backreferences to groups that matched the + # empty string (unquoted url(...) refs); PCRE handles them. + pattern <- "url\\(\\s*(['\"]?)([^'\")]+)\\1\\s*\\)" + matches <- gregexpr(pattern, css, ignore.case = TRUE, perl = TRUE) + cache <- new.env(parent = emptyenv()) + + regmatches(css, matches) <- list(vapply( + regmatches(css, matches)[[1]], + function(token) { + ref <- trimws(sub(pattern, "\\2", token, ignore.case = TRUE, perl = TRUE)) + if (grepl("^(data:|blob:|https?://|//|#)", ref, ignore.case = TRUE)) { + return(token) + } + path <- sub("[?#].*$", "", ref) + if (!nzchar(path)) { + return(token) + } + # Legacy font fallbacks: @font-face src lists are tried in order, so + # when the (inlined) woff2 loads, ttf/otf/eot are never fetched. + # Inlining them would double-to-triple the resource size for nothing. + if (grepl("\\.(ttf|otf|eot)$", path, ignore.case = TRUE)) { + return(token) + } + candidate <- file.path(cssDir, URLdecode(path)) + if (!file.exists(candidate)) { + return(token) + } + candidate <- normalizePath(candidate) + cached <- cache[[candidate]] + if (!is.null(cached)) { + return(cached) + } + bytes <- readBin(candidate, "raw", n = file.info(candidate)$size) + # base64_enc() line-wraps long output; a raw newline inside a quoted + # CSS string is invalid and (in minified, single-line stylesheets) + # can swallow the rest of the sheet. + b64 <- gsub("[\r\n]", "", jsonlite::base64_enc(bytes)) + out <- sprintf( + 'url("data:%s;base64,%s")', + getContentType(candidate), + b64 + ) + cache[[candidate]] <- out + out + }, + character(1), + USE.NAMES = FALSE + )) + css +} + +inlineStylesheetFile <- function(file) { + css <- rewriteCssUrls(readAssetText(file), dirname(file)) + paste0("") +} + +# ` terminates it, even inside a +# JS string. `<\/script` is equivalent inside JS strings/regexes, where such +# sequences virtually always live. +escapeScriptContent <- function(x) { + gsub(" + html <- inlineTagPattern( + html, + pattern = "]*\\ssrc=\"([^\"]+)\"[^>]*>\\s*", + build = function(file) { + paste0("") + } + ) + # + inlineTagPattern( + html, + pattern = "]*\\shref=\"([^\"]+)\"[^>]*/?>", + build = inlineStylesheetFile, + onlyIf = function(tag) grepl("stylesheet", tag, fixed = TRUE) + ) +} + +inlineTagPattern <- function(html, pattern, build, onlyIf = NULL) { + matches <- gregexpr(pattern, html, ignore.case = TRUE)[[1]] + if (identical(as.integer(matches[1]), -1L)) { + return(html) + } + + lengths <- attr(matches, "match.length") + out <- character(0) + last <- 1 + for (i in seq_along(matches)) { + start <- matches[i] + end <- start + lengths[i] - 1 + tag <- substr(html, start, end) + replacement <- tag + if (is.null(onlyIf) || isTRUE(onlyIf(tag))) { + url <- sub(pattern, "\\1", tag, ignore.case = TRUE) + file <- resolveAssetFile(url) + if (!is.null(file)) { + replacement <- build(file) + } else { + # The sandbox can't load external refs anyway; drop them so the + # document doesn't point at unreachable URLs. + replacement <- "" + } + } + out <- c(out, substr(html, last, start - 1), replacement) + last <- end + 1 + } + out <- c(out, substr(html, last, nchar(html))) + paste(out, collapse = "") +} diff --git a/R/mcp-server.R b/R/mcp-server.R new file mode 100644 index 0000000000..c66ffacfd9 --- /dev/null +++ b/R/mcp-server.R @@ -0,0 +1,532 @@ +# Experimental support for serving a Shiny app as an MCP App (SEP-1865). +# +# When `options(shiny.mcp = TRUE)` is set before the app starts, a Model +# Context Protocol endpoint (JSON-RPC over streamable HTTP, JSON responses) +# is mounted at `/mcp` on the app's own httpuv server. MCP hosts that +# support the Apps extension (`io.modelcontextprotocol/ui`) can then call +# the app's tool and render the live application in a sandboxed iframe; +# reactivity is tunneled over postMessage -> tools/call (see mcp-tunnel.R +# and srcts/src/mcp/). + +MCP_PROTOCOL_VERSIONS <- c("2024-11-05", "2025-03-26", "2025-06-18") +MCP_RESOURCE_URI <- "ui://shiny/app" +MCP_RESOURCE_MIME <- "text/html;profile=mcp-app" + +mcpEnabled <- function() { + isTRUE(getOption("shiny.mcp", FALSE)) +} + +# Direct-connect fast path: declare the app's origin in the resource CSP so +# spec-compliant hosts let the iframe open a real WebSocket to the app, +# skipping the tools/call tunnel for reactivity. The bridge feature-detects +# and falls back to the tunnel, so this is safe to leave on even for hosts +# that ignore declared CSP (e.g. claude.ai today). +mcpDirectEnabled <- function() { + isTRUE(getOption("shiny.mcp.direct", TRUE)) +} + +mcpDisplayModes <- function() { + modes <- getOption("shiny.mcp.displayModes", c("inline", "fullscreen", "pip")) + modes <- intersect(as.character(modes), c("inline", "fullscreen", "pip")) + if (length(modes) == 0) modes <- "inline" + modes +} + +# Optional app identity, for gateways that merge several Shiny MCP +# endpoints behind a single MCP server. When set, the internal `_shiny_*` +# tool names are prefixed ("sales" -> "sales_shiny_connect") and the app +# resource is published as ui://shiny/, so tools and resources from +# different apps never collide at the gateway. +mcpAppId <- function() { + id <- getOption("shiny.mcp.appId", NULL) + if (!is.character(id) || length(id) != 1 || is.na(id) || !nzchar(id)) { + return(NULL) + } + if (!grepl("^[A-Za-z0-9_-]+$", id)) { + if (!isTRUE(.globals$mcpAppIdWarned)) { + .globals$mcpAppIdWarned <- TRUE + warning( + "Ignoring options(shiny.mcp.appId): ", + "it may only contain letters, digits, '_' and '-'" + ) + } + return(NULL) + } + id +} + +mcpResourceUri <- function() { + id <- mcpAppId() + if (is.null(id)) MCP_RESOURCE_URI else paste0("ui://shiny/", id) +} + +# "_shiny_connect" -> "_shiny_connect" when an appId is set. +mcpTunnelToolName <- function(base) { + id <- mcpAppId() + if (is.null(id)) base else paste0(id, base) +} + +# Inverse of mcpTunnelToolName(): strip the appId prefix from an incoming +# tools/call name so dispatch can match the canonical `_shiny_*` names. +mcpTunnelLocalName <- function(name) { + id <- mcpAppId() + if (!is.null(id) && startsWith(name, paste0(id, "_shiny_"))) { + return(substring(name, nchar(id) + 1)) + } + name +} + +# The app's externally reachable base URL (may include a path, e.g. Posit +# Connect's /content/), for the direct-connect fast path. Priority: +# +# 1. options(shiny.mcp.origin) — explicit full URL, for nonstandard proxies. +# 2. RStudio-Connect-App-Base-Url — Posit Connect sends the app's external +# base URL (https:///content/) with every request it +# proxies to Shiny content. Verified against a real Connect deployment. +# 3. X-RSC-Request — the full external URL of the request, sent by Connect +# to API content; strip the trailing /mcp to get the content base. +# 4. X-Redx-Frontend-Name — shinyapps.io sends the external host + path +# (no scheme, e.g. "barret.shinyapps.io/my-app/"); combine with +# X-Forwarded-Proto. Verified against a real shinyapps.io deployment. +# 5. rsconnect deployment records (rsconnect/**/*.dcf next to the app) — +# the "output files" written by deployment carry the content `url`. Only +# trusted when the record's host matches the request's Host header, so a +# local run of a deployed app dir never points the iframe at production. +# 6. Origin derived from the request (X-Forwarded-Host falling back to +# Host, + X-Forwarded-Proto) — right for localhost and root-mounted +# https tunnels, but pathless. +# 7. The local httpuv origin (stdio transport has no request). +mcpDirectBase <- function(req) { + reqHeader <- function(name) { + value <- tryCatch(req[[name]], error = function(e) NULL) + if (is.character(value) && nzchar(value %||% "")) value else NULL + } + stripSlash <- function(x) sub("/+$", "", x) + + origin_opt <- getOption("shiny.mcp.origin", NULL) + if (is.character(origin_opt) && nzchar(origin_opt)) { + return(stripSlash(origin_opt)) + } + + connect_base <- reqHeader("HTTP_RSTUDIO_CONNECT_APP_BASE_URL") + if (!is.null(connect_base)) { + return(stripSlash(connect_base)) + } + + rsc <- reqHeader("HTTP_X_RSC_REQUEST") + if (!is.null(rsc)) { + return(stripSlash(sub("/mcp/?$", "", rsc))) + } + + proto <- reqHeader("HTTP_X_FORWARDED_PROTO") %||% "http" + + redx <- reqHeader("HTTP_X_REDX_FRONTEND_NAME") + if (!is.null(redx)) { + return(stripSlash(sprintf("%s://%s", proto, redx))) + } + + host <- reqHeader("HTTP_X_FORWARDED_HOST") %||% reqHeader("HTTP_HOST") + deployed <- mcpDeployedUrl( + getShinyOption("appDir", default = getwd()), + host + ) + if (!is.null(deployed)) { + return(deployed) + } + + if (is.null(host)) { + return(.globals$mcpLocalOrigin) + } + sprintf("%s://%s", proto, host) +} + +# Look up the deployed URL for this app from deployment records written +# next to the app, requiring an exact host match against the serving +# request. Sources, in order: +# - {rsconnect} records: rsconnect/**/*.dcf (field `url`) +# - Posit Publisher records: .posit/publish/deployments/*.toml (`direct_url`) +mcpDeployedUrl <- function(appDir, host) { + if (is.null(host) || !nzchar(host %||% "")) { + return(NULL) + } + candidates <- c( + mcpRsconnectRecordUrls(appDir), + mcpPublisherRecordUrls(appDir) + ) + for (url in candidates) { + if (!is.character(url) || is.na(url) || !nzchar(url)) next + url_host <- sub("^https?://([^/]+).*$", "\\1", url) + if (identical(url_host, host)) { + return(sub("/+$", "", url)) + } + } + NULL +} + +mcpRsconnectRecordUrls <- function(appDir) { + records <- tryCatch( + list.files( + file.path(appDir, "rsconnect"), + pattern = "\\.dcf$", recursive = TRUE, full.names = TRUE + ), + error = function(e) character(0) + ) + vapply(records, function(record) { + tryCatch( + unname(read.dcf(record, fields = "url")[1, "url"]), + error = function(e) NA_character_ + ) + }, character(1), USE.NAMES = FALSE) +} + +# Posit Publisher's deployment records are TOML; extract `direct_url` +# ("the link to use when accessing a deployed ...") without a TOML parser. +mcpPublisherRecordUrls <- function(appDir) { + records <- tryCatch( + list.files( + file.path(appDir, ".posit", "publish", "deployments"), + pattern = "\\.toml$", full.names = TRUE + ), + error = function(e) character(0) + ) + urls <- character(0) + for (record in records) { + lines <- tryCatch( + readLines(record, warn = FALSE), + error = function(e) character(0) + ) + hits <- regmatches( + lines, + regexpr("^\\s*direct_url\\s*=\\s*['\"]([^'\"]+)['\"]", lines) + ) + for (hit in hits) { + urls <- c(urls, sub("^\\s*direct_url\\s*=\\s*['\"]([^'\"]+)['\"].*$", "\\1", hit)) + } + } + urls +} + +# CSP source expressions are origins; extract one from a (possibly +# path-bearing) base URL. +mcpBaseOrigin <- function(base) { + m <- regmatches(base, regexpr("^https?://[^/]+", base)) + if (length(m) == 0) base else m +} + +mcpWsOrigin <- function(origin) { + sub("^http", "ws", origin) +} + +mcpToolInfo <- function() { + opt <- getOption("shiny.mcp.tool", list()) + list( + name = opt$name %||% "open_shiny_app", + description = opt$description %||% paste( + "Open the interactive Shiny application so the user can view and", + "interact with it. Call this when the user wants to see the app." + ), + inputSchema = opt$inputSchema %||% + list(type = "object", properties = empty_named_list()) + ) +} + +mcpCorsHeaders <- function() { + list( + "Access-Control-Allow-Origin" = "*", + "Access-Control-Allow-Methods" = "GET, POST, OPTIONS", + "Access-Control-Allow-Headers" = paste( + "Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version,", + "Last-Event-Id" + ) + ) +} + +mcpJsonResponse <- function(payload, status = 200L) { + httpResponse( + status = status, + content_type = "application/json", + content = enc2utf8(as.character(jsonlite::toJSON( + payload, + auto_unbox = TRUE, null = "null", force = TRUE + ))), + headers = mcpCorsHeaders() + ) +} + +mcpResult <- function(id, result) { + list(jsonrpc = "2.0", id = id, result = result) +} + +mcpError <- function(id, code, message) { + list(jsonrpc = "2.0", id = id, error = list(code = code, message = message)) +} + +# Returns a Shiny HTTP handler serving the MCP endpoint at /mcp. +# +# `uiHandler` renders the app's UI page (used for resources/read); +# `wsHandler` is the app's websocket handler from createAppHandlers(), +# which accepts any object satisfying the httpuv WebSocket duck type +# (used by _shiny_connect to open tunneled sessions). +mcpHttpHandler <- function(uiHandler, wsHandler) { + force(uiHandler) + force(wsHandler) + + function(req) { + path <- sub("/$", "", req$PATH_INFO %||% "") + if (!identical(path, "/mcp")) { + return(NULL) + } + + method <- req$REQUEST_METHOD + if (identical(method, "OPTIONS")) { + return(httpResponse(204L, "text/plain", "", headers = mcpCorsHeaders())) + } + if (!identical(method, "POST")) { + return(httpResponse( + 405L, "text/plain", + "shiny MCP endpoint: use POST (streamable HTTP, JSON responses).", + headers = c(mcpCorsHeaders(), list(Allow = "POST, OPTIONS")) + )) + } + + body <- tryCatch( + { + raw <- req$rook.input$read() + safeFromJSON(rawToChar(raw), simplifyVector = FALSE) + }, + error = function(e) NULL + ) + if (is.null(body) || !is.list(body)) { + return(mcpJsonResponse(mcpError(NULL, -32700L, "Parse error"), 400L)) + } + + out <- tryCatch( + mcpDispatch(body, uiHandler, wsHandler, req = req), + error = function(e) mcpError(body$id, -32603L, conditionMessage(e)) + ) + if (is.null(out)) { + # Notification: no response body + return(httpResponse( + 202L, "application/json", "", + headers = mcpCorsHeaders() + )) + } + hybrid_chain(out, mcpJsonResponse) + } +} + +mcpDispatch <- function(body, uiHandler, wsHandler, req = NULL) { + method <- body$method + if (!is.character(method) || length(method) != 1) { + return(mcpError(body$id, -32600L, "Invalid Request")) + } + if (grepl("^notifications/", method)) { + return(NULL) + } + + switch(method, + "initialize" = mcpResult(body$id, mcpInitializeResult(body)), + "ping" = mcpResult(body$id, empty_named_list()), + "tools/list" = mcpResult(body$id, list(tools = mcpToolsList())), + "tools/call" = mcpToolCall(body, uiHandler, wsHandler), + "resources/list" = mcpResult(body$id, list(resources = mcpResourcesList())), + "resources/read" = mcpResourcesRead(body, uiHandler, req), + mcpError(body$id, -32601L, "Method not found") + ) +} + +mcpInitializeResult <- function(body) { + requested <- body$params$protocolVersion %||% "" + version <- if (requested %in% MCP_PROTOCOL_VERSIONS) { + requested + } else { + MCP_PROTOCOL_VERSIONS[length(MCP_PROTOCOL_VERSIONS)] + } + list( + protocolVersion = version, + capabilities = list( + tools = list(listChanged = FALSE), + resources = list(subscribe = FALSE, listChanged = FALSE) + ), + serverInfo = list( + name = "shiny", + version = as.character(get_package_version("shiny")) + ) + ) +} + +mcpToolsList <- function() { + info <- mcpToolInfo() + # unname: a partially named list would serialize as a JSON object rather + # than the array that tools/list requires. + unname(c( + list(list( + name = info$name, + description = info$description, + inputSchema = info$inputSchema, + `_meta` = list(ui = list(resourceUri = mcpResourceUri())) + )), + mcpTunnelToolsList(), + lapply(mcpAuthorTools(warn = TRUE), function(tool) { + list( + name = tool$name, + description = tool$description, + inputSchema = tool$inputSchema %||% + list(type = "object", properties = empty_named_list()) + ) + }) + )) +} + +# Author-declared tools from options(shiny.mcp.tools = list(...)). Each spec +# is a list with `name`, `description`, optional `inputSchema`, and a +# `handler` function taking the (parsed) arguments as a named list. Handlers +# run in the server R process without a session and may return a promise. +# Invalid specs are skipped (reported once, from tools/list). +mcpAuthorTools <- function(warn = FALSE) { + specs <- getOption("shiny.mcp.tools", list()) + reserved <- c( + mcpToolInfo()$name, + vapply(mcpTunnelToolsList(), function(t) t$name, character(1)) + ) + out <- list() + for (spec in specs) { + problem <- if (!is.list(spec) || !is.character(spec$name %||% NULL)) { + "it has no `name`" + } else if (spec$name %in% reserved) { + sprintf("the name '%s' is reserved", spec$name) + } else if (!is.function(spec$handler %||% NULL)) { + "its `handler` is not a function" + } else if (!is.character(spec$description %||% NULL)) { + "it has no `description`" + } + if (!is.null(problem)) { + if (warn) { + warning( + "Ignoring a tool in options(shiny.mcp.tools) because ", problem, + if (is.character(spec$name %||% NULL)) sprintf(" ('%s')", spec$name), + call. = FALSE + ) + } + next + } + out[[spec$name]] <- spec + } + out +} + +# Convert a handler's return value into an MCP CallToolResult. +mcpAuthorToolResult <- function(id, value) { + if (is.null(value)) { + return(mcpResult(id, list( + content = list(list(type = "text", text = "ok")) + ))) + } + if (is.character(value) || is.numeric(value) || is.logical(value)) { + return(mcpResult(id, list( + content = list(list( + type = "text", + text = paste(as.character(value), collapse = "\n") + )) + ))) + } + if (is.list(value)) { + json <- as.character(jsonlite::toJSON( + value, + auto_unbox = TRUE, null = "null", force = TRUE + )) + return(mcpResult(id, list( + content = list(list(type = "text", text = json)), + structuredContent = value + ))) + } + mcpResult(id, list( + content = list(list(type = "text", text = paste( + utils::capture.output(print(value)), + collapse = "\n" + ))) + )) +} + +mcpAuthorToolCall <- function(tool, params, id) { + args <- params$arguments %||% empty_named_list() + hybrid_chain( + tryCatch(tool$handler(args), error = function(e) e), + function(value) { + if (inherits(value, "condition")) { + return(mcpToolErrorResult(id, conditionMessage(value))) + } + mcpAuthorToolResult(id, value) + }, + catch = function(e) { + mcpToolErrorResult(id, conditionMessage(e)) + } + ) +} + +mcpToolCall <- function(body, uiHandler, wsHandler) { + name <- body$params$name %||% "" + info <- mcpToolInfo() + if (identical(name, info$name)) { + return(mcpResult(body$id, list( + content = list(list( + type = "text", + text = "The Shiny app is now displayed in the conversation." + )) + ))) + } + localName <- mcpTunnelLocalName(name) + if (startsWith(localName, "_shiny_")) { + return(mcpTunnelToolCall( + localName, + body$params$arguments %||% empty_named_list(), + body$id, + wsHandler + )) + } + authorTool <- mcpAuthorTools()[[name]] + if (!is.null(authorTool)) { + return(mcpAuthorToolCall(authorTool, body$params, body$id)) + } + mcpError(body$id, -32602L, sprintf("Unknown tool: %s", name)) +} + +mcpResourcesList <- function() { + list(list( + uri = mcpResourceUri(), + name = "Shiny application", + description = "The interactive Shiny application UI.", + mimeType = MCP_RESOURCE_MIME, + `_meta` = list(ui = list(prefersBorder = TRUE)) + )) +} + +mcpResourcesRead <- function(body, uiHandler, req = NULL) { + uri <- body$params$uri %||% "" + if (!identical(uri, mcpResourceUri())) { + return(mcpError(body$id, -32602L, sprintf("Unknown resource: %s", uri))) + } + + base <- if (mcpDirectEnabled()) mcpDirectBase(req) + config <- dropNulls(list( + appId = mcpAppId(), + directBase = base, + displayModes = as.list(mcpDisplayModes()) + )) + + ui_meta <- list(prefersBorder = TRUE) + if (!is.null(base)) { + origin <- mcpBaseOrigin(base) + ui_meta$csp <- list( + connectDomains = list(origin, mcpWsOrigin(origin)) + ) + } + + html <- renderMcpAppHtml(uiHandler, config = config) + mcpResult(body$id, list(contents = list(list( + uri = mcpResourceUri(), + mimeType = MCP_RESOURCE_MIME, + text = html, + `_meta` = list(ui = ui_meta) + )))) +} diff --git a/R/mcp-session.R b/R/mcp-session.R new file mode 100644 index 0000000000..d890bbb4b0 --- /dev/null +++ b/R/mcp-session.R @@ -0,0 +1,242 @@ +#' Interact with the MCP host from a Shiny app +#' +#' @description +#' `r lifecycle::badge("experimental")` +#' +#' When a Shiny app is served as an MCP App (by setting +#' `options(shiny.mcp = TRUE)` before the app starts), it renders inside an +#' MCP host's conversation (e.g. Claude, Claude Desktop, VS Code Copilot) +#' and can exchange information with the host: +#' +#' * `isMcpSession()` reports whether the current session is connected +#' through an MCP host (as opposed to a regular browser). +#' * `mcpToolInput()` returns the arguments the model supplied when it +#' called the app's tool, as a named list (reactive read). Declare the +#' expected arguments with +#' `options(shiny.mcp.tool = list(inputSchema = ...))`. +#' * `mcpHostContext()` returns the host's context (theme, locale, display +#' mode, ...) as a named list (reactive read). +#' * `mcpUpdateModelContext()` updates the model's context for future +#' conversation turns. Each call overwrites the previous update; the host +#' typically delivers it with the user's next message. +#' * `mcpSendMessage()` sends a user-role message to the host's chat +#' interface, which may trigger a model response. +#' +#' Outside of an MCP session, `mcpUpdateModelContext()` and +#' `mcpSendMessage()` do nothing and return `FALSE`, so apps can call them +#' unconditionally. +#' +#' @section Deployment and the direct-connect fast path: +#' On hosts that honor the declared content security policy, the app's +#' iframe connects over a real WebSocket for native-latency reactivity, +#' falling back to the tools/call tunnel automatically. The websocket URL +#' is derived, in order, from: `options(shiny.mcp.origin = )` (a full base +#' URL, which may include a path); Posit Connect's +#' `RStudio-Connect-App-Base-Url` (or `X-RSC-Request`) header; +#' shinyapps.io's `X-Redx-Frontend-Name` header; +#' a deployment record next to the app whose URL matches the serving host +#' (rsconnect's `rsconnect/**/*.dcf` or Posit Publisher's +#' `.posit/publish/deployments/*.toml`) — so apps deployed +#' under a sub-path such as `/content/` work without configuration; +#' or the origin of the MCP request itself. Set +#' `options(shiny.mcp.direct = FALSE)` to always use the tunnel. +#' +#' @section Multiple apps behind one server: +#' A gateway can merge several Shiny MCP endpoints into a single MCP +#' server, so one connector exposes many apps. For that to work each app +#' must set a unique `options(shiny.mcp.appId = "")` (letters, digits, +#' `_`, `-`): the app's internal tunnel tools are then prefixed with the +#' id and its UI resource is published as `ui://shiny/`, so tools and +#' resources from different apps do not collide when merged. App-facing +#' tool names must also be unique across the merged apps. +#' +#' @section Additional tools: +#' Beyond the tool that opens the app, authors can expose plain R functions +#' as MCP tools the model may call directly, via +#' `options(shiny.mcp.tools = list(...))`. Each tool is a list with a +#' `name`, a `description`, an optional `inputSchema` (JSON Schema as a +#' nested list), and a `handler` function that receives the parsed +#' arguments as a named list. Handlers run in the server R process outside +#' of any Shiny session and may return a character vector (sent as text), a +#' list (sent as JSON `structuredContent`), or a promise. Errors are +#' reported to the model as tool errors. +#' +#' ```r +#' options(shiny.mcp.tools = list( +#' list( +#' name = "get_sample_stats", +#' description = "Summary statistics for a normal sample of size n.", +#' inputSchema = list( +#' type = "object", +#' properties = list(n = list(type = "integer")), +#' required = list("n") +#' ), +#' handler = function(args) { +#' x <- rnorm(args$n) +#' list(n = args$n, mean = mean(x), sd = stats::sd(x)) +#' } +#' ) +#' )) +#' ``` +#' +#' @param text A character string. For `mcpUpdateModelContext()`, the +#' human/model-readable context text; for `mcpSendMessage()`, the message +#' to send to the chat. +#' @param data An optional named list of structured, machine-readable +#' context data (serialized as JSON). +#' @param session The Shiny session object. +#' +#' @return +#' `isMcpSession()` returns `TRUE` or `FALSE`. `mcpToolInput()` and +#' `mcpHostContext()` return a named list, or `NULL` when nothing has been +#' received (they must be called within a reactive context). +#' `mcpUpdateModelContext()` and `mcpSendMessage()` invisibly return `TRUE` +#' if the message was sent to the host and `FALSE` otherwise. +#' +#' @examples +#' \dontrun{ +#' options(shiny.mcp = TRUE) +#' options(shiny.mcp.tool = list( +#' name = "open_sales_dashboard", +#' description = "Show the interactive sales dashboard.", +#' inputSchema = list( +#' type = "object", +#' properties = list( +#' region = list(type = "string", description = "Region to focus on") +#' ) +#' ) +#' )) +#' +#' server <- function(input, output, session) { +#' # React to arguments the model passed to the tool +#' observe({ +#' region <- mcpToolInput()$region +#' if (!is.null(region)) { +#' updateSelectInput(session, "region", selected = region) +#' } +#' }) +#' +#' # Keep the model informed about what the user is looking at +#' observe({ +#' mcpUpdateModelContext( +#' text = paste("The user is viewing region", input$region), +#' data = list(region = input$region) +#' ) +#' }) +#' } +#' } +#' +#' @name mcp-session +NULL + +#' @rdname mcp-session +#' @export +isMcpSession <- function(session = getDefaultReactiveDomain()) { + if (is.null(session)) { + return(FALSE) + } + req <- tryCatch(suppressWarnings(session$request), error = function(e) NULL) + if (is.null(req)) { + return(FALSE) + } + # Tunneled sessions carry a marker on the fake websocket request; + # direct-connect sessions (a real WebSocket opened by the MCP bridge) + # identify themselves with ?mcp=1 on the websocket URL. + if (identical( + tryCatch(req$HTTP_MCP_TUNNEL, error = function(e) NULL), + "1" + )) { + return(TRUE) + } + query <- tryCatch(req$QUERY_STRING, error = function(e) NULL) + is.character(query) && grepl("(^\\??|&)mcp=1(&|$)", query) +} + +#' @rdname mcp-session +#' @export +mcpToolInput <- function(session = getDefaultReactiveDomain()) { + if (is.null(session)) { + stop("mcpToolInput() must be called from within a Shiny session") + } + mcpParseClientData(session$clientData$mcp_tool_input) +} + +#' @rdname mcp-session +#' @export +mcpHostContext <- function(session = getDefaultReactiveDomain()) { + if (is.null(session)) { + stop("mcpHostContext() must be called from within a Shiny session") + } + mcpParseClientData(session$clientData$mcp_host_context) +} + +mcpParseClientData <- function(json) { + if (is.null(json) || !is.character(json) || !nzchar(json)) { + return(NULL) + } + tryCatch( + safeFromJSON(json, simplifyVector = FALSE), + error = function(e) NULL + ) +} + +#' @rdname mcp-session +#' @export +mcpUpdateModelContext <- function( + text = NULL, + data = NULL, + session = getDefaultReactiveDomain() +) { + if (is.null(text) && is.null(data)) { + stop("mcpUpdateModelContext() requires `text` and/or `data`") + } + if (!isMcpSession(session)) { + return(invisible(FALSE)) + } + params <- dropNulls(list( + content = if (!is.null(text)) { + list(list(type = "text", text = text)) + }, + structuredContent = data + )) + session$sendCustomMessage("shiny.mcp.updateModelContext", params) + invisible(TRUE) +} + +#' @rdname mcp-session +#' @export +mcpSendMessage <- function( + text, + session = getDefaultReactiveDomain() +) { + if (!is.character(text) || length(text) != 1 || !nzchar(text)) { + stop("mcpSendMessage() requires a non-empty character string `text`") + } + if (!isMcpSession(session)) { + return(invisible(FALSE)) + } + session$sendCustomMessage("shiny.mcp.sendMessage", list( + role = "user", + content = list(list(type = "text", text = text)) + )) + invisible(TRUE) +} + +#' @param mode The display mode to request: `"inline"`, `"fullscreen"`, or +#' `"pip"`. The host may decline; observe `mcpHostContext()$displayMode` +#' for the mode actually in effect. Declare the modes the app supports +#' with `options(shiny.mcp.displayModes = c("inline", "fullscreen"))` +#' (default: all three). +#' @rdname mcp-session +#' @export +mcpRequestDisplayMode <- function( + mode = c("inline", "fullscreen", "pip"), + session = getDefaultReactiveDomain() +) { + mode <- match.arg(mode) + if (!isMcpSession(session)) { + return(invisible(FALSE)) + } + session$sendCustomMessage("shiny.mcp.requestDisplayMode", list(mode = mode)) + invisible(TRUE) +} diff --git a/R/mcp-stdio.R b/R/mcp-stdio.R new file mode 100644 index 0000000000..9c8ca68976 --- /dev/null +++ b/R/mcp-stdio.R @@ -0,0 +1,113 @@ +# Stdio transport for the MCP Apps endpoint (see mcp-server.R). +# +# With `options(shiny.mcp = TRUE, shiny.mcp.stdio = TRUE)`, the running app +# also speaks MCP over stdin/stdout — newline-delimited JSON-RPC, the +# framing local desktop hosts (Claude Desktop, `claude mcp add` without +# --transport http) use when they launch a server process themselves: +# +# { "mcpServers": { "my-app": { +# "command": "Rscript", +# "args": ["-e", "options(shiny.mcp=TRUE, shiny.mcp.stdio=TRUE); shiny::runApp('path/to/app', launch.browser=FALSE)"] +# } } } +# +# stdin is read non-blockingly from a `later`-scheduled poll loop, so it +# coexists with the httpuv/reactive event loop that runApp() drives; both +# transports dispatch through the same mcpDispatch(). stdout is reserved +# for protocol messages — app code must not print to it (use message(), +# which goes to stderr). Not supported on Windows (non-blocking stdin). + +mcpStdioEnabled <- function() { + isTRUE(getOption("shiny.mcp.stdio", FALSE)) +} + +mcpStdioHandleLine <- function(line, dispatch, write) { + if (!nzchar(trimws(line))) { + return(invisible()) + } + + body <- tryCatch( + safeFromJSON(line, simplifyVector = FALSE), + error = function(e) NULL + ) + if (is.null(body) || !is.list(body)) { + write(mcpStdioSerialize(mcpError(NULL, -32700L, "Parse error"))) + return(invisible()) + } + + out <- tryCatch( + dispatch(body), + error = function(e) mcpError(body$id, -32603L, conditionMessage(e)) + ) + if (is.null(out)) { + # Notification: no response + return(invisible()) + } + hybrid_chain( + out, + function(response) { + write(mcpStdioSerialize(response)) + }, + catch = function(e) { + write(mcpStdioSerialize( + mcpError(body$id, -32603L, conditionMessage(e)) + )) + } + ) + invisible() +} + +mcpStdioSerialize <- function(payload) { + as.character(jsonlite::toJSON( + payload, + auto_unbox = TRUE, null = "null", force = TRUE + )) +} + +# Start the stdin poll loop. Returns a function that stops it. +mcpStdioStart <- function(dispatch, pollSecs = 0.05) { + if (.Platform$OS.type == "windows") { + warning( + "options(shiny.mcp.stdio) is not supported on Windows ", + "(non-blocking stdin); use the HTTP transport at /mcp instead.", + call. = FALSE + ) + return(invisible(function() invisible())) + } + + con <- file("stdin", open = "r", blocking = FALSE) + out <- stdout() + stopped <- FALSE + + write <- function(x) { + writeLines(x, con = out) + flush(out) + } + + poll <- function() { + if (stopped) { + return(invisible()) + } + lines <- tryCatch( + readLines(con, n = 100L, warn = FALSE), + error = function(e) character(0) + ) + for (line in lines) { + tryCatch( + mcpStdioHandleLine(line, dispatch, write), + error = function(e) { + message("shiny MCP stdio: error handling message: ", + conditionMessage(e)) + } + ) + } + later::later(poll, pollSecs) + invisible() + } + later::later(poll, 0) + + invisible(function() { + stopped <<- TRUE + close(con) + invisible() + }) +} diff --git a/R/mcp-tunnel.R b/R/mcp-tunnel.R new file mode 100644 index 0000000000..113a097be5 --- /dev/null +++ b/R/mcp-tunnel.R @@ -0,0 +1,428 @@ +# The MCP Apps tunnel: a fake "websocket" satisfying the duck type that +# ShinySession/createAppHandlers() expect ($send, $close, $request, +# $onMessage, $onClose), backed by frame queues that the app iframe drives +# through the app-only `_shiny_*` tools (see mcp-server.R). +# +# Client -> server frames arrive via `_shiny_send` and are fed to the +# onMessage callbacks. Server -> client frames (session output) are queued +# and drained by `_shiny_receive`, which long-polls: it resolves as soon as +# frames are available, or after `timeoutSecs` with an empty batch (the +# client immediately re-polls). Ordering is guaranteed by the client keeping +# a single `_shiny_receive` in flight. + +McpConnection <- R6::R6Class( + "McpConnection", + public = list( + request = NULL, + lastActivity = NULL, + initialize = function() { + private$id_ <- createUniqueId(16) + self$lastActivity <- Sys.time() + req <- new.env(parent = emptyenv()) + req$PATH_INFO <- "/websocket/" + req$QUERY_STRING <- "" + req$REQUEST_METHOD <- "GET" + # Marks sessions created over the MCP tunnel (see isMcpSession()), so + # e.g. processDeps() can inline dynamic dependencies for the sandbox. + req$HTTP_MCP_TUNNEL <- "1" + self$request <- req + }, + + # ---- websocket duck type (consumed by ShinySession/createAppHandlers) ---- + send = function(msg) { + if (private$closed_) { + return(invisible()) + } + frame <- if (is.raw(msg)) { + list(data = jsonlite::base64_enc(msg), binary = TRUE) + } else { + list(data = msg, binary = FALSE) + } + private$outbox_[[length(private$outbox_) + 1]] <- frame + private$resolvePending() + invisible() + }, + close = function(code = 1000L) { + # Server-initiated close (e.g. session$close()); tell the client via + # the `closed` flag on the next receive, and run onClose callbacks. + if (private$closed_) { + return(invisible()) + } + private$closed_ <- TRUE + private$resolvePending() + private$fireClose() + invisible() + }, + onMessage = function(cb) { + private$messageCallbacks_ <- c(private$messageCallbacks_, cb) + invisible() + }, + onClose = function(cb) { + private$closeCallbacks_ <- c(private$closeCallbacks_, cb) + invisible() + }, + + # ---- tunnel side ---- + dispatchFrames = function(frames) { + self$lastActivity <- Sys.time() + for (frame in frames) { + binary <- isTRUE(frame$binary) + msg <- if (binary) jsonlite::base64_dec(frame$data) else frame$data + for (cb in private$messageCallbacks_) { + cb(binary, msg) + } + } + invisible() + }, + receiveFrames = function(timeoutSecs = 15) { + self$lastActivity <- Sys.time() + if (length(private$outbox_) > 0 || private$closed_) { + return(promises::promise_resolve(private$drain())) + } + promises::promise(function(resolve, reject) { + private$pending_ <- resolve + later::later(function() { + if (!is.null(private$pending_)) { + resolve_fn <- private$pending_ + private$pending_ <- NULL + resolve_fn(private$drain()) + } + }, timeoutSecs) + }) + }, + notifyClosed = function() { + # Client-initiated close (`_shiny_close`) or GC. + if (private$closed_) { + return(invisible()) + } + private$closed_ <- TRUE + private$resolvePending() + private$fireClose() + invisible() + }, + isClosed = function() { + private$closed_ + } + ), + active = list( + id = function() private$id_ + ), + private = list( + id_ = NULL, + outbox_ = list(), + pending_ = NULL, + closed_ = FALSE, + closeFired_ = FALSE, + messageCallbacks_ = list(), + closeCallbacks_ = list(), + drain = function() { + frames <- private$outbox_ + private$outbox_ <- list() + list(frames = frames, closed = private$closed_) + }, + resolvePending = function() { + if (!is.null(private$pending_)) { + resolve_fn <- private$pending_ + private$pending_ <- NULL + resolve_fn(private$drain()) + } + }, + fireClose = function() { + if (private$closeFired_) { + return() + } + private$closeFired_ <- TRUE + for (cb in private$closeCallbacks_) { + cb() + } + } + ) +) + +mcpConnections <- NULL +on_load({ + mcpConnections <- Map$new() +}) + +MCP_CONN_IDLE_TIMEOUT_SECS <- 60 + +mcpConnRegister <- function(conn) { + mcpConnections$set(conn$id, conn) + mcpScheduleSweep() + invisible(conn) +} + +mcpConnGet <- function(id) { + if (is.null(id) || !is.character(id)) { + return(NULL) + } + mcpConnections$get(id) +} + +mcpConnRemove <- function(id) { + mcpConnections$remove(id) +} + +# Periodically close connections whose client stopped polling (e.g. the +# iframe was destroyed without `ui/resource-teardown`). Healthy clients +# long-poll at least every ~15s, so 60s of silence means the client is gone. +mcpScheduleSweep <- function() { + if (isTRUE(.globals$mcpSweepScheduled)) { + return(invisible()) + } + .globals$mcpSweepScheduled <- TRUE + later::later(function() { + .globals$mcpSweepScheduled <- FALSE + now <- Sys.time() + for (id in mcpConnections$keys()) { + conn <- mcpConnections$get(id) + if (is.null(conn)) next + idle <- as.numeric(difftime(now, conn$lastActivity, units = "secs")) + if (idle > MCP_CONN_IDLE_TIMEOUT_SECS) { + conn$notifyClosed() + mcpConnections$remove(id) + } + } + if (mcpConnections$size() > 0) { + mcpScheduleSweep() + } + }, 30) + invisible() +} + +mcpToolResult <- function(id, structured = NULL, text = "ok") { + result <- list(content = list(list(type = "text", text = text))) + if (!is.null(structured)) { + result$structuredContent <- structured + } + mcpResult(id, result) +} + +mcpToolErrorResult <- function(id, text) { + mcpResult(id, list( + content = list(list(type = "text", text = text)), + isError = TRUE + )) +} + +# Stateful Rook input stream over an in-memory raw vector. The upload +# handler reads in 64KB chunks until it gets an empty read, so this must +# consume rather than replay. +mcpRookInput <- function(bytes) { + pos <- 0L + total <- length(bytes) + list( + read = function(l = -1L) { + if (pos >= total) { + return(raw(0)) + } + n <- if (l < 0) total - pos else min(l, total - pos) + out <- bytes[(pos + 1L):(pos + n)] + pos <<- pos + as.integer(n) + out + }, + read_lines = function(n = -1L) { + stop("read_lines is not supported for MCP-tunneled requests") + }, + rewind = function() { + pos <<- 0L + invisible() + } + ) +} + +# HTTP-shaped requests from the app iframe, executed against the in-process +# handlers that serve Shiny's side channels: /session/* (uploads, downloads, +# dataobj), shiny's own www dir, and registered resource paths. These are +# package-level handlers, so no per-app state is needed. The app's UI page +# handler is intentionally absent (the page is served via resources/read), +# as is the httpuv-level staticPaths machinery (an app's www/ dir is not +# reachable here). +mcpTunnelHttpChain <- function() { + joinHandlers(c( + sessionHandler, + system_file("www", package = "shiny"), + resourcePathHandler + )) +} + +mcpHttpToolCall <- function(params, id) { + # connectionId is optional: direct-connect sessions (real WebSocket) still + # route HTTP side channels through this tool but have no tunnel + # connection. Session endpoints are guarded by their unguessable tokens. + cid <- params$connectionId + if (!is.null(cid) && nzchar(cid %||% "")) { + conn <- mcpConnGet(cid) + if (is.null(conn) || conn$isClosed()) { + return(mcpToolErrorResult(id, "Unknown or closed connectionId")) + } + conn$lastActivity <- Sys.time() + } + + path <- params$path %||% "/" + if (!startsWith(path, "/")) { + path <- paste0("/", path) + } + query <- "" + qpos <- regexpr("?", path, fixed = TRUE) + if (qpos > 0) { + query <- substr(path, qpos + 1L, nchar(path)) + path <- substr(path, 1L, qpos - 1L) + } + + body <- if (is.null(params$body)) { + raw(0) + } else { + jsonlite::base64_dec(params$body) + } + + req <- new.env(parent = emptyenv()) + req$REQUEST_METHOD <- toupper(params$method %||% "GET") + req$SCRIPT_NAME <- "" + req$PATH_INFO <- path + req$QUERY_STRING <- query + req$CONTENT_LENGTH <- length(body) + req$rook.input <- mcpRookInput(body) + for (nm in names(params$headers %||% list())) { + value <- params$headers[[nm]] + key <- gsub("-", "_", toupper(nm), fixed = TRUE) + if (identical(key, "CONTENT_TYPE")) { + req$CONTENT_TYPE <- value + } else { + assign(paste0("HTTP_", key), value, envir = req) + } + } + + handler <- mcpTunnelHttpChain() + hybrid_chain(handler(req), function(resp) { + if (is.null(resp)) { + resp <- httpResponse(404L, "text/plain", "Not found") + } + mcpSerializeHttpResponse(id, resp) + }) +} + +mcpSerializeHttpResponse <- function(id, resp) { + content <- resp$content + if (is.character(content)) { + content <- charToRaw(enc2utf8(paste(content, collapse = "\n"))) + } else if (is.list(content) && !is.null(content$file)) { + bytes <- readBin(content$file, "raw", n = file.info(content$file)$size) + if (isTRUE(content$owned)) { + unlink(content$file) + } + content <- bytes + } + headers <- as.list(resp$headers) + headers[["Content-Type"]] <- resp$content_type + mcpToolResult( + id, + list( + status = resp$status, + headers = headers, + body = jsonlite::base64_enc(content) + ), + "http" + ) +} + +mcpTunnelToolsList <- function() { + app_only <- list(ui = list(visibility = list("app"))) + conn_arg <- list(connectionId = list(type = "string")) + list( + list( + name = mcpTunnelToolName("_shiny_connect"), + description = "Internal: open a Shiny session for the app iframe.", + inputSchema = list(type = "object", properties = empty_named_list()), + `_meta` = app_only + ), + list( + name = mcpTunnelToolName("_shiny_send"), + description = "Internal: deliver client frames to the Shiny session.", + inputSchema = list( + type = "object", + properties = c(conn_arg, list(frames = list(type = "array"))), + required = list("connectionId", "frames") + ), + `_meta` = app_only + ), + list( + name = mcpTunnelToolName("_shiny_receive"), + description = "Internal: long-poll for frames from the Shiny session.", + inputSchema = list( + type = "object", + properties = conn_arg, + required = list("connectionId") + ), + `_meta` = app_only + ), + list( + name = mcpTunnelToolName("_shiny_close"), + description = "Internal: close the Shiny session.", + inputSchema = list( + type = "object", + properties = conn_arg, + required = list("connectionId") + ), + `_meta` = app_only + ), + list( + name = mcpTunnelToolName("_shiny_http"), + description = "Internal: perform an HTTP request against the Shiny app.", + inputSchema = list( + type = "object", + properties = c(conn_arg, list( + method = list(type = "string"), + path = list(type = "string"), + headers = list(type = "object"), + body = list(type = "string", description = "base64") + )), + required = list("method", "path") + ), + `_meta` = app_only + ) + ) +} + +mcpTunnelToolCall <- function(name, params, id, wsHandler) { + if (identical(name, "_shiny_connect")) { + conn <- McpConnection$new() + ok <- wsHandler(conn) + if (!isTRUE(ok) || conn$isClosed()) { + return(mcpToolErrorResult(id, "Failed to open Shiny session")) + } + mcpConnRegister(conn) + return(mcpToolResult(id, list(connectionId = conn$id), "connected")) + } + + if (identical(name, "_shiny_http")) { + # Handles its own (optional) connectionId: direct-connect sessions + # have no tunnel connection. + return(mcpHttpToolCall(params, id)) + } + + conn <- mcpConnGet(params$connectionId) + if (is.null(conn) || conn$isClosed()) { + return(mcpToolErrorResult(id, "Unknown or closed connectionId")) + } + + if (identical(name, "_shiny_send")) { + conn$dispatchFrames(params$frames %||% list()) + return(mcpToolResult(id)) + } + if (identical(name, "_shiny_receive")) { + timeoutSecs <- params$timeoutSecs %||% 15 + if (!is.numeric(timeoutSecs) || timeoutSecs < 0 || timeoutSecs > 30) { + timeoutSecs <- 15 + } + return(promises::then(conn$receiveFrames(timeoutSecs), function(res) { + mcpToolResult(id, res, "frames") + })) + } + if (identical(name, "_shiny_close")) { + conn$notifyClosed() + mcpConnRemove(conn$id) + return(mcpToolResult(id, NULL, "closed")) + } + mcpError(id, -32602L, sprintf("Unknown tool: %s", name)) +} diff --git a/R/server.R b/R/server.R index 07f43e3812..4471d75868 100644 --- a/R/server.R +++ b/R/server.R @@ -142,180 +142,194 @@ createAppHandlers <- function(httpHandlers, serverFuncSource) { # denied (403 response for HTTP, and instant close for websocket). checkSharedSecret <- loadSharedSecret() - appHandlers <- list( - http = joinHandlers(c( - sessionHandler, - httpHandlers, - sys.www.root, - resourcePathHandler, - reactLogHandler - )), - ws = function(ws) { - if (!checkSharedSecret(ws$request$HTTP_SHINY_SHARED_SECRET)) { + wsHandler <- function(ws) { + if (!checkSharedSecret(ws$request$HTTP_SHINY_SHARED_SECRET)) { + ws$close() + return(TRUE) + } + + if (identical(ws$request$PATH_INFO, "/autoreload/")) { + if (!get_devmode_option("shiny.autoreload", FALSE)) { ws$close() return(TRUE) } - if (identical(ws$request$PATH_INFO, "/autoreload/")) { - if (!get_devmode_option("shiny.autoreload", FALSE)) { - ws$close() - return(TRUE) - } + callbackHandle <- autoReloadCallbacks$register(function() { + ws$send("autoreload") + ws$close() + }) + ws$onClose(function() { + callbackHandle() + }) + return(TRUE) + } - callbackHandle <- autoReloadCallbacks$register(function() { - ws$send("autoreload") - ws$close() - }) - ws$onClose(function() { - callbackHandle() - }) - return(TRUE) - } + if (!is.null(getOption("shiny.observer.error", NULL))) { + warning( + call. = FALSE, + "options(shiny.observer.error) is no longer supported; please unset it!" + ) + stopApp() + } - if (!is.null(getOption("shiny.observer.error", NULL))) { - warning( - call. = FALSE, - "options(shiny.observer.error) is no longer supported; please unset it!" - ) - stopApp() - } + shinysession <- ShinySession$new(ws) + appsByToken$set(shinysession$token, shinysession) + shinysession$setShowcase(.globals$showcaseDefault) + + messageHandler <- function(binary, msg) { + withReactiveDomain(shinysession, { + # To ease transition from websockets-based code. Should remove once we're stable. + if (is.character(msg)) + msg <- charToRaw(msg) + + traceOption <- getOption('shiny.trace', FALSE) + if (isTRUE(traceOption) || traceOption == "recv") { + if (binary) + message("RECV ", '$$binary data$$') + else + message("RECV ", rawToChar(msg)) + } - shinysession <- ShinySession$new(ws) - appsByToken$set(shinysession$token, shinysession) - shinysession$setShowcase(.globals$showcaseDefault) - - messageHandler <- function(binary, msg) { - withReactiveDomain(shinysession, { - # To ease transition from websockets-based code. Should remove once we're stable. - if (is.character(msg)) - msg <- charToRaw(msg) - - traceOption <- getOption('shiny.trace', FALSE) - if (isTRUE(traceOption) || traceOption == "recv") { - if (binary) - message("RECV ", '$$binary data$$') - else - message("RECV ", rawToChar(msg)) + if (isEmptyMessage(msg)) + return() + + msg <- decodeMessage(msg) + + # Set up a restore context from .clientdata_url_search before + # handling all the input values, because the restore context may be + # used by an input handler (like the one for "shiny.file"). This + # should only happen once, when the app starts. + if (is.null(shinysession$restoreContext)) { + bookmarkStore <- getShinyOption("bookmarkStore", default = "disable") + if (bookmarkStore == "disable") { + # If bookmarking is disabled, use empty context + shinysession$restoreContext <- RestoreContext$new() + } else { + # If there's bookmarked state, save it on the session object + shinysession$restoreContext <- RestoreContext$new(msg$data$.clientdata_url_search) + shinysession$createBookmarkObservers() } + } - if (isEmptyMessage(msg)) - return() - - msg <- decodeMessage(msg) - - # Set up a restore context from .clientdata_url_search before - # handling all the input values, because the restore context may be - # used by an input handler (like the one for "shiny.file"). This - # should only happen once, when the app starts. - if (is.null(shinysession$restoreContext)) { - bookmarkStore <- getShinyOption("bookmarkStore", default = "disable") - if (bookmarkStore == "disable") { - # If bookmarking is disabled, use empty context - shinysession$restoreContext <- RestoreContext$new() - } else { - # If there's bookmarked state, save it on the session object - shinysession$restoreContext <- RestoreContext$new(msg$data$.clientdata_url_search) - shinysession$createBookmarkObservers() - } - } + msg$data <- applyInputHandlers(msg$data) - msg$data <- applyInputHandlers(msg$data) - - switch( - msg$method, - init = { - - serverFunc <- withReactiveDomain(NULL, serverFuncSource()) - if (!identicalFunctionBodies(serverFunc, appvars$server)) { - appvars$server <- serverFunc - if (!is.null(appvars$server)) - { - # Tag this function as the Shiny server function. A debugger may use this - # tag to give this function special treatment. - # It's very important that it's appvars$server itself and NOT a copy that - # is invoked, otherwise new breakpoints won't be picked up. - attr(appvars$server, "shinyServerFunction") <- TRUE - registerDebugHook("server", appvars, "Server Function") - } - } + switch( + msg$method, + init = { - # Check for switching into/out of showcase mode - if (.globals$showcaseOverride && - exists(".clientdata_url_search", where = msg$data)) { - mode <- showcaseModeOfQuerystring(msg$data$.clientdata_url_search) - if (!is.null(mode)) - shinysession$setShowcase(mode) + serverFunc <- withReactiveDomain(NULL, serverFuncSource()) + if (!identicalFunctionBodies(serverFunc, appvars$server)) { + appvars$server <- serverFunc + if (!is.null(appvars$server)) + { + # Tag this function as the Shiny server function. A debugger may use this + # tag to give this function special treatment. + # It's very important that it's appvars$server itself and NOT a copy that + # is invoked, otherwise new breakpoints won't be picked up. + attr(appvars$server, "shinyServerFunction") <- TRUE + registerDebugHook("server", appvars, "Server Function") } + } - # In shinysession$createBookmarkObservers() above, observers may be - # created, which puts the shiny session in busyCount > 0 state. That - # prevents the manageInputs here from taking immediate effect, by - # default. The manageInputs here needs to take effect though, because - # otherwise the bookmark observers won't find the clientData they are - # looking for. So use `now = TRUE` to force the changes to be - # immediate. - # - # FIXME: break createBookmarkObservers into two separate steps, one - # before and one after manageInputs, and put the observer creation - # in the latter. Then add an assertion that busyCount == 0L when - # this manageInputs is called. - shinysession$manageInputs(msg$data, now = TRUE) - - # The client tells us what singletons were rendered into - # the initial page - if (!is.null(msg$data$.clientdata_singletons)) { - shinysession$singletons <- strsplit( - msg$data$.clientdata_singletons, ',')[[1]] - } + # Check for switching into/out of showcase mode + if (.globals$showcaseOverride && + exists(".clientdata_url_search", where = msg$data)) { + mode <- showcaseModeOfQuerystring(msg$data$.clientdata_url_search) + if (!is.null(mode)) + shinysession$setShowcase(mode) + } + + # In shinysession$createBookmarkObservers() above, observers may be + # created, which puts the shiny session in busyCount > 0 state. That + # prevents the manageInputs here from taking immediate effect, by + # default. The manageInputs here needs to take effect though, because + # otherwise the bookmark observers won't find the clientData they are + # looking for. So use `now = TRUE` to force the changes to be + # immediate. + # + # FIXME: break createBookmarkObservers into two separate steps, one + # before and one after manageInputs, and put the observer creation + # in the latter. Then add an assertion that busyCount == 0L when + # this manageInputs is called. + shinysession$manageInputs(msg$data, now = TRUE) + + # The client tells us what singletons were rendered into + # the initial page + if (!is.null(msg$data$.clientdata_singletons)) { + shinysession$singletons <- strsplit( + msg$data$.clientdata_singletons, ',')[[1]] + } - local({ - args <- argsForServerFunc(serverFunc, shinysession) + local({ + args <- argsForServerFunc(serverFunc, shinysession) - withReactiveDomain(shinysession, { - otel_span_session_start(domain = shinysession, { + withReactiveDomain(shinysession, { + otel_span_session_start(domain = shinysession, { - do.call( - # No corresponding ..stacktraceoff; the server func is pure - # user code - wrapFunctionLabel(appvars$server, "server", - ..stacktraceon = TRUE - ), - args - ) + do.call( + # No corresponding ..stacktraceoff; the server func is pure + # user code + wrapFunctionLabel(appvars$server, "server", + ..stacktraceon = TRUE + ), + args + ) - }) }) - }) - }, - update = { - shinysession$manageInputs(msg$data) - }, - shinysession$dispatch(msg) - ) - # The HTTP_GUID, if it exists, is for Shiny Server reporting purposes - shinysession$startTiming(ws$request$HTTP_GUID) - shinysession$requestFlush() - - # Make httpuv return control to Shiny quickly, instead of waiting - # for the usual timeout - httpuv::interrupt() - }) - } - ws$onMessage(function(binary, msg) { - # If unhandled errors occur, make sure they get properly logged - withLogErrors(messageHandler(binary, msg)) - }) - ws$onClose(function() { - shinysession$wsClosed() - appsByToken$remove(shinysession$token) - appsNeedingFlush$remove(shinysession$token) + }) + }, + update = { + shinysession$manageInputs(msg$data) + }, + shinysession$dispatch(msg) + ) + # The HTTP_GUID, if it exists, is for Shiny Server reporting purposes + shinysession$startTiming(ws$request$HTTP_GUID) + shinysession$requestFlush() + + # Make httpuv return control to Shiny quickly, instead of waiting + # for the usual timeout + httpuv::interrupt() }) + } + ws$onMessage(function(binary, msg) { + # If unhandled errors occur, make sure they get properly logged + withLogErrors(messageHandler(binary, msg)) + }) - return(TRUE) + ws$onClose(function() { + shinysession$wsClosed() + appsByToken$remove(shinysession$token) + appsNeedingFlush$remove(shinysession$token) + }) + + return(TRUE) + } + + mcpHandler <- NULL + if (mcpEnabled()) { + uiHandler <- joinHandlers(httpHandlers) + mcpHandler <- mcpHttpHandler(uiHandler, wsHandler) + # Also used by the stdio transport (see mcp-stdio.R); late-bound via + # .globals so app restarts pick up the current handlers. + .globals$mcpDispatch <- function(body) { + mcpDispatch(body, uiHandler, wsHandler) } + } + + appHandlers <- list( + http = joinHandlers(c( + sessionHandler, + mcpHandler, + httpHandlers, + sys.www.root, + resourcePathHandler, + reactLogHandler + )), + ws = wsHandler ) return(appHandlers) } @@ -391,14 +405,22 @@ startHttpuvApp <- function(appObj, port, host, quiet) { handlerManager$addHandler(appHandlers$http, "/", tail = TRUE) handlerManager$addWSHandler(appHandlers$ws, "/", tail = TRUE) + if (mcpEnabled() && mcpStdioEnabled() && is.null(.globals$mcpStdioStop)) { + .globals$mcpStdioStop <- mcpStdioStart(function(body) { + .globals$mcpDispatch(body) + }) + } + httpuvApp <- handlerManager$createHttpuvApp() httpuvApp$staticPaths <- c( appObj$staticPaths, - list( + dropNulls(list( # Always handle /session URLs dynamically, even if / is a static path. "session" = excludeStaticPath(), + # Same for /mcp when the MCP Apps endpoint is enabled. + "mcp" = if (mcpEnabled()) excludeStaticPath(), "shared" = system_file(package = "shiny", "www", "shared") - ), + )), .globals$resourcePaths ) @@ -462,6 +484,12 @@ startHttpuvApp <- function(appObj, port, host, quiet) { hostString <- paste0("[", hostString, "]") message('\n', 'Listening on http://', hostString, ':', port) } + if (mcpEnabled()) { + # Fallback origin for the direct-connect fast path when there's no + # HTTP request to derive it from (stdio transport). + localHost <- if (host %in% c("0.0.0.0", "::")) "127.0.0.1" else host + .globals$mcpLocalOrigin <- sprintf("http://%s:%s", localHost, port) + } return(startServer(host, port, httpuvApp)) } else if (is.character(port)) { if (!quiet) { diff --git a/inst/www/shared/shiny-mcp-bridge.js b/inst/www/shared/shiny-mcp-bridge.js new file mode 100644 index 0000000000..19e335bd8a --- /dev/null +++ b/inst/www/shared/shiny-mcp-bridge.js @@ -0,0 +1,106 @@ +/*! shiny 1.14.0.9000 | (c) 2012-2026 Posit Software, PBC. | License: MIT + file LICENSE */ +"use strict";(()=>{var Rd=Object.defineProperty;var ug=(t,r,n)=>r in t?Rd(t,r,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[r]=n;var Ke=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,n)=>(typeof require<"u"?require:r)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var x=(t,r)=>()=>(t&&(r=t(t=0)),r);var we=(t,r)=>{for(var n in r)Rd(t,n,{get:r[n],enumerable:!0})};var N=(t,r,n)=>ug(t,typeof r!="symbol"?r+"":r,n);function p(t,r,n){function i(s,c){if(s._zod||Object.defineProperty(s,"_zod",{value:{def:c,constr:a,traits:new Set},enumerable:!1}),s._zod.traits.has(t))return;s._zod.traits.add(t),r(s,c);let u=a.prototype,d=Object.keys(u);for(let m=0;mn?.Parent&&s instanceof n.Parent?!0:s?._zod?.traits?.has(t)}),Object.defineProperty(a,"name",{value:t}),a}function H(t){return t&&Object.assign(Ge,t),Ge}var Ad,xn,kn,$e,Ee,Ge,Qe=x(()=>{xn=Object.freeze({status:"aborted"});kn=Symbol("zod_brand"),$e=class extends Error{constructor(){super("Encountered Promise during synchronous parse. Use .parseAsync() instead.")}},Ee=class extends Error{constructor(r){super(`Encountered unidirectional transform during encode: ${r}`),this.name="ZodEncodeError"}};(Ad=globalThis).__zod_globalConfig??(Ad.__zod_globalConfig={});Ge=globalThis.__zod_globalConfig});var _={};we(_,{BIGINT_FORMAT_RANGES:()=>ca,Class:()=>ea,NUMBER_FORMAT_RANGES:()=>sa,aborted:()=>Ce,allowsEval:()=>na,assert:()=>fg,assertEqual:()=>lg,assertIs:()=>pg,assertNever:()=>mg,assertNotEqual:()=>dg,assignProp:()=>Re,base64ToUint8Array:()=>Md,base64urlToUint8Array:()=>Og,cached:()=>xt,captureStackTrace:()=>Sn,cleanEnum:()=>Tg,cleanRegex:()=>nr,clone:()=>ie,cloneDef:()=>hg,createTransparentProxy:()=>xg,defineLazy:()=>O,esc:()=>zn,escapeRegex:()=>ve,explicitlyAborted:()=>ua,extend:()=>Sg,finalizeIssue:()=>ce,floatSafeRemainder:()=>ta,getElementAtPath:()=>vg,getEnumValues:()=>rr,getLengthableOrigin:()=>ar,getParsedType:()=>$g,getSizableOrigin:()=>ir,hexToUint8Array:()=>Ug,isObject:()=>Xe,isPlainObject:()=>Ae,issue:()=>kt,joinValues:()=>f,jsonStringifyReplacer:()=>$t,merge:()=>Ig,mergeDefs:()=>je,normalizeParams:()=>$,nullish:()=>Ze,numKeys:()=>_g,objectClone:()=>gg,omit:()=>zg,optionalKeys:()=>aa,parsedType:()=>b,partial:()=>Pg,pick:()=>kg,prefixIssues:()=>de,primitiveTypes:()=>ia,promiseAllObject:()=>yg,propertyKeyTypes:()=>or,randomString:()=>bg,required:()=>jg,safeExtend:()=>wg,shallowClone:()=>oa,slugify:()=>ra,stringifyPrimitive:()=>y,uint8ArrayToBase64:()=>Ld,uint8ArrayToBase64url:()=>Dg,uint8ArrayToHex:()=>Ng,unwrapMessage:()=>tr});function lg(t){return t}function dg(t){return t}function pg(t){}function mg(t){throw new Error("Unexpected value in exhaustive check")}function fg(t){}function rr(t){let r=Object.values(t).filter(i=>typeof i=="number");return Object.entries(t).filter(([i,e])=>r.indexOf(+i)===-1).map(([i,e])=>e)}function f(t,r="|"){return t.map(n=>y(n)).join(r)}function $t(t,r){return typeof r=="bigint"?r.toString():r}function xt(t){return{get value(){{let n=t();return Object.defineProperty(this,"value",{value:n}),n}throw new Error("cached value already set")}}}function Ze(t){return t==null}function nr(t){let r=t.startsWith("^")?1:0,n=t.endsWith("$")?t.length-1:t.length;return t.slice(r,n)}function ta(t,r){let n=t/r,i=Math.round(n),e=Number.EPSILON*Math.max(Math.abs(n),1);return Math.abs(n-i)n?.[i],t):t}function yg(t){let r=Object.keys(t),n=r.map(i=>t[i]);return Promise.all(n).then(i=>{let e={};for(let o=0;or};if(r?.message!==void 0){if(r?.error!==void 0)throw new Error("Cannot specify both `message` and `error` params");r.error=r.message}return delete r.message,typeof r.error=="string"?{...r,error:()=>r.error}:r}function xg(t){let r;return new Proxy({},{get(n,i,e){return r??(r=t()),Reflect.get(r,i,e)},set(n,i,e,o){return r??(r=t()),Reflect.set(r,i,e,o)},has(n,i){return r??(r=t()),Reflect.has(r,i)},deleteProperty(n,i){return r??(r=t()),Reflect.deleteProperty(r,i)},ownKeys(n){return r??(r=t()),Reflect.ownKeys(r)},getOwnPropertyDescriptor(n,i){return r??(r=t()),Reflect.getOwnPropertyDescriptor(r,i)},defineProperty(n,i,e){return r??(r=t()),Reflect.defineProperty(r,i,e)}})}function y(t){return typeof t=="bigint"?t.toString()+"n":typeof t=="string"?`"${t}"`:`${t}`}function aa(t){return Object.keys(t).filter(r=>t[r]._zod.optin==="optional"&&t[r]._zod.optout==="optional")}function kg(t,r){let n=t._zod.def,i=n.checks;if(i&&i.length>0)throw new Error(".pick() cannot be used on object schemas containing refinements");let o=je(t._zod.def,{get shape(){let a={};for(let s in r){if(!(s in n.shape))throw new Error(`Unrecognized key: "${s}"`);r[s]&&(a[s]=n.shape[s])}return Re(this,"shape",a),a},checks:[]});return ie(t,o)}function zg(t,r){let n=t._zod.def,i=n.checks;if(i&&i.length>0)throw new Error(".omit() cannot be used on object schemas containing refinements");let o=je(t._zod.def,{get shape(){let a={...t._zod.def.shape};for(let s in r){if(!(s in n.shape))throw new Error(`Unrecognized key: "${s}"`);r[s]&&delete a[s]}return Re(this,"shape",a),a},checks:[]});return ie(t,o)}function Sg(t,r){if(!Ae(r))throw new Error("Invalid input to extend: expected a plain object");let n=t._zod.def.checks;if(n&&n.length>0){let o=t._zod.def.shape;for(let a in r)if(Object.getOwnPropertyDescriptor(o,a)!==void 0)throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.")}let e=je(t._zod.def,{get shape(){let o={...t._zod.def.shape,...r};return Re(this,"shape",o),o}});return ie(t,e)}function wg(t,r){if(!Ae(r))throw new Error("Invalid input to safeExtend: expected a plain object");let n=je(t._zod.def,{get shape(){let i={...t._zod.def.shape,...r};return Re(this,"shape",i),i}});return ie(t,n)}function Ig(t,r){if(t._zod.def.checks?.length)throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");let n=je(t._zod.def,{get shape(){let i={...t._zod.def.shape,...r._zod.def.shape};return Re(this,"shape",i),i},get catchall(){return r._zod.def.catchall},checks:r._zod.def.checks??[]});return ie(t,n)}function Pg(t,r,n){let e=r._zod.def.checks;if(e&&e.length>0)throw new Error(".partial() cannot be used on object schemas containing refinements");let a=je(r._zod.def,{get shape(){let s=r._zod.def.shape,c={...s};if(n)for(let u in n){if(!(u in s))throw new Error(`Unrecognized key: "${u}"`);n[u]&&(c[u]=t?new t({type:"optional",innerType:s[u]}):s[u])}else for(let u in s)c[u]=t?new t({type:"optional",innerType:s[u]}):s[u];return Re(this,"shape",c),c},checks:[]});return ie(r,a)}function jg(t,r,n){let i=je(r._zod.def,{get shape(){let e=r._zod.def.shape,o={...e};if(n)for(let a in n){if(!(a in o))throw new Error(`Unrecognized key: "${a}"`);n[a]&&(o[a]=new t({type:"nonoptional",innerType:e[a]}))}else for(let a in e)o[a]=new t({type:"nonoptional",innerType:e[a]});return Re(this,"shape",o),o}});return ie(r,i)}function Ce(t,r=0){if(t.aborted===!0)return!0;for(let n=r;n{var i;return(i=n).path??(i.path=[]),n.path.unshift(t),n})}function tr(t){return typeof t=="string"?t:t?.message}function ce(t,r,n){let i=t.message?t.message:tr(t.inst?._zod.def?.error?.(t))??tr(r?.error?.(t))??tr(n.customError?.(t))??tr(n.localeError?.(t))??"Invalid input",{inst:e,continue:o,input:a,...s}=t;return s.path??(s.path=[]),s.message=i,r?.reportInput&&(s.input=a),s}function ir(t){return t instanceof Set?"set":t instanceof Map?"map":t instanceof File?"file":"unknown"}function ar(t){return Array.isArray(t)?"array":typeof t=="string"?"string":"unknown"}function b(t){let r=typeof t;switch(r){case"number":return Number.isNaN(t)?"nan":"number";case"object":{if(t===null)return"null";if(Array.isArray(t))return"array";let n=t;if(n&&Object.getPrototypeOf(n)!==Object.prototype&&"constructor"in n&&n.constructor)return n.constructor.name}}return r}function kt(...t){let[r,n,i]=t;return typeof r=="string"?{message:r,code:"custom",input:n,inst:i}:{...r}}function Tg(t){return Object.entries(t).filter(([r,n])=>Number.isNaN(Number.parseInt(r,10))).map(r=>r[1])}function Md(t){let r=atob(t),n=new Uint8Array(r.length);for(let i=0;ir.toString(16).padStart(2,"0")).join("")}var Cd,Sn,na,$g,or,ia,sa,ca,ea,w=x(()=>{Qe();Cd=Symbol("evaluating");Sn="captureStackTrace"in Error?Error.captureStackTrace:(...t)=>{};na=xt(()=>{if(Ge.jitless||typeof navigator<"u"&&navigator?.userAgent?.includes("Cloudflare"))return!1;try{let t=Function;return new t(""),!0}catch{return!1}});$g=t=>{let r=typeof t;switch(r){case"undefined":return"undefined";case"string":return"string";case"number":return Number.isNaN(t)?"nan":"number";case"boolean":return"boolean";case"function":return"function";case"bigint":return"bigint";case"symbol":return"symbol";case"object":return Array.isArray(t)?"array":t===null?"null":t.then&&typeof t.then=="function"&&t.catch&&typeof t.catch=="function"?"promise":typeof Map<"u"&&t instanceof Map?"map":typeof Set<"u"&&t instanceof Set?"set":typeof Date<"u"&&t instanceof Date?"date":typeof File<"u"&&t instanceof File?"file":"object";default:throw new Error(`Unknown data type: ${r}`)}},or=new Set(["string","number","symbol"]),ia=new Set(["string","number","bigint","boolean","symbol","undefined"]);sa={safeint:[Number.MIN_SAFE_INTEGER,Number.MAX_SAFE_INTEGER],int32:[-2147483648,2147483647],uint32:[0,4294967295],float32:[-34028234663852886e22,34028234663852886e22],float64:[-Number.MAX_VALUE,Number.MAX_VALUE]},ca={int64:[BigInt("-9223372036854775808"),BigInt("9223372036854775807")],uint64:[BigInt(0),BigInt("18446744073709551615")]};ea=class{constructor(...r){}}});function zt(t,r=n=>n.message){let n={},i=[];for(let e of t.issues)e.path.length>0?(n[e.path[0]]=n[e.path[0]]||[],n[e.path[0]].push(r(e))):i.push(r(e));return{formErrors:i,fieldErrors:n}}function St(t,r=n=>n.message){let n={_errors:[]},i=(e,o=[])=>{for(let a of e.issues)if(a.code==="invalid_union"&&a.errors.length)a.errors.map(s=>i({issues:s},[...o,...a.path]));else if(a.code==="invalid_key")i({issues:a.issues},[...o,...a.path]);else if(a.code==="invalid_element")i({issues:a.issues},[...o,...a.path]);else{let s=[...o,...a.path];if(s.length===0)n._errors.push(r(a));else{let c=n,u=0;for(;un.message){let n={errors:[]},i=(e,o=[])=>{var a,s;for(let c of e.issues)if(c.code==="invalid_union"&&c.errors.length)c.errors.map(u=>i({issues:u},[...o,...c.path]));else if(c.code==="invalid_key")i({issues:c.issues},[...o,...c.path]);else if(c.code==="invalid_element")i({issues:c.issues},[...o,...c.path]);else{let u=[...o,...c.path];if(u.length===0){n.errors.push(r(c));continue}let d=n,m=0;for(;mtypeof i=="object"?i.key:i);for(let i of n)typeof i=="number"?r.push(`[${i}]`):typeof i=="symbol"?r.push(`[${JSON.stringify(String(i))}]`):/[^\w$]/.test(i)?r.push(`[${JSON.stringify(i)}]`):(r.length&&r.push("."),r.push(i));return r.join("")}function In(t){let r=[],n=[...t.issues].sort((i,e)=>(i.path??[]).length-(e.path??[]).length);for(let i of n)r.push(`\u2716 ${i.message}`),i.path?.length&&r.push(` \u2192 at ${Fd(i.path)}`);return r.join(` +`)}var qd,sr,pe,la=x(()=>{Qe();w();qd=(t,r)=>{t.name="$ZodError",Object.defineProperty(t,"_zod",{value:t._zod,enumerable:!1}),Object.defineProperty(t,"issues",{value:r,enumerable:!1}),t.message=JSON.stringify(r,$t,2),Object.defineProperty(t,"toString",{value:()=>t.message,enumerable:!1})},sr=p("$ZodError",qd),pe=p("$ZodError",qd,{Parent:Error})});var wt,cr,It,ur,Pt,jt,Tt,lr,Pn,Jd,jn,Vd,Tn,Hd,On,Bd,Dn,Wd,Un,Kd,Nn,Gd,En,Qd,da=x(()=>{Qe();la();w();wt=t=>(r,n,i,e)=>{let o=i?{...i,async:!1}:{async:!1},a=r._zod.run({value:n,issues:[]},o);if(a instanceof Promise)throw new $e;if(a.issues.length){let s=new(e?.Err??t)(a.issues.map(c=>ce(c,o,H())));throw Sn(s,e?.callee),s}return a.value},cr=wt(pe),It=t=>async(r,n,i,e)=>{let o=i?{...i,async:!0}:{async:!0},a=r._zod.run({value:n,issues:[]},o);if(a instanceof Promise&&(a=await a),a.issues.length){let s=new(e?.Err??t)(a.issues.map(c=>ce(c,o,H())));throw Sn(s,e?.callee),s}return a.value},ur=It(pe),Pt=t=>(r,n,i)=>{let e=i?{...i,async:!1}:{async:!1},o=r._zod.run({value:n,issues:[]},e);if(o instanceof Promise)throw new $e;return o.issues.length?{success:!1,error:new(t??sr)(o.issues.map(a=>ce(a,e,H())))}:{success:!0,data:o.value}},jt=Pt(pe),Tt=t=>async(r,n,i)=>{let e=i?{...i,async:!0}:{async:!0},o=r._zod.run({value:n,issues:[]},e);return o instanceof Promise&&(o=await o),o.issues.length?{success:!1,error:new t(o.issues.map(a=>ce(a,e,H())))}:{success:!0,data:o.value}},lr=Tt(pe),Pn=t=>(r,n,i)=>{let e=i?{...i,direction:"backward"}:{direction:"backward"};return wt(t)(r,n,e)},Jd=Pn(pe),jn=t=>(r,n,i)=>wt(t)(r,n,i),Vd=jn(pe),Tn=t=>async(r,n,i)=>{let e=i?{...i,direction:"backward"}:{direction:"backward"};return It(t)(r,n,e)},Hd=Tn(pe),On=t=>async(r,n,i)=>It(t)(r,n,i),Bd=On(pe),Dn=t=>(r,n,i)=>{let e=i?{...i,direction:"backward"}:{direction:"backward"};return Pt(t)(r,n,e)},Wd=Dn(pe),Un=t=>(r,n,i)=>Pt(t)(r,n,i),Kd=Un(pe),Nn=t=>async(r,n,i)=>{let e=i?{...i,direction:"backward"}:{direction:"backward"};return Tt(t)(r,n,e)},Gd=Nn(pe),En=t=>async(r,n,i)=>Tt(t)(r,n,i),Qd=En(pe)});var me={};we(me,{base64:()=>Ia,base64url:()=>Zn,bigint:()=>Na,boolean:()=>Za,browserEmail:()=>Fg,cidrv4:()=>Sa,cidrv6:()=>wa,cuid:()=>pa,cuid2:()=>ma,date:()=>Ta,datetime:()=>Da,domain:()=>Hg,duration:()=>ya,e164:()=>ja,email:()=>_a,emoji:()=>$a,extendedDuration:()=>Zg,guid:()=>ba,hex:()=>Bg,hostname:()=>Vg,html5Email:()=>Mg,httpProtocol:()=>Pa,idnEmail:()=>qg,integer:()=>Ea,ipv4:()=>xa,ipv6:()=>ka,ksuid:()=>ha,lowercase:()=>Ca,mac:()=>za,md5_base64:()=>Kg,md5_base64url:()=>Gg,md5_hex:()=>Wg,nanoid:()=>va,null:()=>Ra,number:()=>Rn,rfc5322Email:()=>Lg,sha1_base64:()=>Xg,sha1_base64url:()=>Yg,sha1_hex:()=>Qg,sha256_base64:()=>th,sha256_base64url:()=>rh,sha256_hex:()=>eh,sha384_base64:()=>oh,sha384_base64url:()=>ih,sha384_hex:()=>nh,sha512_base64:()=>sh,sha512_base64url:()=>ch,sha512_hex:()=>ah,string:()=>Ua,time:()=>Oa,ulid:()=>fa,undefined:()=>Aa,unicodeEmail:()=>Xd,uppercase:()=>Ma,uuid:()=>Ye,uuid4:()=>Rg,uuid6:()=>Ag,uuid7:()=>Cg,xid:()=>ga});function $a(){return new RegExp(Jg,"u")}function ep(t){let r="(?:[01]\\d|2[0-3]):[0-5]\\d";return typeof t.precision=="number"?t.precision===-1?`${r}`:t.precision===0?`${r}:[0-5]\\d`:`${r}:[0-5]\\d\\.\\d{${t.precision}}`:`${r}(?::[0-5]\\d(?:\\.\\d+)?)?`}function Oa(t){return new RegExp(`^${ep(t)}$`)}function Da(t){let r=ep({precision:t.precision}),n=["Z"];t.local&&n.push(""),t.offset&&n.push("([+-](?:[01]\\d|2[0-3]):[0-5]\\d)");let i=`${r}(?:${n.join("|")})`;return new RegExp(`^${Yd}T(?:${i})$`)}function dr(t,r){return new RegExp(`^[A-Za-z0-9+/]{${t}}${r}$`)}function pr(t){return new RegExp(`^[A-Za-z0-9_-]{${t}}$`)}var pa,ma,fa,ga,ha,va,ya,Zg,ba,Ye,Rg,Ag,Cg,_a,Mg,Lg,Xd,qg,Fg,Jg,xa,ka,za,Sa,wa,Ia,Zn,Vg,Hg,Pa,ja,Yd,Ta,Ua,Na,Ea,Rn,Za,Ra,Aa,Ca,Ma,Bg,Wg,Kg,Gg,Qg,Xg,Yg,eh,th,rh,nh,oh,ih,ah,sh,ch,An=x(()=>{w();pa=/^[cC][0-9a-z]{6,}$/,ma=/^[0-9a-z]+$/,fa=/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/,ga=/^[0-9a-vA-V]{20}$/,ha=/^[A-Za-z0-9]{27}$/,va=/^[a-zA-Z0-9_-]{21}$/,ya=/^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,Zg=/^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/,ba=/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,Ye=t=>t?new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${t}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`):/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,Rg=Ye(4),Ag=Ye(6),Cg=Ye(7),_a=/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/,Mg=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,Lg=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,Xd=/^[^\s@"]{1,64}@[^\s@]{1,255}$/u,qg=Xd,Fg=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,Jg="^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$";xa=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,ka=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/,za=t=>{let r=ve(t??":");return new RegExp(`^(?:[0-9A-F]{2}${r}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${r}){5}[0-9a-f]{2}$`)},Sa=/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,wa=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,Ia=/^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,Zn=/^[A-Za-z0-9_-]*$/,Vg=/^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/,Hg=/^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/,Pa=/^https?$/,ja=/^\+[1-9]\d{6,14}$/,Yd="(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))",Ta=new RegExp(`^${Yd}$`);Ua=t=>{let r=t?`[\\s\\S]{${t?.minimum??0},${t?.maximum??""}}`:"[\\s\\S]*";return new RegExp(`^${r}$`)},Na=/^-?\d+n?$/,Ea=/^-?\d+$/,Rn=/^-?\d+(?:\.\d+)?$/,Za=/^(?:true|false)$/i,Ra=/^null$/i,Aa=/^undefined$/i,Ca=/^[^A-Z]*$/,Ma=/^[^a-z]*$/,Bg=/^[0-9a-fA-F]*$/;Wg=/^[0-9a-fA-F]{32}$/,Kg=dr(22,"=="),Gg=pr(22),Qg=/^[0-9a-fA-F]{40}$/,Xg=dr(27,"="),Yg=pr(27),eh=/^[0-9a-fA-F]{64}$/,th=dr(43,"="),rh=pr(43),nh=/^[0-9a-fA-F]{96}$/,oh=dr(64,""),ih=pr(64),ah=/^[0-9a-fA-F]{128}$/,sh=dr(86,"=="),ch=pr(86)});function tp(t,r,n){t.issues.length&&r.issues.push(...de(n,t.issues))}var J,rp,Cn,Mn,La,qa,Fa,Ja,Va,Ha,Ba,Wa,Ka,Ot,Ga,Qa,Xa,Ya,es,ts,rs,ns,os,Ln=x(()=>{Qe();An();w();J=p("$ZodCheck",(t,r)=>{var n;t._zod??(t._zod={}),t._zod.def=r,(n=t._zod).onattach??(n.onattach=[])}),rp={number:"number",bigint:"bigint",object:"date"},Cn=p("$ZodCheckLessThan",(t,r)=>{J.init(t,r);let n=rp[typeof r.value];t._zod.onattach.push(i=>{let e=i._zod.bag,o=(r.inclusive?e.maximum:e.exclusiveMaximum)??Number.POSITIVE_INFINITY;r.value{(r.inclusive?i.value<=r.value:i.value{J.init(t,r);let n=rp[typeof r.value];t._zod.onattach.push(i=>{let e=i._zod.bag,o=(r.inclusive?e.minimum:e.exclusiveMinimum)??Number.NEGATIVE_INFINITY;r.value>o&&(r.inclusive?e.minimum=r.value:e.exclusiveMinimum=r.value)}),t._zod.check=i=>{(r.inclusive?i.value>=r.value:i.value>r.value)||i.issues.push({origin:n,code:"too_small",minimum:typeof r.value=="object"?r.value.getTime():r.value,input:i.value,inclusive:r.inclusive,inst:t,continue:!r.abort})}}),La=p("$ZodCheckMultipleOf",(t,r)=>{J.init(t,r),t._zod.onattach.push(n=>{var i;(i=n._zod.bag).multipleOf??(i.multipleOf=r.value)}),t._zod.check=n=>{if(typeof n.value!=typeof r.value)throw new Error("Cannot mix number and bigint in multiple_of check.");(typeof n.value=="bigint"?n.value%r.value===BigInt(0):ta(n.value,r.value)===0)||n.issues.push({origin:typeof n.value,code:"not_multiple_of",divisor:r.value,input:n.value,inst:t,continue:!r.abort})}}),qa=p("$ZodCheckNumberFormat",(t,r)=>{J.init(t,r),r.format=r.format||"float64";let n=r.format?.includes("int"),i=n?"int":"number",[e,o]=sa[r.format];t._zod.onattach.push(a=>{let s=a._zod.bag;s.format=r.format,s.minimum=e,s.maximum=o,n&&(s.pattern=Ea)}),t._zod.check=a=>{let s=a.value;if(n){if(!Number.isInteger(s)){a.issues.push({expected:i,format:r.format,code:"invalid_type",continue:!1,input:s,inst:t});return}if(!Number.isSafeInteger(s)){s>0?a.issues.push({input:s,code:"too_big",maximum:Number.MAX_SAFE_INTEGER,note:"Integers must be within the safe integer range.",inst:t,origin:i,inclusive:!0,continue:!r.abort}):a.issues.push({input:s,code:"too_small",minimum:Number.MIN_SAFE_INTEGER,note:"Integers must be within the safe integer range.",inst:t,origin:i,inclusive:!0,continue:!r.abort});return}}so&&a.issues.push({origin:"number",input:s,code:"too_big",maximum:o,inclusive:!0,inst:t,continue:!r.abort})}}),Fa=p("$ZodCheckBigIntFormat",(t,r)=>{J.init(t,r);let[n,i]=ca[r.format];t._zod.onattach.push(e=>{let o=e._zod.bag;o.format=r.format,o.minimum=n,o.maximum=i}),t._zod.check=e=>{let o=e.value;oi&&e.issues.push({origin:"bigint",input:o,code:"too_big",maximum:i,inclusive:!0,inst:t,continue:!r.abort})}}),Ja=p("$ZodCheckMaxSize",(t,r)=>{var n;J.init(t,r),(n=t._zod.def).when??(n.when=i=>{let e=i.value;return!Ze(e)&&e.size!==void 0}),t._zod.onattach.push(i=>{let e=i._zod.bag.maximum??Number.POSITIVE_INFINITY;r.maximum{let e=i.value;e.size<=r.maximum||i.issues.push({origin:ir(e),code:"too_big",maximum:r.maximum,inclusive:!0,input:e,inst:t,continue:!r.abort})}}),Va=p("$ZodCheckMinSize",(t,r)=>{var n;J.init(t,r),(n=t._zod.def).when??(n.when=i=>{let e=i.value;return!Ze(e)&&e.size!==void 0}),t._zod.onattach.push(i=>{let e=i._zod.bag.minimum??Number.NEGATIVE_INFINITY;r.minimum>e&&(i._zod.bag.minimum=r.minimum)}),t._zod.check=i=>{let e=i.value;e.size>=r.minimum||i.issues.push({origin:ir(e),code:"too_small",minimum:r.minimum,inclusive:!0,input:e,inst:t,continue:!r.abort})}}),Ha=p("$ZodCheckSizeEquals",(t,r)=>{var n;J.init(t,r),(n=t._zod.def).when??(n.when=i=>{let e=i.value;return!Ze(e)&&e.size!==void 0}),t._zod.onattach.push(i=>{let e=i._zod.bag;e.minimum=r.size,e.maximum=r.size,e.size=r.size}),t._zod.check=i=>{let e=i.value,o=e.size;if(o===r.size)return;let a=o>r.size;i.issues.push({origin:ir(e),...a?{code:"too_big",maximum:r.size}:{code:"too_small",minimum:r.size},inclusive:!0,exact:!0,input:i.value,inst:t,continue:!r.abort})}}),Ba=p("$ZodCheckMaxLength",(t,r)=>{var n;J.init(t,r),(n=t._zod.def).when??(n.when=i=>{let e=i.value;return!Ze(e)&&e.length!==void 0}),t._zod.onattach.push(i=>{let e=i._zod.bag.maximum??Number.POSITIVE_INFINITY;r.maximum{let e=i.value;if(e.length<=r.maximum)return;let a=ar(e);i.issues.push({origin:a,code:"too_big",maximum:r.maximum,inclusive:!0,input:e,inst:t,continue:!r.abort})}}),Wa=p("$ZodCheckMinLength",(t,r)=>{var n;J.init(t,r),(n=t._zod.def).when??(n.when=i=>{let e=i.value;return!Ze(e)&&e.length!==void 0}),t._zod.onattach.push(i=>{let e=i._zod.bag.minimum??Number.NEGATIVE_INFINITY;r.minimum>e&&(i._zod.bag.minimum=r.minimum)}),t._zod.check=i=>{let e=i.value;if(e.length>=r.minimum)return;let a=ar(e);i.issues.push({origin:a,code:"too_small",minimum:r.minimum,inclusive:!0,input:e,inst:t,continue:!r.abort})}}),Ka=p("$ZodCheckLengthEquals",(t,r)=>{var n;J.init(t,r),(n=t._zod.def).when??(n.when=i=>{let e=i.value;return!Ze(e)&&e.length!==void 0}),t._zod.onattach.push(i=>{let e=i._zod.bag;e.minimum=r.length,e.maximum=r.length,e.length=r.length}),t._zod.check=i=>{let e=i.value,o=e.length;if(o===r.length)return;let a=ar(e),s=o>r.length;i.issues.push({origin:a,...s?{code:"too_big",maximum:r.length}:{code:"too_small",minimum:r.length},inclusive:!0,exact:!0,input:i.value,inst:t,continue:!r.abort})}}),Ot=p("$ZodCheckStringFormat",(t,r)=>{var n,i;J.init(t,r),t._zod.onattach.push(e=>{let o=e._zod.bag;o.format=r.format,r.pattern&&(o.patterns??(o.patterns=new Set),o.patterns.add(r.pattern))}),r.pattern?(n=t._zod).check??(n.check=e=>{r.pattern.lastIndex=0,!r.pattern.test(e.value)&&e.issues.push({origin:"string",code:"invalid_format",format:r.format,input:e.value,...r.pattern?{pattern:r.pattern.toString()}:{},inst:t,continue:!r.abort})}):(i=t._zod).check??(i.check=()=>{})}),Ga=p("$ZodCheckRegex",(t,r)=>{Ot.init(t,r),t._zod.check=n=>{r.pattern.lastIndex=0,!r.pattern.test(n.value)&&n.issues.push({origin:"string",code:"invalid_format",format:"regex",input:n.value,pattern:r.pattern.toString(),inst:t,continue:!r.abort})}}),Qa=p("$ZodCheckLowerCase",(t,r)=>{r.pattern??(r.pattern=Ca),Ot.init(t,r)}),Xa=p("$ZodCheckUpperCase",(t,r)=>{r.pattern??(r.pattern=Ma),Ot.init(t,r)}),Ya=p("$ZodCheckIncludes",(t,r)=>{J.init(t,r);let n=ve(r.includes),i=new RegExp(typeof r.position=="number"?`^.{${r.position}}${n}`:n);r.pattern=i,t._zod.onattach.push(e=>{let o=e._zod.bag;o.patterns??(o.patterns=new Set),o.patterns.add(i)}),t._zod.check=e=>{e.value.includes(r.includes,r.position)||e.issues.push({origin:"string",code:"invalid_format",format:"includes",includes:r.includes,input:e.value,inst:t,continue:!r.abort})}}),es=p("$ZodCheckStartsWith",(t,r)=>{J.init(t,r);let n=new RegExp(`^${ve(r.prefix)}.*`);r.pattern??(r.pattern=n),t._zod.onattach.push(i=>{let e=i._zod.bag;e.patterns??(e.patterns=new Set),e.patterns.add(n)}),t._zod.check=i=>{i.value.startsWith(r.prefix)||i.issues.push({origin:"string",code:"invalid_format",format:"starts_with",prefix:r.prefix,input:i.value,inst:t,continue:!r.abort})}}),ts=p("$ZodCheckEndsWith",(t,r)=>{J.init(t,r);let n=new RegExp(`.*${ve(r.suffix)}$`);r.pattern??(r.pattern=n),t._zod.onattach.push(i=>{let e=i._zod.bag;e.patterns??(e.patterns=new Set),e.patterns.add(n)}),t._zod.check=i=>{i.value.endsWith(r.suffix)||i.issues.push({origin:"string",code:"invalid_format",format:"ends_with",suffix:r.suffix,input:i.value,inst:t,continue:!r.abort})}});rs=p("$ZodCheckProperty",(t,r)=>{J.init(t,r),t._zod.check=n=>{let i=r.schema._zod.run({value:n.value[r.property],issues:[]},{});if(i instanceof Promise)return i.then(e=>tp(e,n,r.property));tp(i,n,r.property)}}),ns=p("$ZodCheckMimeType",(t,r)=>{J.init(t,r);let n=new Set(r.mime);t._zod.onattach.push(i=>{i._zod.bag.mime=r.mime}),t._zod.check=i=>{n.has(i.value.type)||i.issues.push({code:"invalid_value",values:r.mime,input:i.value.type,inst:t,continue:!r.abort})}}),os=p("$ZodCheckOverwrite",(t,r)=>{J.init(t,r),t._zod.check=n=>{n.value=r.tx(n.value)}})});var mr,is=x(()=>{mr=class{constructor(r=[]){this.content=[],this.indent=0,this&&(this.args=r)}indented(r){this.indent+=1,r(this),this.indent-=1}write(r){if(typeof r=="function"){r(this,{execution:"sync"}),r(this,{execution:"async"});return}let i=r.split(` +`).filter(a=>a),e=Math.min(...i.map(a=>a.length-a.trimStart().length)),o=i.map(a=>a.slice(e)).map(a=>" ".repeat(this.indent*2)+a);for(let a of o)this.content.push(a)}compile(){let r=Function,n=this?.args,e=[...(this?.content??[""]).map(o=>` ${o}`)];return new r(...n,e.join(` +`))}}});var as,ss=x(()=>{as={major:4,minor:4,patch:3}});function js(t){if(t==="")return!0;if(/\s/.test(t)||t.length%4!==0)return!1;try{return atob(t),!0}catch{return!1}}function yp(t){if(!Zn.test(t))return!1;let r=t.replace(/[-_]/g,i=>i==="-"?"+":"/"),n=r.padEnd(Math.ceil(r.length/4)*4,"=");return js(n)}function bp(t,r=null){try{let n=t.split(".");if(n.length!==3)return!1;let[i]=n;if(!i)return!1;let e=JSON.parse(atob(i));return!("typ"in e&&e?.typ!=="JWT"||!e.alg||r&&(!("alg"in e)||e.alg!==r))}catch{return!1}}function op(t,r,n){t.issues.length&&r.issues.push(...de(n,t.issues)),r.value[n]=t.value}function Vn(t,r,n,i,e,o){let a=n in i;if(t.issues.length){if(e&&o&&!a)return;r.issues.push(...de(n,t.issues))}if(!a&&!e){t.issues.length||r.issues.push({code:"invalid_type",expected:"nonoptional",input:void 0,path:[n]});return}t.value===void 0?a&&(r.value[n]=void 0):r.value[n]=t.value}function _p(t){let r=Object.keys(t.shape);for(let i of r)if(!t.shape?.[i]?._zod?.traits?.has("$ZodType"))throw new Error(`Invalid element at key "${i}": expected a Zod schema`);let n=aa(t.shape);return{...t,keys:r,keySet:new Set(r),numKeys:r.length,optionalKeys:new Set(n)}}function $p(t,r,n,i,e,o){let a=[],s=e.keySet,c=e.catchall._zod,u=c.def.type,d=c.optin==="optional",m=c.optout==="optional";for(let h in r){if(h==="__proto__"||s.has(h))continue;if(u==="never"){a.push(h);continue}let v=c.run({value:r[h],issues:[]},i);v instanceof Promise?t.push(v.then(S=>Vn(S,n,h,r,d,m))):Vn(v,n,h,r,d,m)}return a.length&&n.issues.push({code:"unrecognized_keys",keys:a,input:r,inst:o}),t.length?Promise.all(t).then(()=>n):n}function ip(t,r,n,i){for(let o of t)if(o.issues.length===0)return r.value=o.value,r;let e=t.filter(o=>!Ce(o));return e.length===1?(r.value=e[0].value,e[0]):(r.issues.push({code:"invalid_union",input:r.value,inst:n,errors:t.map(o=>o.issues.map(a=>ce(a,i,H())))}),r)}function ap(t,r,n,i){let e=t.filter(o=>o.issues.length===0);return e.length===1?(r.value=e[0].value,r):(e.length===0?r.issues.push({code:"invalid_union",input:r.value,inst:n,errors:t.map(o=>o.issues.map(a=>ce(a,i,H())))}):r.issues.push({code:"invalid_union",input:r.value,inst:n,errors:[],inclusive:!1}),r)}function cs(t,r){if(t===r)return{valid:!0,data:t};if(t instanceof Date&&r instanceof Date&&+t==+r)return{valid:!0,data:t};if(Ae(t)&&Ae(r)){let n=Object.keys(r),i=Object.keys(t).filter(o=>n.indexOf(o)!==-1),e={...t,...r};for(let o of i){let a=cs(t[o],r[o]);if(!a.valid)return{valid:!1,mergeErrorPath:[o,...a.mergeErrorPath]};e[o]=a.data}return{valid:!0,data:e}}if(Array.isArray(t)&&Array.isArray(r)){if(t.length!==r.length)return{valid:!1,mergeErrorPath:[]};let n=[];for(let i=0;is.l&&s.r).map(([s])=>s);if(o.length&&e&&t.issues.push({...e,keys:o}),Ce(t))return t;let a=cs(r.value,n.value);if(!a.valid)throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(a.mergeErrorPath)}`);return t.value=a.data,t}function cp(t,r){for(let n=t.length-1;n>=0;n--)if(t[n]._zod[r]!=="optional")return n+1;return 0}function up(t,r,n){t.issues.length&&r.issues.push(...de(n,t.issues)),r.value[n]=t.value}function lp(t,r,n,i,e){for(let o=0;o=e){r.value.length=o;break}r.issues.push(...de(o,a.issues))}r.value[o]=a.value}for(let o=r.value.length-1;o>=i.length&&(n[o]._zod.optout==="optional"&&r.value[o]===void 0);o--)r.value.length=o;return r}function dp(t,r,n,i,e,o,a){t.issues.length&&(or.has(typeof i)?n.issues.push(...de(i,t.issues)):n.issues.push({code:"invalid_key",origin:"map",input:e,inst:o,issues:t.issues.map(s=>ce(s,a,H()))})),r.issues.length&&(or.has(typeof i)?n.issues.push(...de(i,r.issues)):n.issues.push({origin:"map",code:"invalid_element",input:e,inst:o,key:i,issues:r.issues.map(s=>ce(s,a,H()))})),n.value.set(t.value,r.value)}function pp(t,r){t.issues.length&&r.issues.push(...t.issues),r.value.add(t.value)}function mp(t,r){return r===void 0&&(t.issues.length||t.fallback)?{issues:[],value:void 0}:t}function fp(t,r){return t.value===void 0&&(t.value=r.defaultValue),t}function gp(t,r){return!t.issues.length&&t.value===void 0&&t.issues.push({code:"invalid_type",expected:"nonoptional",input:t.value,inst:r}),t}function qn(t,r,n){return t.issues.length?(t.aborted=!0,t):r._zod.run({value:t.value,issues:t.issues,fallback:t.fallback},n)}function Fn(t,r,n){if(t.issues.length)return t.aborted=!0,t;if((n.direction||"forward")==="forward"){let e=r.transform(t.value,t);return e instanceof Promise?e.then(o=>Jn(t,o,r.out,n)):Jn(t,e,r.out,n)}else{let e=r.reverseTransform(t.value,t);return e instanceof Promise?e.then(o=>Jn(t,o,r.in,n)):Jn(t,e,r.in,n)}}function Jn(t,r,n,i){return t.issues.length?(t.aborted=!0,t):n._zod.run({value:r,issues:t.issues},i)}function hp(t){return t.value=Object.freeze(t.value),t}function vp(t,r,n,i){if(!t){let e={code:"custom",input:n,inst:i,path:[...i._zod.def.path??[]],continue:!i._zod.def.abort};i._zod.def.params&&(e.params=i._zod.def.params),r.issues.push(kt(e))}}var P,et,L,us,ls,ds,ps,ms,fs,gs,hs,vs,ys,bs,_s,$s,xs,ks,zs,Ss,ws,Is,Ps,Ts,Os,Ds,Us,Ns,Hn,Es,fr,Bn,Zs,Rs,As,Cs,Ms,Ls,qs,Fs,Js,Vs,xp,Hs,gr,Bs,Ws,Ks,Wn,Gs,Qs,Xs,Ys,ec,tc,rc,Kn,nc,oc,ic,ac,sc,cc,uc,lc,Gn,hr,dc,pc,mc,fc,gc,hc,vc,yc=x(()=>{Ln();Qe();is();da();An();w();ss();w();P=p("$ZodType",(t,r)=>{var n;t??(t={}),t._zod.def=r,t._zod.bag=t._zod.bag||{},t._zod.version=as;let i=[...t._zod.def.checks??[]];t._zod.traits.has("$ZodCheck")&&i.unshift(t);for(let e of i)for(let o of e._zod.onattach)o(t);if(i.length===0)(n=t._zod).deferred??(n.deferred=[]),t._zod.deferred?.push(()=>{t._zod.run=t._zod.parse});else{let e=(a,s,c)=>{let u=Ce(a),d;for(let m of s){if(m._zod.def.when){if(ua(a)||!m._zod.def.when(a))continue}else if(u)continue;let h=a.issues.length,v=m._zod.check(a);if(v instanceof Promise&&c?.async===!1)throw new $e;if(d||v instanceof Promise)d=(d??Promise.resolve()).then(async()=>{await v,a.issues.length!==h&&(u||(u=Ce(a,h)))});else{if(a.issues.length===h)continue;u||(u=Ce(a,h))}}return d?d.then(()=>a):a},o=(a,s,c)=>{if(Ce(a))return a.aborted=!0,a;let u=e(s,i,c);if(u instanceof Promise){if(c.async===!1)throw new $e;return u.then(d=>t._zod.parse(d,c))}return t._zod.parse(u,c)};t._zod.run=(a,s)=>{if(s.skipChecks)return t._zod.parse(a,s);if(s.direction==="backward"){let u=t._zod.parse({value:a.value,issues:[]},{...s,skipChecks:!0});return u instanceof Promise?u.then(d=>o(d,a,s)):o(u,a,s)}let c=t._zod.parse(a,s);if(c instanceof Promise){if(s.async===!1)throw new $e;return c.then(u=>e(u,i,s))}return e(c,i,s)}}O(t,"~standard",()=>({validate:e=>{try{let o=jt(t,e);return o.success?{value:o.data}:{issues:o.error?.issues}}catch{return lr(t,e).then(a=>a.success?{value:a.data}:{issues:a.error?.issues})}},vendor:"zod",version:1}))}),et=p("$ZodString",(t,r)=>{P.init(t,r),t._zod.pattern=[...t?._zod.bag?.patterns??[]].pop()??Ua(t._zod.bag),t._zod.parse=(n,i)=>{if(r.coerce)try{n.value=String(n.value)}catch{}return typeof n.value=="string"||n.issues.push({expected:"string",code:"invalid_type",input:n.value,inst:t}),n}}),L=p("$ZodStringFormat",(t,r)=>{Ot.init(t,r),et.init(t,r)}),us=p("$ZodGUID",(t,r)=>{r.pattern??(r.pattern=ba),L.init(t,r)}),ls=p("$ZodUUID",(t,r)=>{if(r.version){let i={v1:1,v2:2,v3:3,v4:4,v5:5,v6:6,v7:7,v8:8}[r.version];if(i===void 0)throw new Error(`Invalid UUID version: "${r.version}"`);r.pattern??(r.pattern=Ye(i))}else r.pattern??(r.pattern=Ye());L.init(t,r)}),ds=p("$ZodEmail",(t,r)=>{r.pattern??(r.pattern=_a),L.init(t,r)}),ps=p("$ZodURL",(t,r)=>{L.init(t,r),t._zod.check=n=>{try{let i=n.value.trim();if(!r.normalize&&r.protocol?.source===Pa.source&&!/^https?:\/\//i.test(i)){n.issues.push({code:"invalid_format",format:"url",note:"Invalid URL format",input:n.value,inst:t,continue:!r.abort});return}let e=new URL(i);r.hostname&&(r.hostname.lastIndex=0,r.hostname.test(e.hostname)||n.issues.push({code:"invalid_format",format:"url",note:"Invalid hostname",pattern:r.hostname.source,input:n.value,inst:t,continue:!r.abort})),r.protocol&&(r.protocol.lastIndex=0,r.protocol.test(e.protocol.endsWith(":")?e.protocol.slice(0,-1):e.protocol)||n.issues.push({code:"invalid_format",format:"url",note:"Invalid protocol",pattern:r.protocol.source,input:n.value,inst:t,continue:!r.abort})),r.normalize?n.value=e.href:n.value=i;return}catch{n.issues.push({code:"invalid_format",format:"url",input:n.value,inst:t,continue:!r.abort})}}}),ms=p("$ZodEmoji",(t,r)=>{r.pattern??(r.pattern=$a()),L.init(t,r)}),fs=p("$ZodNanoID",(t,r)=>{r.pattern??(r.pattern=va),L.init(t,r)}),gs=p("$ZodCUID",(t,r)=>{r.pattern??(r.pattern=pa),L.init(t,r)}),hs=p("$ZodCUID2",(t,r)=>{r.pattern??(r.pattern=ma),L.init(t,r)}),vs=p("$ZodULID",(t,r)=>{r.pattern??(r.pattern=fa),L.init(t,r)}),ys=p("$ZodXID",(t,r)=>{r.pattern??(r.pattern=ga),L.init(t,r)}),bs=p("$ZodKSUID",(t,r)=>{r.pattern??(r.pattern=ha),L.init(t,r)}),_s=p("$ZodISODateTime",(t,r)=>{r.pattern??(r.pattern=Da(r)),L.init(t,r)}),$s=p("$ZodISODate",(t,r)=>{r.pattern??(r.pattern=Ta),L.init(t,r)}),xs=p("$ZodISOTime",(t,r)=>{r.pattern??(r.pattern=Oa(r)),L.init(t,r)}),ks=p("$ZodISODuration",(t,r)=>{r.pattern??(r.pattern=ya),L.init(t,r)}),zs=p("$ZodIPv4",(t,r)=>{r.pattern??(r.pattern=xa),L.init(t,r),t._zod.bag.format="ipv4"}),Ss=p("$ZodIPv6",(t,r)=>{r.pattern??(r.pattern=ka),L.init(t,r),t._zod.bag.format="ipv6",t._zod.check=n=>{try{new URL(`http://[${n.value}]`)}catch{n.issues.push({code:"invalid_format",format:"ipv6",input:n.value,inst:t,continue:!r.abort})}}}),ws=p("$ZodMAC",(t,r)=>{r.pattern??(r.pattern=za(r.delimiter)),L.init(t,r),t._zod.bag.format="mac"}),Is=p("$ZodCIDRv4",(t,r)=>{r.pattern??(r.pattern=Sa),L.init(t,r)}),Ps=p("$ZodCIDRv6",(t,r)=>{r.pattern??(r.pattern=wa),L.init(t,r),t._zod.check=n=>{let i=n.value.split("/");try{if(i.length!==2)throw new Error;let[e,o]=i;if(!o)throw new Error;let a=Number(o);if(`${a}`!==o)throw new Error;if(a<0||a>128)throw new Error;new URL(`http://[${e}]`)}catch{n.issues.push({code:"invalid_format",format:"cidrv6",input:n.value,inst:t,continue:!r.abort})}}});Ts=p("$ZodBase64",(t,r)=>{r.pattern??(r.pattern=Ia),L.init(t,r),t._zod.bag.contentEncoding="base64",t._zod.check=n=>{js(n.value)||n.issues.push({code:"invalid_format",format:"base64",input:n.value,inst:t,continue:!r.abort})}});Os=p("$ZodBase64URL",(t,r)=>{r.pattern??(r.pattern=Zn),L.init(t,r),t._zod.bag.contentEncoding="base64url",t._zod.check=n=>{yp(n.value)||n.issues.push({code:"invalid_format",format:"base64url",input:n.value,inst:t,continue:!r.abort})}}),Ds=p("$ZodE164",(t,r)=>{r.pattern??(r.pattern=ja),L.init(t,r)});Us=p("$ZodJWT",(t,r)=>{L.init(t,r),t._zod.check=n=>{bp(n.value,r.alg)||n.issues.push({code:"invalid_format",format:"jwt",input:n.value,inst:t,continue:!r.abort})}}),Ns=p("$ZodCustomStringFormat",(t,r)=>{L.init(t,r),t._zod.check=n=>{r.fn(n.value)||n.issues.push({code:"invalid_format",format:r.format,input:n.value,inst:t,continue:!r.abort})}}),Hn=p("$ZodNumber",(t,r)=>{P.init(t,r),t._zod.pattern=t._zod.bag.pattern??Rn,t._zod.parse=(n,i)=>{if(r.coerce)try{n.value=Number(n.value)}catch{}let e=n.value;if(typeof e=="number"&&!Number.isNaN(e)&&Number.isFinite(e))return n;let o=typeof e=="number"?Number.isNaN(e)?"NaN":Number.isFinite(e)?void 0:"Infinity":void 0;return n.issues.push({expected:"number",code:"invalid_type",input:e,inst:t,...o?{received:o}:{}}),n}}),Es=p("$ZodNumberFormat",(t,r)=>{qa.init(t,r),Hn.init(t,r)}),fr=p("$ZodBoolean",(t,r)=>{P.init(t,r),t._zod.pattern=Za,t._zod.parse=(n,i)=>{if(r.coerce)try{n.value=!!n.value}catch{}let e=n.value;return typeof e=="boolean"||n.issues.push({expected:"boolean",code:"invalid_type",input:e,inst:t}),n}}),Bn=p("$ZodBigInt",(t,r)=>{P.init(t,r),t._zod.pattern=Na,t._zod.parse=(n,i)=>{if(r.coerce)try{n.value=BigInt(n.value)}catch{}return typeof n.value=="bigint"||n.issues.push({expected:"bigint",code:"invalid_type",input:n.value,inst:t}),n}}),Zs=p("$ZodBigIntFormat",(t,r)=>{Fa.init(t,r),Bn.init(t,r)}),Rs=p("$ZodSymbol",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;return typeof e=="symbol"||n.issues.push({expected:"symbol",code:"invalid_type",input:e,inst:t}),n}}),As=p("$ZodUndefined",(t,r)=>{P.init(t,r),t._zod.pattern=Aa,t._zod.values=new Set([void 0]),t._zod.parse=(n,i)=>{let e=n.value;return typeof e>"u"||n.issues.push({expected:"undefined",code:"invalid_type",input:e,inst:t}),n}}),Cs=p("$ZodNull",(t,r)=>{P.init(t,r),t._zod.pattern=Ra,t._zod.values=new Set([null]),t._zod.parse=(n,i)=>{let e=n.value;return e===null||n.issues.push({expected:"null",code:"invalid_type",input:e,inst:t}),n}}),Ms=p("$ZodAny",(t,r)=>{P.init(t,r),t._zod.parse=n=>n}),Ls=p("$ZodUnknown",(t,r)=>{P.init(t,r),t._zod.parse=n=>n}),qs=p("$ZodNever",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>(n.issues.push({expected:"never",code:"invalid_type",input:n.value,inst:t}),n)}),Fs=p("$ZodVoid",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;return typeof e>"u"||n.issues.push({expected:"void",code:"invalid_type",input:e,inst:t}),n}}),Js=p("$ZodDate",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{if(r.coerce)try{n.value=new Date(n.value)}catch{}let e=n.value,o=e instanceof Date;return o&&!Number.isNaN(e.getTime())||n.issues.push({expected:"date",code:"invalid_type",input:e,...o?{received:"Invalid Date"}:{},inst:t}),n}});Vs=p("$ZodArray",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;if(!Array.isArray(e))return n.issues.push({expected:"array",code:"invalid_type",input:e,inst:t}),n;n.value=Array(e.length);let o=[];for(let a=0;aop(u,n,a))):op(c,n,a)}return o.length?Promise.all(o).then(()=>n):n}});xp=p("$ZodObject",(t,r)=>{if(P.init(t,r),!Object.getOwnPropertyDescriptor(r,"shape")?.get){let s=r.shape;Object.defineProperty(r,"shape",{get:()=>{let c={...s};return Object.defineProperty(r,"shape",{value:c}),c}})}let i=xt(()=>_p(r));O(t._zod,"propValues",()=>{let s=r.shape,c={};for(let u in s){let d=s[u]._zod;if(d.values){c[u]??(c[u]=new Set);for(let m of d.values)c[u].add(m)}}return c});let e=Xe,o=r.catchall,a;t._zod.parse=(s,c)=>{a??(a=i.value);let u=s.value;if(!e(u))return s.issues.push({expected:"object",code:"invalid_type",input:u,inst:t}),s;s.value={};let d=[],m=a.shape;for(let h of a.keys){let v=m[h],S=v._zod.optin==="optional",G=v._zod.optout==="optional",V=v._zod.run({value:u[h],issues:[]},c);V instanceof Promise?d.push(V.then(Ne=>Vn(Ne,s,h,u,S,G))):Vn(V,s,h,u,S,G)}return o?$p(d,u,s,c,i.value,t):d.length?Promise.all(d).then(()=>s):s}}),Hs=p("$ZodObjectJIT",(t,r)=>{xp.init(t,r);let n=t._zod.parse,i=xt(()=>_p(r)),e=h=>{let v=new mr(["shape","payload","ctx"]),S=i.value,G=B=>{let F=zn(B);return`shape[${F}]._zod.run({ value: input[${F}], issues: [] }, ctx)`};v.write("const input = payload.value;");let V=Object.create(null),Ne=0;for(let B of S.keys)V[B]=`key_${Ne++}`;v.write("const newResult = {};");for(let B of S.keys){let F=V[B],te=zn(B),Ed=h[B],Zd=Ed?._zod?.optin==="optional",cg=Ed?._zod?.optout==="optional";v.write(`const ${F} = ${G(B)};`),Zd&&cg?v.write(` + if (${F}.issues.length) { + if (${te} in input) { + payload.issues = payload.issues.concat(${F}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${te}, ...iss.path] : [${te}] + }))); + } + } + + if (${F}.value === undefined) { + if (${te} in input) { + newResult[${te}] = undefined; + } + } else { + newResult[${te}] = ${F}.value; + } + + `):Zd?v.write(` + if (${F}.issues.length) { + payload.issues = payload.issues.concat(${F}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${te}, ...iss.path] : [${te}] + }))); + } + + if (${F}.value === undefined) { + if (${te} in input) { + newResult[${te}] = undefined; + } + } else { + newResult[${te}] = ${F}.value; + } + + `):v.write(` + const ${F}_present = ${te} in input; + if (${F}.issues.length) { + payload.issues = payload.issues.concat(${F}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${te}, ...iss.path] : [${te}] + }))); + } + if (!${F}_present && !${F}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${te}] + }); + } + + if (${F}_present) { + if (${F}.value === undefined) { + newResult[${te}] = undefined; + } else { + newResult[${te}] = ${F}.value; + } + } + + `)}v.write("payload.value = newResult;"),v.write("return payload;");let Q=v.compile();return(B,F)=>Q(h,B,F)},o,a=Xe,s=!Ge.jitless,u=s&&na.value,d=r.catchall,m;t._zod.parse=(h,v)=>{m??(m=i.value);let S=h.value;return a(S)?s&&u&&v?.async===!1&&v.jitless!==!0?(o||(o=e(r.shape)),h=o(h,v),d?$p([],S,h,v,m,t):h):n(h,v):(h.issues.push({expected:"object",code:"invalid_type",input:S,inst:t}),h)}});gr=p("$ZodUnion",(t,r)=>{P.init(t,r),O(t._zod,"optin",()=>r.options.some(i=>i._zod.optin==="optional")?"optional":void 0),O(t._zod,"optout",()=>r.options.some(i=>i._zod.optout==="optional")?"optional":void 0),O(t._zod,"values",()=>{if(r.options.every(i=>i._zod.values))return new Set(r.options.flatMap(i=>Array.from(i._zod.values)))}),O(t._zod,"pattern",()=>{if(r.options.every(i=>i._zod.pattern)){let i=r.options.map(e=>e._zod.pattern);return new RegExp(`^(${i.map(e=>nr(e.source)).join("|")})$`)}});let n=r.options.length===1?r.options[0]._zod.run:null;t._zod.parse=(i,e)=>{if(n)return n(i,e);let o=!1,a=[];for(let s of r.options){let c=s._zod.run({value:i.value,issues:[]},e);if(c instanceof Promise)a.push(c),o=!0;else{if(c.issues.length===0)return c;a.push(c)}}return o?Promise.all(a).then(s=>ip(s,i,t,e)):ip(a,i,t,e)}});Bs=p("$ZodXor",(t,r)=>{gr.init(t,r),r.inclusive=!1;let n=r.options.length===1?r.options[0]._zod.run:null;t._zod.parse=(i,e)=>{if(n)return n(i,e);let o=!1,a=[];for(let s of r.options){let c=s._zod.run({value:i.value,issues:[]},e);c instanceof Promise?(a.push(c),o=!0):a.push(c)}return o?Promise.all(a).then(s=>ap(s,i,t,e)):ap(a,i,t,e)}}),Ws=p("$ZodDiscriminatedUnion",(t,r)=>{r.inclusive=!1,gr.init(t,r);let n=t._zod.parse;O(t._zod,"propValues",()=>{let e={};for(let o of r.options){let a=o._zod.propValues;if(!a||Object.keys(a).length===0)throw new Error(`Invalid discriminated union option at index "${r.options.indexOf(o)}"`);for(let[s,c]of Object.entries(a)){e[s]||(e[s]=new Set);for(let u of c)e[s].add(u)}}return e});let i=xt(()=>{let e=r.options,o=new Map;for(let a of e){let s=a._zod.propValues?.[r.discriminator];if(!s||s.size===0)throw new Error(`Invalid discriminated union option at index "${r.options.indexOf(a)}"`);for(let c of s){if(o.has(c))throw new Error(`Duplicate discriminator value "${String(c)}"`);o.set(c,a)}}return o});t._zod.parse=(e,o)=>{let a=e.value;if(!Xe(a))return e.issues.push({code:"invalid_type",expected:"object",input:a,inst:t}),e;let s=i.value.get(a?.[r.discriminator]);return s?s._zod.run(e,o):r.unionFallback||o.direction==="backward"?n(e,o):(e.issues.push({code:"invalid_union",errors:[],note:"No matching discriminator",discriminator:r.discriminator,options:Array.from(i.value.keys()),input:a,path:[r.discriminator],inst:t}),e)}}),Ks=p("$ZodIntersection",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value,o=r.left._zod.run({value:e,issues:[]},i),a=r.right._zod.run({value:e,issues:[]},i);return o instanceof Promise||a instanceof Promise?Promise.all([o,a]).then(([c,u])=>sp(n,c,u)):sp(n,o,a)}});Wn=p("$ZodTuple",(t,r)=>{P.init(t,r);let n=r.items;t._zod.parse=(i,e)=>{let o=i.value;if(!Array.isArray(o))return i.issues.push({input:o,inst:t,expected:"tuple",code:"invalid_type"}),i;i.value=[];let a=[],s=cp(n,"optin"),c=cp(n,"optout");if(!r.rest){if(o.lengthn.length&&i.issues.push({code:"too_big",maximum:n.length,inclusive:!0,input:o,inst:t,origin:"array"})}let u=new Array(n.length);for(let d=0;d{u[d]=h})):u[d]=m}if(r.rest){let d=n.length-1,m=o.slice(n.length);for(let h of m){d++;let v=r.rest._zod.run({value:h,issues:[]},e);v instanceof Promise?a.push(v.then(S=>up(S,i,d))):up(v,i,d)}}return a.length?Promise.all(a).then(()=>lp(u,i,n,o,c)):lp(u,i,n,o,c)}});Gs=p("$ZodRecord",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;if(!Ae(e))return n.issues.push({expected:"record",code:"invalid_type",input:e,inst:t}),n;let o=[],a=r.keyType._zod.values;if(a){n.value={};let s=new Set;for(let u of a)if(typeof u=="string"||typeof u=="number"||typeof u=="symbol"){s.add(typeof u=="number"?u.toString():u);let d=r.keyType._zod.run({value:u,issues:[]},i);if(d instanceof Promise)throw new Error("Async schemas not supported in object keys currently");if(d.issues.length){n.issues.push({code:"invalid_key",origin:"record",issues:d.issues.map(v=>ce(v,i,H())),input:u,path:[u],inst:t});continue}let m=d.value,h=r.valueType._zod.run({value:e[u],issues:[]},i);h instanceof Promise?o.push(h.then(v=>{v.issues.length&&n.issues.push(...de(u,v.issues)),n.value[m]=v.value})):(h.issues.length&&n.issues.push(...de(u,h.issues)),n.value[m]=h.value)}let c;for(let u in e)s.has(u)||(c=c??[],c.push(u));c&&c.length>0&&n.issues.push({code:"unrecognized_keys",input:e,inst:t,keys:c})}else{n.value={};for(let s of Reflect.ownKeys(e)){if(s==="__proto__"||!Object.prototype.propertyIsEnumerable.call(e,s))continue;let c=r.keyType._zod.run({value:s,issues:[]},i);if(c instanceof Promise)throw new Error("Async schemas not supported in object keys currently");if(typeof s=="string"&&Rn.test(s)&&c.issues.length){let m=r.keyType._zod.run({value:Number(s),issues:[]},i);if(m instanceof Promise)throw new Error("Async schemas not supported in object keys currently");m.issues.length===0&&(c=m)}if(c.issues.length){r.mode==="loose"?n.value[s]=e[s]:n.issues.push({code:"invalid_key",origin:"record",issues:c.issues.map(m=>ce(m,i,H())),input:s,path:[s],inst:t});continue}let d=r.valueType._zod.run({value:e[s],issues:[]},i);d instanceof Promise?o.push(d.then(m=>{m.issues.length&&n.issues.push(...de(s,m.issues)),n.value[c.value]=m.value})):(d.issues.length&&n.issues.push(...de(s,d.issues)),n.value[c.value]=d.value)}}return o.length?Promise.all(o).then(()=>n):n}}),Qs=p("$ZodMap",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;if(!(e instanceof Map))return n.issues.push({expected:"map",code:"invalid_type",input:e,inst:t}),n;let o=[];n.value=new Map;for(let[a,s]of e){let c=r.keyType._zod.run({value:a,issues:[]},i),u=r.valueType._zod.run({value:s,issues:[]},i);c instanceof Promise||u instanceof Promise?o.push(Promise.all([c,u]).then(([d,m])=>{dp(d,m,n,a,e,t,i)})):dp(c,u,n,a,e,t,i)}return o.length?Promise.all(o).then(()=>n):n}});Xs=p("$ZodSet",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;if(!(e instanceof Set))return n.issues.push({input:e,inst:t,expected:"set",code:"invalid_type"}),n;let o=[];n.value=new Set;for(let a of e){let s=r.valueType._zod.run({value:a,issues:[]},i);s instanceof Promise?o.push(s.then(c=>pp(c,n))):pp(s,n)}return o.length?Promise.all(o).then(()=>n):n}});Ys=p("$ZodEnum",(t,r)=>{P.init(t,r);let n=rr(r.entries),i=new Set(n);t._zod.values=i,t._zod.pattern=new RegExp(`^(${n.filter(e=>or.has(typeof e)).map(e=>typeof e=="string"?ve(e):e.toString()).join("|")})$`),t._zod.parse=(e,o)=>{let a=e.value;return i.has(a)||e.issues.push({code:"invalid_value",values:n,input:a,inst:t}),e}}),ec=p("$ZodLiteral",(t,r)=>{if(P.init(t,r),r.values.length===0)throw new Error("Cannot create literal schema with no valid values");let n=new Set(r.values);t._zod.values=n,t._zod.pattern=new RegExp(`^(${r.values.map(i=>typeof i=="string"?ve(i):i?ve(i.toString()):String(i)).join("|")})$`),t._zod.parse=(i,e)=>{let o=i.value;return n.has(o)||i.issues.push({code:"invalid_value",values:r.values,input:o,inst:t}),i}}),tc=p("$ZodFile",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{let e=n.value;return e instanceof File||n.issues.push({expected:"file",code:"invalid_type",input:e,inst:t}),n}}),rc=p("$ZodTransform",(t,r)=>{P.init(t,r),t._zod.optin="optional",t._zod.parse=(n,i)=>{if(i.direction==="backward")throw new Ee(t.constructor.name);let e=r.transform(n.value,n);if(i.async)return(e instanceof Promise?e:Promise.resolve(e)).then(a=>(n.value=a,n.fallback=!0,n));if(e instanceof Promise)throw new $e;return n.value=e,n.fallback=!0,n}});Kn=p("$ZodOptional",(t,r)=>{P.init(t,r),t._zod.optin="optional",t._zod.optout="optional",O(t._zod,"values",()=>r.innerType._zod.values?new Set([...r.innerType._zod.values,void 0]):void 0),O(t._zod,"pattern",()=>{let n=r.innerType._zod.pattern;return n?new RegExp(`^(${nr(n.source)})?$`):void 0}),t._zod.parse=(n,i)=>{if(r.innerType._zod.optin==="optional"){let e=n.value,o=r.innerType._zod.run(n,i);return o instanceof Promise?o.then(a=>mp(a,e)):mp(o,e)}return n.value===void 0?n:r.innerType._zod.run(n,i)}}),nc=p("$ZodExactOptional",(t,r)=>{Kn.init(t,r),O(t._zod,"values",()=>r.innerType._zod.values),O(t._zod,"pattern",()=>r.innerType._zod.pattern),t._zod.parse=(n,i)=>r.innerType._zod.run(n,i)}),oc=p("$ZodNullable",(t,r)=>{P.init(t,r),O(t._zod,"optin",()=>r.innerType._zod.optin),O(t._zod,"optout",()=>r.innerType._zod.optout),O(t._zod,"pattern",()=>{let n=r.innerType._zod.pattern;return n?new RegExp(`^(${nr(n.source)}|null)$`):void 0}),O(t._zod,"values",()=>r.innerType._zod.values?new Set([...r.innerType._zod.values,null]):void 0),t._zod.parse=(n,i)=>n.value===null?n:r.innerType._zod.run(n,i)}),ic=p("$ZodDefault",(t,r)=>{P.init(t,r),t._zod.optin="optional",O(t._zod,"values",()=>r.innerType._zod.values),t._zod.parse=(n,i)=>{if(i.direction==="backward")return r.innerType._zod.run(n,i);if(n.value===void 0)return n.value=r.defaultValue,n;let e=r.innerType._zod.run(n,i);return e instanceof Promise?e.then(o=>fp(o,r)):fp(e,r)}});ac=p("$ZodPrefault",(t,r)=>{P.init(t,r),t._zod.optin="optional",O(t._zod,"values",()=>r.innerType._zod.values),t._zod.parse=(n,i)=>(i.direction==="backward"||n.value===void 0&&(n.value=r.defaultValue),r.innerType._zod.run(n,i))}),sc=p("$ZodNonOptional",(t,r)=>{P.init(t,r),O(t._zod,"values",()=>{let n=r.innerType._zod.values;return n?new Set([...n].filter(i=>i!==void 0)):void 0}),t._zod.parse=(n,i)=>{let e=r.innerType._zod.run(n,i);return e instanceof Promise?e.then(o=>gp(o,t)):gp(e,t)}});cc=p("$ZodSuccess",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>{if(i.direction==="backward")throw new Ee("ZodSuccess");let e=r.innerType._zod.run(n,i);return e instanceof Promise?e.then(o=>(n.value=o.issues.length===0,n)):(n.value=e.issues.length===0,n)}}),uc=p("$ZodCatch",(t,r)=>{P.init(t,r),t._zod.optin="optional",O(t._zod,"optout",()=>r.innerType._zod.optout),O(t._zod,"values",()=>r.innerType._zod.values),t._zod.parse=(n,i)=>{if(i.direction==="backward")return r.innerType._zod.run(n,i);let e=r.innerType._zod.run(n,i);return e instanceof Promise?e.then(o=>(n.value=o.value,o.issues.length&&(n.value=r.catchValue({...n,error:{issues:o.issues.map(a=>ce(a,i,H()))},input:n.value}),n.issues=[],n.fallback=!0),n)):(n.value=e.value,e.issues.length&&(n.value=r.catchValue({...n,error:{issues:e.issues.map(o=>ce(o,i,H()))},input:n.value}),n.issues=[],n.fallback=!0),n)}}),lc=p("$ZodNaN",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>((typeof n.value!="number"||!Number.isNaN(n.value))&&n.issues.push({input:n.value,inst:t,expected:"nan",code:"invalid_type"}),n)}),Gn=p("$ZodPipe",(t,r)=>{P.init(t,r),O(t._zod,"values",()=>r.in._zod.values),O(t._zod,"optin",()=>r.in._zod.optin),O(t._zod,"optout",()=>r.out._zod.optout),O(t._zod,"propValues",()=>r.in._zod.propValues),t._zod.parse=(n,i)=>{if(i.direction==="backward"){let o=r.out._zod.run(n,i);return o instanceof Promise?o.then(a=>qn(a,r.in,i)):qn(o,r.in,i)}let e=r.in._zod.run(n,i);return e instanceof Promise?e.then(o=>qn(o,r.out,i)):qn(e,r.out,i)}});hr=p("$ZodCodec",(t,r)=>{P.init(t,r),O(t._zod,"values",()=>r.in._zod.values),O(t._zod,"optin",()=>r.in._zod.optin),O(t._zod,"optout",()=>r.out._zod.optout),O(t._zod,"propValues",()=>r.in._zod.propValues),t._zod.parse=(n,i)=>{if((i.direction||"forward")==="forward"){let o=r.in._zod.run(n,i);return o instanceof Promise?o.then(a=>Fn(a,r,i)):Fn(o,r,i)}else{let o=r.out._zod.run(n,i);return o instanceof Promise?o.then(a=>Fn(a,r,i)):Fn(o,r,i)}}});dc=p("$ZodPreprocess",(t,r)=>{Gn.init(t,r)}),pc=p("$ZodReadonly",(t,r)=>{P.init(t,r),O(t._zod,"propValues",()=>r.innerType._zod.propValues),O(t._zod,"values",()=>r.innerType._zod.values),O(t._zod,"optin",()=>r.innerType?._zod?.optin),O(t._zod,"optout",()=>r.innerType?._zod?.optout),t._zod.parse=(n,i)=>{if(i.direction==="backward")return r.innerType._zod.run(n,i);let e=r.innerType._zod.run(n,i);return e instanceof Promise?e.then(hp):hp(e)}});mc=p("$ZodTemplateLiteral",(t,r)=>{P.init(t,r);let n=[];for(let i of r.parts)if(typeof i=="object"&&i!==null){if(!i._zod.pattern)throw new Error(`Invalid template literal part, no pattern found: ${[...i._zod.traits].shift()}`);let e=i._zod.pattern instanceof RegExp?i._zod.pattern.source:i._zod.pattern;if(!e)throw new Error(`Invalid template literal part: ${i._zod.traits}`);let o=e.startsWith("^")?1:0,a=e.endsWith("$")?e.length-1:e.length;n.push(e.slice(o,a))}else if(i===null||ia.has(typeof i))n.push(ve(`${i}`));else throw new Error(`Invalid template literal part: ${i}`);t._zod.pattern=new RegExp(`^${n.join("")}$`),t._zod.parse=(i,e)=>typeof i.value!="string"?(i.issues.push({input:i.value,inst:t,expected:"string",code:"invalid_type"}),i):(t._zod.pattern.lastIndex=0,t._zod.pattern.test(i.value)||i.issues.push({input:i.value,inst:t,code:"invalid_format",format:r.format??"template_literal",pattern:t._zod.pattern.source}),i)}),fc=p("$ZodFunction",(t,r)=>(P.init(t,r),t._def=r,t._zod.def=r,t.implement=n=>{if(typeof n!="function")throw new Error("implement() must be called with a function");return function(...i){let e=t._def.input?cr(t._def.input,i):i,o=Reflect.apply(n,this,e);return t._def.output?cr(t._def.output,o):o}},t.implementAsync=n=>{if(typeof n!="function")throw new Error("implementAsync() must be called with a function");return async function(...i){let e=t._def.input?await ur(t._def.input,i):i,o=await Reflect.apply(n,this,e);return t._def.output?await ur(t._def.output,o):o}},t._zod.parse=(n,i)=>typeof n.value!="function"?(n.issues.push({code:"invalid_type",expected:"function",input:n.value,inst:t}),n):(t._def.output&&t._def.output._zod.def.type==="promise"?n.value=t.implementAsync(n.value):n.value=t.implement(n.value),n),t.input=(...n)=>{let i=t.constructor;return Array.isArray(n[0])?new i({type:"function",input:new Wn({type:"tuple",items:n[0],rest:n[1]}),output:t._def.output}):new i({type:"function",input:n[0],output:t._def.output})},t.output=n=>{let i=t.constructor;return new i({type:"function",input:t._def.input,output:n})},t)),gc=p("$ZodPromise",(t,r)=>{P.init(t,r),t._zod.parse=(n,i)=>Promise.resolve(n.value).then(e=>r.innerType._zod.run({value:e,issues:[]},i))}),hc=p("$ZodLazy",(t,r)=>{P.init(t,r),O(t._zod,"innerType",()=>{let n=r;return n._cachedInner||(n._cachedInner=r.getter()),n._cachedInner}),O(t._zod,"pattern",()=>t._zod.innerType?._zod?.pattern),O(t._zod,"propValues",()=>t._zod.innerType?._zod?.propValues),O(t._zod,"optin",()=>t._zod.innerType?._zod?.optin??void 0),O(t._zod,"optout",()=>t._zod.innerType?._zod?.optout??void 0),t._zod.parse=(n,i)=>t._zod.innerType._zod.run(n,i)}),vc=p("$ZodCustom",(t,r)=>{J.init(t,r),P.init(t,r),t._zod.parse=(n,i)=>n,t._zod.check=n=>{let i=n.value,e=r.fn(i);if(e instanceof Promise)return e.then(o=>vp(o,n,i,t));vp(e,n,i,t)}})});function kp(){return{localeError:lh()}}var lh,zp=x(()=>{w();lh=()=>{let t={string:{unit:"\u062D\u0631\u0641",verb:"\u0623\u0646 \u064A\u062D\u0648\u064A"},file:{unit:"\u0628\u0627\u064A\u062A",verb:"\u0623\u0646 \u064A\u062D\u0648\u064A"},array:{unit:"\u0639\u0646\u0635\u0631",verb:"\u0623\u0646 \u064A\u062D\u0648\u064A"},set:{unit:"\u0639\u0646\u0635\u0631",verb:"\u0623\u0646 \u064A\u062D\u0648\u064A"}};function r(e){return t[e]??null}let n={regex:"\u0645\u062F\u062E\u0644",email:"\u0628\u0631\u064A\u062F \u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A",url:"\u0631\u0627\u0628\u0637",emoji:"\u0625\u064A\u0645\u0648\u062C\u064A",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u062A\u0627\u0631\u064A\u062E \u0648\u0648\u0642\u062A \u0628\u0645\u0639\u064A\u0627\u0631 ISO",date:"\u062A\u0627\u0631\u064A\u062E \u0628\u0645\u0639\u064A\u0627\u0631 ISO",time:"\u0648\u0642\u062A \u0628\u0645\u0639\u064A\u0627\u0631 ISO",duration:"\u0645\u062F\u0629 \u0628\u0645\u0639\u064A\u0627\u0631 ISO",ipv4:"\u0639\u0646\u0648\u0627\u0646 IPv4",ipv6:"\u0639\u0646\u0648\u0627\u0646 IPv6",cidrv4:"\u0645\u062F\u0649 \u0639\u0646\u0627\u0648\u064A\u0646 \u0628\u0635\u064A\u063A\u0629 IPv4",cidrv6:"\u0645\u062F\u0649 \u0639\u0646\u0627\u0648\u064A\u0646 \u0628\u0635\u064A\u063A\u0629 IPv6",base64:"\u0646\u064E\u0635 \u0628\u062A\u0631\u0645\u064A\u0632 base64-encoded",base64url:"\u0646\u064E\u0635 \u0628\u062A\u0631\u0645\u064A\u0632 base64url-encoded",json_string:"\u0646\u064E\u0635 \u0639\u0644\u0649 \u0647\u064A\u0626\u0629 JSON",e164:"\u0631\u0642\u0645 \u0647\u0627\u062A\u0641 \u0628\u0645\u0639\u064A\u0627\u0631 E.164",jwt:"JWT",template_literal:"\u0645\u062F\u062E\u0644"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0645\u062F\u062E\u0644\u0627\u062A \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644\u0629: \u064A\u0641\u062A\u0631\u0636 \u0625\u062F\u062E\u0627\u0644 instanceof ${e.expected}\u060C \u0648\u0644\u0643\u0646 \u062A\u0645 \u0625\u062F\u062E\u0627\u0644 ${s}`:`\u0645\u062F\u062E\u0644\u0627\u062A \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644\u0629: \u064A\u0641\u062A\u0631\u0636 \u0625\u062F\u062E\u0627\u0644 ${o}\u060C \u0648\u0644\u0643\u0646 \u062A\u0645 \u0625\u062F\u062E\u0627\u0644 ${s}`}case"invalid_value":return e.values.length===1?`\u0645\u062F\u062E\u0644\u0627\u062A \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644\u0629: \u064A\u0641\u062A\u0631\u0636 \u0625\u062F\u062E\u0627\u0644 ${y(e.values[0])}`:`\u0627\u062E\u062A\u064A\u0627\u0631 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644: \u064A\u062A\u0648\u0642\u0639 \u0627\u0646\u062A\u0642\u0627\u0621 \u0623\u062D\u062F \u0647\u0630\u0647 \u0627\u0644\u062E\u064A\u0627\u0631\u0627\u062A: ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?` \u0623\u0643\u0628\u0631 \u0645\u0646 \u0627\u0644\u0644\u0627\u0632\u0645: \u064A\u0641\u062A\u0631\u0636 \u0623\u0646 \u062A\u0643\u0648\u0646 ${e.origin??"\u0627\u0644\u0642\u064A\u0645\u0629"} ${o} ${e.maximum.toString()} ${a.unit??"\u0639\u0646\u0635\u0631"}`:`\u0623\u0643\u0628\u0631 \u0645\u0646 \u0627\u0644\u0644\u0627\u0632\u0645: \u064A\u0641\u062A\u0631\u0636 \u0623\u0646 \u062A\u0643\u0648\u0646 ${e.origin??"\u0627\u0644\u0642\u064A\u0645\u0629"} ${o} ${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u0623\u0635\u063A\u0631 \u0645\u0646 \u0627\u0644\u0644\u0627\u0632\u0645: \u064A\u0641\u062A\u0631\u0636 \u0644\u0640 ${e.origin} \u0623\u0646 \u064A\u0643\u0648\u0646 ${o} ${e.minimum.toString()} ${a.unit}`:`\u0623\u0635\u063A\u0631 \u0645\u0646 \u0627\u0644\u0644\u0627\u0632\u0645: \u064A\u0641\u062A\u0631\u0636 \u0644\u0640 ${e.origin} \u0623\u0646 \u064A\u0643\u0648\u0646 ${o} ${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u0646\u064E\u0635 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0628\u062F\u0623 \u0628\u0640 "${e.prefix}"`:o.format==="ends_with"?`\u0646\u064E\u0635 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0646\u062A\u0647\u064A \u0628\u0640 "${o.suffix}"`:o.format==="includes"?`\u0646\u064E\u0635 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062A\u0636\u0645\u0651\u064E\u0646 "${o.includes}"`:o.format==="regex"?`\u0646\u064E\u0635 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0637\u0627\u0628\u0642 \u0627\u0644\u0646\u0645\u0637 ${o.pattern}`:`${n[o.format]??e.format} \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644`}case"not_multiple_of":return`\u0631\u0642\u0645 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0646 \u0645\u0636\u0627\u0639\u0641\u0627\u062A ${e.divisor}`;case"unrecognized_keys":return`\u0645\u0639\u0631\u0641${e.keys.length>1?"\u0627\u062A":""} \u063A\u0631\u064A\u0628${e.keys.length>1?"\u0629":""}: ${f(e.keys,"\u060C ")}`;case"invalid_key":return`\u0645\u0639\u0631\u0641 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644 \u0641\u064A ${e.origin}`;case"invalid_union":return"\u0645\u062F\u062E\u0644 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644";case"invalid_element":return`\u0645\u062F\u062E\u0644 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644 \u0641\u064A ${e.origin}`;default:return"\u0645\u062F\u062E\u0644 \u063A\u064A\u0631 \u0645\u0642\u0628\u0648\u0644"}}}});function Sp(){return{localeError:dh()}}var dh,wp=x(()=>{w();dh=()=>{let t={string:{unit:"simvol",verb:"olmal\u0131d\u0131r"},file:{unit:"bayt",verb:"olmal\u0131d\u0131r"},array:{unit:"element",verb:"olmal\u0131d\u0131r"},set:{unit:"element",verb:"olmal\u0131d\u0131r"}};function r(e){return t[e]??null}let n={regex:"input",email:"email address",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datetime",date:"ISO date",time:"ISO time",duration:"ISO duration",ipv4:"IPv4 address",ipv6:"IPv6 address",cidrv4:"IPv4 range",cidrv6:"IPv6 range",base64:"base64-encoded string",base64url:"base64url-encoded string",json_string:"JSON string",e164:"E.164 number",jwt:"JWT",template_literal:"input"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Yanl\u0131\u015F d\u0259y\u0259r: g\xF6zl\u0259nil\u0259n instanceof ${e.expected}, daxil olan ${s}`:`Yanl\u0131\u015F d\u0259y\u0259r: g\xF6zl\u0259nil\u0259n ${o}, daxil olan ${s}`}case"invalid_value":return e.values.length===1?`Yanl\u0131\u015F d\u0259y\u0259r: g\xF6zl\u0259nil\u0259n ${y(e.values[0])}`:`Yanl\u0131\u015F se\xE7im: a\u015Fa\u011F\u0131dak\u0131lardan biri olmal\u0131d\u0131r: ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\xC7ox b\xF6y\xFCk: g\xF6zl\u0259nil\u0259n ${e.origin??"d\u0259y\u0259r"} ${o}${e.maximum.toString()} ${a.unit??"element"}`:`\xC7ox b\xF6y\xFCk: g\xF6zl\u0259nil\u0259n ${e.origin??"d\u0259y\u0259r"} ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\xC7ox ki\xE7ik: g\xF6zl\u0259nil\u0259n ${e.origin} ${o}${e.minimum.toString()} ${a.unit}`:`\xC7ox ki\xE7ik: g\xF6zl\u0259nil\u0259n ${e.origin} ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Yanl\u0131\u015F m\u0259tn: "${o.prefix}" il\u0259 ba\u015Flamal\u0131d\u0131r`:o.format==="ends_with"?`Yanl\u0131\u015F m\u0259tn: "${o.suffix}" il\u0259 bitm\u0259lidir`:o.format==="includes"?`Yanl\u0131\u015F m\u0259tn: "${o.includes}" daxil olmal\u0131d\u0131r`:o.format==="regex"?`Yanl\u0131\u015F m\u0259tn: ${o.pattern} \u015Fablonuna uy\u011Fun olmal\u0131d\u0131r`:`Yanl\u0131\u015F ${n[o.format]??e.format}`}case"not_multiple_of":return`Yanl\u0131\u015F \u0259d\u0259d: ${e.divisor} il\u0259 b\xF6l\xFCn\u0259 bil\u0259n olmal\u0131d\u0131r`;case"unrecognized_keys":return`Tan\u0131nmayan a\xE7ar${e.keys.length>1?"lar":""}: ${f(e.keys,", ")}`;case"invalid_key":return`${e.origin} daxilind\u0259 yanl\u0131\u015F a\xE7ar`;case"invalid_union":return"Yanl\u0131\u015F d\u0259y\u0259r";case"invalid_element":return`${e.origin} daxilind\u0259 yanl\u0131\u015F d\u0259y\u0259r`;default:return"Yanl\u0131\u015F d\u0259y\u0259r"}}}});function Ip(t,r,n,i){let e=Math.abs(t),o=e%10,a=e%100;return a>=11&&a<=19?i:o===1?r:o>=2&&o<=4?n:i}function Pp(){return{localeError:ph()}}var ph,jp=x(()=>{w();ph=()=>{let t={string:{unit:{one:"\u0441\u0456\u043C\u0432\u0430\u043B",few:"\u0441\u0456\u043C\u0432\u0430\u043B\u044B",many:"\u0441\u0456\u043C\u0432\u0430\u043B\u0430\u045E"},verb:"\u043C\u0435\u0446\u044C"},array:{unit:{one:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442",few:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B",many:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430\u045E"},verb:"\u043C\u0435\u0446\u044C"},set:{unit:{one:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442",few:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B",many:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430\u045E"},verb:"\u043C\u0435\u0446\u044C"},file:{unit:{one:"\u0431\u0430\u0439\u0442",few:"\u0431\u0430\u0439\u0442\u044B",many:"\u0431\u0430\u0439\u0442\u0430\u045E"},verb:"\u043C\u0435\u0446\u044C"}};function r(e){return t[e]??null}let n={regex:"\u0443\u0432\u043E\u0434",email:"email \u0430\u0434\u0440\u0430\u0441",url:"URL",emoji:"\u044D\u043C\u043E\u0434\u0437\u0456",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u0434\u0430\u0442\u0430 \u0456 \u0447\u0430\u0441",date:"ISO \u0434\u0430\u0442\u0430",time:"ISO \u0447\u0430\u0441",duration:"ISO \u043F\u0440\u0430\u0446\u044F\u0433\u043B\u0430\u0441\u0446\u044C",ipv4:"IPv4 \u0430\u0434\u0440\u0430\u0441",ipv6:"IPv6 \u0430\u0434\u0440\u0430\u0441",cidrv4:"IPv4 \u0434\u044B\u044F\u043F\u0430\u0437\u043E\u043D",cidrv6:"IPv6 \u0434\u044B\u044F\u043F\u0430\u0437\u043E\u043D",base64:"\u0440\u0430\u0434\u043E\u043A \u0443 \u0444\u0430\u0440\u043C\u0430\u0446\u0435 base64",base64url:"\u0440\u0430\u0434\u043E\u043A \u0443 \u0444\u0430\u0440\u043C\u0430\u0446\u0435 base64url",json_string:"JSON \u0440\u0430\u0434\u043E\u043A",e164:"\u043D\u0443\u043C\u0430\u0440 E.164",jwt:"JWT",template_literal:"\u0443\u0432\u043E\u0434"},i={nan:"NaN",number:"\u043B\u0456\u043A",array:"\u043C\u0430\u0441\u0456\u045E"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u045E\u0432\u043E\u0434: \u0447\u0430\u043A\u0430\u045E\u0441\u044F instanceof ${e.expected}, \u0430\u0442\u0440\u044B\u043C\u0430\u043D\u0430 ${s}`:`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u045E\u0432\u043E\u0434: \u0447\u0430\u043A\u0430\u045E\u0441\u044F ${o}, \u0430\u0442\u0440\u044B\u043C\u0430\u043D\u0430 ${s}`}case"invalid_value":return e.values.length===1?`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u045E\u0432\u043E\u0434: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F ${y(e.values[0])}`:`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u0432\u0430\u0440\u044B\u044F\u043D\u0442: \u0447\u0430\u043A\u0430\u045E\u0441\u044F \u0430\u0434\u0437\u0456\u043D \u0437 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);if(a){let s=Number(e.maximum),c=Ip(s,a.unit.one,a.unit.few,a.unit.many);return`\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u0432\u044F\u043B\u0456\u043A\u0456: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${e.origin??"\u0437\u043D\u0430\u0447\u044D\u043D\u043D\u0435"} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 ${a.verb} ${o}${e.maximum.toString()} ${c}`}return`\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u0432\u044F\u043B\u0456\u043A\u0456: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${e.origin??"\u0437\u043D\u0430\u0447\u044D\u043D\u043D\u0435"} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 \u0431\u044B\u0446\u044C ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);if(a){let s=Number(e.minimum),c=Ip(s,a.unit.one,a.unit.few,a.unit.many);return`\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u043C\u0430\u043B\u044B: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${e.origin} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 ${a.verb} ${o}${e.minimum.toString()} ${c}`}return`\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u043C\u0430\u043B\u044B: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${e.origin} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 \u0431\u044B\u0446\u044C ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u0440\u0430\u0434\u043E\u043A: \u043F\u0430\u0432\u0456\u043D\u0435\u043D \u043F\u0430\u0447\u044B\u043D\u0430\u0446\u0446\u0430 \u0437 "${o.prefix}"`:o.format==="ends_with"?`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u0440\u0430\u0434\u043E\u043A: \u043F\u0430\u0432\u0456\u043D\u0435\u043D \u0437\u0430\u043A\u0430\u043D\u0447\u0432\u0430\u0446\u0446\u0430 \u043D\u0430 "${o.suffix}"`:o.format==="includes"?`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u0440\u0430\u0434\u043E\u043A: \u043F\u0430\u0432\u0456\u043D\u0435\u043D \u0437\u043C\u044F\u0448\u0447\u0430\u0446\u044C "${o.includes}"`:o.format==="regex"?`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u0440\u0430\u0434\u043E\u043A: \u043F\u0430\u0432\u0456\u043D\u0435\u043D \u0430\u0434\u043F\u0430\u0432\u044F\u0434\u0430\u0446\u044C \u0448\u0430\u0431\u043B\u043E\u043D\u0443 ${o.pattern}`:`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B ${n[o.format]??e.format}`}case"not_multiple_of":return`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u043B\u0456\u043A: \u043F\u0430\u0432\u0456\u043D\u0435\u043D \u0431\u044B\u0446\u044C \u043A\u0440\u0430\u0442\u043D\u044B\u043C ${e.divisor}`;case"unrecognized_keys":return`\u041D\u0435\u0440\u0430\u0441\u043F\u0430\u0437\u043D\u0430\u043D\u044B ${e.keys.length>1?"\u043A\u043B\u044E\u0447\u044B":"\u043A\u043B\u044E\u0447"}: ${f(e.keys,", ")}`;case"invalid_key":return`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u043A\u043B\u044E\u0447 \u0443 ${e.origin}`;case"invalid_union":return"\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u045E\u0432\u043E\u0434";case"invalid_element":return`\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u0430\u0435 \u0437\u043D\u0430\u0447\u044D\u043D\u043D\u0435 \u045E ${e.origin}`;default:return"\u041D\u044F\u043F\u0440\u0430\u0432\u0456\u043B\u044C\u043D\u044B \u045E\u0432\u043E\u0434"}}}});function Tp(){return{localeError:mh()}}var mh,Op=x(()=>{w();mh=()=>{let t={string:{unit:"\u0441\u0438\u043C\u0432\u043E\u043B\u0430",verb:"\u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430"},file:{unit:"\u0431\u0430\u0439\u0442\u0430",verb:"\u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430"},array:{unit:"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0430",verb:"\u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430"},set:{unit:"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0430",verb:"\u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430"}};function r(e){return t[e]??null}let n={regex:"\u0432\u0445\u043E\u0434",email:"\u0438\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441",url:"URL",emoji:"\u0435\u043C\u043E\u0434\u0436\u0438",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u0432\u0440\u0435\u043C\u0435",date:"ISO \u0434\u0430\u0442\u0430",time:"ISO \u0432\u0440\u0435\u043C\u0435",duration:"ISO \u043F\u0440\u043E\u0434\u044A\u043B\u0436\u0438\u0442\u0435\u043B\u043D\u043E\u0441\u0442",ipv4:"IPv4 \u0430\u0434\u0440\u0435\u0441",ipv6:"IPv6 \u0430\u0434\u0440\u0435\u0441",cidrv4:"IPv4 \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D",cidrv6:"IPv6 \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D",base64:"base64-\u043A\u043E\u0434\u0438\u0440\u0430\u043D \u043D\u0438\u0437",base64url:"base64url-\u043A\u043E\u0434\u0438\u0440\u0430\u043D \u043D\u0438\u0437",json_string:"JSON \u043D\u0438\u0437",e164:"E.164 \u043D\u043E\u043C\u0435\u0440",jwt:"JWT",template_literal:"\u0432\u0445\u043E\u0434"},i={nan:"NaN",number:"\u0447\u0438\u0441\u043B\u043E",array:"\u043C\u0430\u0441\u0438\u0432"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u0432\u0445\u043E\u0434: \u043E\u0447\u0430\u043A\u0432\u0430\u043D instanceof ${e.expected}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D ${s}`:`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u0432\u0445\u043E\u0434: \u043E\u0447\u0430\u043A\u0432\u0430\u043D ${o}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D ${s}`}case"invalid_value":return e.values.length===1?`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u0432\u0445\u043E\u0434: \u043E\u0447\u0430\u043A\u0432\u0430\u043D ${y(e.values[0])}`:`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430 \u043E\u043F\u0446\u0438\u044F: \u043E\u0447\u0430\u043A\u0432\u0430\u043D\u043E \u0435\u0434\u043D\u043E \u043E\u0442 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u0422\u0432\u044A\u0440\u0434\u0435 \u0433\u043E\u043B\u044F\u043C\u043E: \u043E\u0447\u0430\u043A\u0432\u0430 \u0441\u0435 ${e.origin??"\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442"} \u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430 ${o}${e.maximum.toString()} ${a.unit??"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0430"}`:`\u0422\u0432\u044A\u0440\u0434\u0435 \u0433\u043E\u043B\u044F\u043C\u043E: \u043E\u0447\u0430\u043A\u0432\u0430 \u0441\u0435 ${e.origin??"\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442"} \u0434\u0430 \u0431\u044A\u0434\u0435 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u0422\u0432\u044A\u0440\u0434\u0435 \u043C\u0430\u043B\u043A\u043E: \u043E\u0447\u0430\u043A\u0432\u0430 \u0441\u0435 ${e.origin} \u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430 ${o}${e.minimum.toString()} ${a.unit}`:`\u0422\u0432\u044A\u0440\u0434\u0435 \u043C\u0430\u043B\u043A\u043E: \u043E\u0447\u0430\u043A\u0432\u0430 \u0441\u0435 ${e.origin} \u0434\u0430 \u0431\u044A\u0434\u0435 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;if(o.format==="starts_with")return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043D\u0438\u0437: \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0437\u0430\u043F\u043E\u0447\u0432\u0430 \u0441 "${o.prefix}"`;if(o.format==="ends_with")return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043D\u0438\u0437: \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0437\u0430\u0432\u044A\u0440\u0448\u0432\u0430 \u0441 "${o.suffix}"`;if(o.format==="includes")return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043D\u0438\u0437: \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0432\u043A\u043B\u044E\u0447\u0432\u0430 "${o.includes}"`;if(o.format==="regex")return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043D\u0438\u0437: \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0441\u044A\u0432\u043F\u0430\u0434\u0430 \u0441 ${o.pattern}`;let a="\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D";return o.format==="emoji"&&(a="\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u043E"),o.format==="datetime"&&(a="\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u043E"),o.format==="date"&&(a="\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430"),o.format==="time"&&(a="\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u043E"),o.format==="duration"&&(a="\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430"),`${a} ${n[o.format]??e.format}`}case"not_multiple_of":return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u043E \u0447\u0438\u0441\u043B\u043E: \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043A\u0440\u0430\u0442\u043D\u043E \u043D\u0430 ${e.divisor}`;case"unrecognized_keys":return`\u041D\u0435\u0440\u0430\u0437\u043F\u043E\u0437\u043D\u0430\u0442${e.keys.length>1?"\u0438":""} \u043A\u043B\u044E\u0447${e.keys.length>1?"\u043E\u0432\u0435":""}: ${f(e.keys,", ")}`;case"invalid_key":return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043A\u043B\u044E\u0447 \u0432 ${e.origin}`;case"invalid_union":return"\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u0432\u0445\u043E\u0434";case"invalid_element":return`\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430 \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442 \u0432 ${e.origin}`;default:return"\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u0432\u0445\u043E\u0434"}}}});function Dp(){return{localeError:fh()}}var fh,Up=x(()=>{w();fh=()=>{let t={string:{unit:"car\xE0cters",verb:"contenir"},file:{unit:"bytes",verb:"contenir"},array:{unit:"elements",verb:"contenir"},set:{unit:"elements",verb:"contenir"}};function r(e){return t[e]??null}let n={regex:"entrada",email:"adre\xE7a electr\xF2nica",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"data i hora ISO",date:"data ISO",time:"hora ISO",duration:"durada ISO",ipv4:"adre\xE7a IPv4",ipv6:"adre\xE7a IPv6",cidrv4:"rang IPv4",cidrv6:"rang IPv6",base64:"cadena codificada en base64",base64url:"cadena codificada en base64url",json_string:"cadena JSON",e164:"n\xFAmero E.164",jwt:"JWT",template_literal:"entrada"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Tipus inv\xE0lid: s'esperava instanceof ${e.expected}, s'ha rebut ${s}`:`Tipus inv\xE0lid: s'esperava ${o}, s'ha rebut ${s}`}case"invalid_value":return e.values.length===1?`Valor inv\xE0lid: s'esperava ${y(e.values[0])}`:`Opci\xF3 inv\xE0lida: s'esperava una de ${f(e.values," o ")}`;case"too_big":{let o=e.inclusive?"com a m\xE0xim":"menys de",a=r(e.origin);return a?`Massa gran: s'esperava que ${e.origin??"el valor"} contingu\xE9s ${o} ${e.maximum.toString()} ${a.unit??"elements"}`:`Massa gran: s'esperava que ${e.origin??"el valor"} fos ${o} ${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?"com a m\xEDnim":"m\xE9s de",a=r(e.origin);return a?`Massa petit: s'esperava que ${e.origin} contingu\xE9s ${o} ${e.minimum.toString()} ${a.unit}`:`Massa petit: s'esperava que ${e.origin} fos ${o} ${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Format inv\xE0lid: ha de comen\xE7ar amb "${o.prefix}"`:o.format==="ends_with"?`Format inv\xE0lid: ha d'acabar amb "${o.suffix}"`:o.format==="includes"?`Format inv\xE0lid: ha d'incloure "${o.includes}"`:o.format==="regex"?`Format inv\xE0lid: ha de coincidir amb el patr\xF3 ${o.pattern}`:`Format inv\xE0lid per a ${n[o.format]??e.format}`}case"not_multiple_of":return`N\xFAmero inv\xE0lid: ha de ser m\xFAltiple de ${e.divisor}`;case"unrecognized_keys":return`Clau${e.keys.length>1?"s":""} no reconeguda${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Clau inv\xE0lida a ${e.origin}`;case"invalid_union":return"Entrada inv\xE0lida";case"invalid_element":return`Element inv\xE0lid a ${e.origin}`;default:return"Entrada inv\xE0lida"}}}});function Np(){return{localeError:gh()}}var gh,Ep=x(()=>{w();gh=()=>{let t={string:{unit:"znak\u016F",verb:"m\xEDt"},file:{unit:"bajt\u016F",verb:"m\xEDt"},array:{unit:"prvk\u016F",verb:"m\xEDt"},set:{unit:"prvk\u016F",verb:"m\xEDt"}};function r(e){return t[e]??null}let n={regex:"regul\xE1rn\xED v\xFDraz",email:"e-mailov\xE1 adresa",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"datum a \u010Das ve form\xE1tu ISO",date:"datum ve form\xE1tu ISO",time:"\u010Das ve form\xE1tu ISO",duration:"doba trv\xE1n\xED ISO",ipv4:"IPv4 adresa",ipv6:"IPv6 adresa",cidrv4:"rozsah IPv4",cidrv6:"rozsah IPv6",base64:"\u0159et\u011Bzec zak\xF3dovan\xFD ve form\xE1tu base64",base64url:"\u0159et\u011Bzec zak\xF3dovan\xFD ve form\xE1tu base64url",json_string:"\u0159et\u011Bzec ve form\xE1tu JSON",e164:"\u010D\xEDslo E.164",jwt:"JWT",template_literal:"vstup"},i={nan:"NaN",number:"\u010D\xEDslo",string:"\u0159et\u011Bzec",function:"funkce",array:"pole"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Neplatn\xFD vstup: o\u010Dek\xE1v\xE1no instanceof ${e.expected}, obdr\u017Eeno ${s}`:`Neplatn\xFD vstup: o\u010Dek\xE1v\xE1no ${o}, obdr\u017Eeno ${s}`}case"invalid_value":return e.values.length===1?`Neplatn\xFD vstup: o\u010Dek\xE1v\xE1no ${y(e.values[0])}`:`Neplatn\xE1 mo\u017Enost: o\u010Dek\xE1v\xE1na jedna z hodnot ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Hodnota je p\u0159\xEDli\u0161 velk\xE1: ${e.origin??"hodnota"} mus\xED m\xEDt ${o}${e.maximum.toString()} ${a.unit??"prvk\u016F"}`:`Hodnota je p\u0159\xEDli\u0161 velk\xE1: ${e.origin??"hodnota"} mus\xED b\xFDt ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Hodnota je p\u0159\xEDli\u0161 mal\xE1: ${e.origin??"hodnota"} mus\xED m\xEDt ${o}${e.minimum.toString()} ${a.unit??"prvk\u016F"}`:`Hodnota je p\u0159\xEDli\u0161 mal\xE1: ${e.origin??"hodnota"} mus\xED b\xFDt ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Neplatn\xFD \u0159et\u011Bzec: mus\xED za\u010D\xEDnat na "${o.prefix}"`:o.format==="ends_with"?`Neplatn\xFD \u0159et\u011Bzec: mus\xED kon\u010Dit na "${o.suffix}"`:o.format==="includes"?`Neplatn\xFD \u0159et\u011Bzec: mus\xED obsahovat "${o.includes}"`:o.format==="regex"?`Neplatn\xFD \u0159et\u011Bzec: mus\xED odpov\xEDdat vzoru ${o.pattern}`:`Neplatn\xFD form\xE1t ${n[o.format]??e.format}`}case"not_multiple_of":return`Neplatn\xE9 \u010D\xEDslo: mus\xED b\xFDt n\xE1sobkem ${e.divisor}`;case"unrecognized_keys":return`Nezn\xE1m\xE9 kl\xED\u010De: ${f(e.keys,", ")}`;case"invalid_key":return`Neplatn\xFD kl\xED\u010D v ${e.origin}`;case"invalid_union":return"Neplatn\xFD vstup";case"invalid_element":return`Neplatn\xE1 hodnota v ${e.origin}`;default:return"Neplatn\xFD vstup"}}}});function Zp(){return{localeError:hh()}}var hh,Rp=x(()=>{w();hh=()=>{let t={string:{unit:"tegn",verb:"havde"},file:{unit:"bytes",verb:"havde"},array:{unit:"elementer",verb:"indeholdt"},set:{unit:"elementer",verb:"indeholdt"}};function r(e){return t[e]??null}let n={regex:"input",email:"e-mailadresse",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO dato- og klokkesl\xE6t",date:"ISO-dato",time:"ISO-klokkesl\xE6t",duration:"ISO-varighed",ipv4:"IPv4-omr\xE5de",ipv6:"IPv6-omr\xE5de",cidrv4:"IPv4-spektrum",cidrv6:"IPv6-spektrum",base64:"base64-kodet streng",base64url:"base64url-kodet streng",json_string:"JSON-streng",e164:"E.164-nummer",jwt:"JWT",template_literal:"input"},i={nan:"NaN",string:"streng",number:"tal",boolean:"boolean",array:"liste",object:"objekt",set:"s\xE6t",file:"fil"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Ugyldigt input: forventede instanceof ${e.expected}, fik ${s}`:`Ugyldigt input: forventede ${o}, fik ${s}`}case"invalid_value":return e.values.length===1?`Ugyldig v\xE6rdi: forventede ${y(e.values[0])}`:`Ugyldigt valg: forventede en af f\xF8lgende ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin),s=i[e.origin]??e.origin;return a?`For stor: forventede ${s??"value"} ${a.verb} ${o} ${e.maximum.toString()} ${a.unit??"elementer"}`:`For stor: forventede ${s??"value"} havde ${o} ${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin),s=i[e.origin]??e.origin;return a?`For lille: forventede ${s} ${a.verb} ${o} ${e.minimum.toString()} ${a.unit}`:`For lille: forventede ${s} havde ${o} ${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Ugyldig streng: skal starte med "${o.prefix}"`:o.format==="ends_with"?`Ugyldig streng: skal ende med "${o.suffix}"`:o.format==="includes"?`Ugyldig streng: skal indeholde "${o.includes}"`:o.format==="regex"?`Ugyldig streng: skal matche m\xF8nsteret ${o.pattern}`:`Ugyldig ${n[o.format]??e.format}`}case"not_multiple_of":return`Ugyldigt tal: skal v\xE6re deleligt med ${e.divisor}`;case"unrecognized_keys":return`${e.keys.length>1?"Ukendte n\xF8gler":"Ukendt n\xF8gle"}: ${f(e.keys,", ")}`;case"invalid_key":return`Ugyldig n\xF8gle i ${e.origin}`;case"invalid_union":return"Ugyldigt input: matcher ingen af de tilladte typer";case"invalid_element":return`Ugyldig v\xE6rdi i ${e.origin}`;default:return"Ugyldigt input"}}}});function Ap(){return{localeError:vh()}}var vh,Cp=x(()=>{w();vh=()=>{let t={string:{unit:"Zeichen",verb:"zu haben"},file:{unit:"Bytes",verb:"zu haben"},array:{unit:"Elemente",verb:"zu haben"},set:{unit:"Elemente",verb:"zu haben"}};function r(e){return t[e]??null}let n={regex:"Eingabe",email:"E-Mail-Adresse",url:"URL",emoji:"Emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO-Datum und -Uhrzeit",date:"ISO-Datum",time:"ISO-Uhrzeit",duration:"ISO-Dauer",ipv4:"IPv4-Adresse",ipv6:"IPv6-Adresse",cidrv4:"IPv4-Bereich",cidrv6:"IPv6-Bereich",base64:"Base64-codierter String",base64url:"Base64-URL-codierter String",json_string:"JSON-String",e164:"E.164-Nummer",jwt:"JWT",template_literal:"Eingabe"},i={nan:"NaN",number:"Zahl",array:"Array"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Ung\xFCltige Eingabe: erwartet instanceof ${e.expected}, erhalten ${s}`:`Ung\xFCltige Eingabe: erwartet ${o}, erhalten ${s}`}case"invalid_value":return e.values.length===1?`Ung\xFCltige Eingabe: erwartet ${y(e.values[0])}`:`Ung\xFCltige Option: erwartet eine von ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Zu gro\xDF: erwartet, dass ${e.origin??"Wert"} ${o}${e.maximum.toString()} ${a.unit??"Elemente"} hat`:`Zu gro\xDF: erwartet, dass ${e.origin??"Wert"} ${o}${e.maximum.toString()} ist`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Zu klein: erwartet, dass ${e.origin} ${o}${e.minimum.toString()} ${a.unit} hat`:`Zu klein: erwartet, dass ${e.origin} ${o}${e.minimum.toString()} ist`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Ung\xFCltiger String: muss mit "${o.prefix}" beginnen`:o.format==="ends_with"?`Ung\xFCltiger String: muss mit "${o.suffix}" enden`:o.format==="includes"?`Ung\xFCltiger String: muss "${o.includes}" enthalten`:o.format==="regex"?`Ung\xFCltiger String: muss dem Muster ${o.pattern} entsprechen`:`Ung\xFCltig: ${n[o.format]??e.format}`}case"not_multiple_of":return`Ung\xFCltige Zahl: muss ein Vielfaches von ${e.divisor} sein`;case"unrecognized_keys":return`${e.keys.length>1?"Unbekannte Schl\xFCssel":"Unbekannter Schl\xFCssel"}: ${f(e.keys,", ")}`;case"invalid_key":return`Ung\xFCltiger Schl\xFCssel in ${e.origin}`;case"invalid_union":return"Ung\xFCltige Eingabe";case"invalid_element":return`Ung\xFCltiger Wert in ${e.origin}`;default:return"Ung\xFCltige Eingabe"}}}});function Mp(){return{localeError:yh()}}var yh,Lp=x(()=>{w();yh=()=>{let t={string:{unit:"\u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2",verb:"\u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9"},file:{unit:"bytes",verb:"\u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9"},array:{unit:"\u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03B1",verb:"\u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9"},set:{unit:"\u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03B1",verb:"\u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9"},map:{unit:"\u03BA\u03B1\u03C4\u03B1\u03C7\u03C9\u03C1\u03AE\u03C3\u03B5\u03B9\u03C2",verb:"\u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9"}};function r(e){return t[e]??null}let n={regex:"\u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2",email:"\u03B4\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7 email",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u03B7\u03BC\u03B5\u03C1\u03BF\u03BC\u03B7\u03BD\u03AF\u03B1 \u03BA\u03B1\u03B9 \u03CE\u03C1\u03B1",date:"ISO \u03B7\u03BC\u03B5\u03C1\u03BF\u03BC\u03B7\u03BD\u03AF\u03B1",time:"ISO \u03CE\u03C1\u03B1",duration:"ISO \u03B4\u03B9\u03AC\u03C1\u03BA\u03B5\u03B9\u03B1",ipv4:"\u03B4\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7 IPv4",ipv6:"\u03B4\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7 IPv6",mac:"\u03B4\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7 MAC",cidrv4:"\u03B5\u03CD\u03C1\u03BF\u03C2 IPv4",cidrv6:"\u03B5\u03CD\u03C1\u03BF\u03C2 IPv6",base64:"\u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03C0\u03BF\u03B9\u03B7\u03BC\u03AD\u03BD\u03B7 \u03C3\u03B5 base64",base64url:"\u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03C0\u03BF\u03B9\u03B7\u03BC\u03AD\u03BD\u03B7 \u03C3\u03B5 base64url",json_string:"\u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC JSON",e164:"\u03B1\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2 E.164",jwt:"JWT",template_literal:"\u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return typeof e.expected=="string"&&/^[A-Z]/.test(e.expected)?`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD instanceof ${e.expected}, \u03BB\u03AE\u03C6\u03B8\u03B7\u03BA\u03B5 ${s}`:`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD ${o}, \u03BB\u03AE\u03C6\u03B8\u03B7\u03BA\u03B5 ${s}`}case"invalid_value":return e.values.length===1?`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD ${y(e.values[0])}`:`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03B5\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD \u03AD\u03BD\u03B1 \u03B1\u03C0\u03CC ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u03A0\u03BF\u03BB\u03CD \u03BC\u03B5\u03B3\u03AC\u03BB\u03BF: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD ${e.origin??"\u03C4\u03B9\u03BC\u03AE"} \u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9 ${o}${e.maximum.toString()} ${a.unit??"\u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03B1"}`:`\u03A0\u03BF\u03BB\u03CD \u03BC\u03B5\u03B3\u03AC\u03BB\u03BF: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD ${e.origin??"\u03C4\u03B9\u03BC\u03AE"} \u03BD\u03B1 \u03B5\u03AF\u03BD\u03B1\u03B9 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u03A0\u03BF\u03BB\u03CD \u03BC\u03B9\u03BA\u03C1\u03CC: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD ${e.origin} \u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9 ${o}${e.minimum.toString()} ${a.unit}`:`\u03A0\u03BF\u03BB\u03CD \u03BC\u03B9\u03BA\u03C1\u03CC: \u03B1\u03BD\u03B1\u03BC\u03B5\u03BD\u03CC\u03C4\u03B1\u03BD ${e.origin} \u03BD\u03B1 \u03B5\u03AF\u03BD\u03B1\u03B9 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC: \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03BE\u03B5\u03BA\u03B9\u03BD\u03AC \u03BC\u03B5 "${o.prefix}"`:o.format==="ends_with"?`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC: \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03C4\u03B5\u03BB\u03B5\u03B9\u03CE\u03BD\u03B5\u03B9 \u03BC\u03B5 "${o.suffix}"`:o.format==="includes"?`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC: \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03B5\u03B9 "${o.includes}"`:o.format==="regex"?`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC: \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03C4\u03B1\u03B9\u03C1\u03B9\u03AC\u03B6\u03B5\u03B9 \u03BC\u03B5 \u03C4\u03BF \u03BC\u03BF\u03C4\u03AF\u03B2\u03BF ${o.pattern}`:`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03BF: ${n[o.format]??e.format}`}case"not_multiple_of":return`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03BF\u03C2 \u03B1\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2: \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03C0\u03BF\u03BB\u03BB\u03B1\u03C0\u03BB\u03AC\u03C3\u03B9\u03BF \u03C4\u03BF\u03C5 ${e.divisor}`;case"unrecognized_keys":return`\u0386\u03B3\u03BD\u03C9\u03C3\u03C4${e.keys.length>1?"\u03B1":"\u03BF"} \u03BA\u03BB\u03B5\u03B9\u03B4${e.keys.length>1?"\u03B9\u03AC":"\u03AF"}: ${f(e.keys,", ")}`;case"invalid_key":return`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03BF \u03BA\u03BB\u03B5\u03B9\u03B4\u03AF \u03C3\u03C4\u03BF ${e.origin}`;case"invalid_union":return"\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2";case"invalid_element":return`\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03C4\u03B9\u03BC\u03AE \u03C3\u03C4\u03BF ${e.origin}`;default:return"\u039C\u03B7 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7 \u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2"}}}});function Qn(){return{localeError:bh()}}var bh,bc=x(()=>{w();bh=()=>{let t={string:{unit:"characters",verb:"to have"},file:{unit:"bytes",verb:"to have"},array:{unit:"items",verb:"to have"},set:{unit:"items",verb:"to have"},map:{unit:"entries",verb:"to have"}};function r(e){return t[e]??null}let n={regex:"input",email:"email address",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datetime",date:"ISO date",time:"ISO time",duration:"ISO duration",ipv4:"IPv4 address",ipv6:"IPv6 address",mac:"MAC address",cidrv4:"IPv4 range",cidrv6:"IPv6 range",base64:"base64-encoded string",base64url:"base64url-encoded string",json_string:"JSON string",e164:"E.164 number",jwt:"JWT",template_literal:"input"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return`Invalid input: expected ${o}, received ${s}`}case"invalid_value":return e.values.length===1?`Invalid input: expected ${y(e.values[0])}`:`Invalid option: expected one of ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Too big: expected ${e.origin??"value"} to have ${o}${e.maximum.toString()} ${a.unit??"elements"}`:`Too big: expected ${e.origin??"value"} to be ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Too small: expected ${e.origin} to have ${o}${e.minimum.toString()} ${a.unit}`:`Too small: expected ${e.origin} to be ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Invalid string: must start with "${o.prefix}"`:o.format==="ends_with"?`Invalid string: must end with "${o.suffix}"`:o.format==="includes"?`Invalid string: must include "${o.includes}"`:o.format==="regex"?`Invalid string: must match pattern ${o.pattern}`:`Invalid ${n[o.format]??e.format}`}case"not_multiple_of":return`Invalid number: must be a multiple of ${e.divisor}`;case"unrecognized_keys":return`Unrecognized key${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Invalid key in ${e.origin}`;case"invalid_union":return e.options&&Array.isArray(e.options)&&e.options.length>0?`Invalid discriminator value. Expected ${e.options.map(a=>`'${a}'`).join(" | ")}`:"Invalid input";case"invalid_element":return`Invalid value in ${e.origin}`;default:return"Invalid input"}}}});function qp(){return{localeError:_h()}}var _h,Fp=x(()=>{w();_h=()=>{let t={string:{unit:"karaktrojn",verb:"havi"},file:{unit:"bajtojn",verb:"havi"},array:{unit:"elementojn",verb:"havi"},set:{unit:"elementojn",verb:"havi"}};function r(e){return t[e]??null}let n={regex:"enigo",email:"retadreso",url:"URL",emoji:"emo\u011Dio",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO-datotempo",date:"ISO-dato",time:"ISO-tempo",duration:"ISO-da\u016Dro",ipv4:"IPv4-adreso",ipv6:"IPv6-adreso",cidrv4:"IPv4-rango",cidrv6:"IPv6-rango",base64:"64-ume kodita karaktraro",base64url:"URL-64-ume kodita karaktraro",json_string:"JSON-karaktraro",e164:"E.164-nombro",jwt:"JWT",template_literal:"enigo"},i={nan:"NaN",number:"nombro",array:"tabelo",null:"senvalora"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Nevalida enigo: atendi\u011Dis instanceof ${e.expected}, ricevi\u011Dis ${s}`:`Nevalida enigo: atendi\u011Dis ${o}, ricevi\u011Dis ${s}`}case"invalid_value":return e.values.length===1?`Nevalida enigo: atendi\u011Dis ${y(e.values[0])}`:`Nevalida opcio: atendi\u011Dis unu el ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Tro granda: atendi\u011Dis ke ${e.origin??"valoro"} havu ${o}${e.maximum.toString()} ${a.unit??"elementojn"}`:`Tro granda: atendi\u011Dis ke ${e.origin??"valoro"} havu ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Tro malgranda: atendi\u011Dis ke ${e.origin} havu ${o}${e.minimum.toString()} ${a.unit}`:`Tro malgranda: atendi\u011Dis ke ${e.origin} estu ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Nevalida karaktraro: devas komenci\u011Di per "${o.prefix}"`:o.format==="ends_with"?`Nevalida karaktraro: devas fini\u011Di per "${o.suffix}"`:o.format==="includes"?`Nevalida karaktraro: devas inkluzivi "${o.includes}"`:o.format==="regex"?`Nevalida karaktraro: devas kongrui kun la modelo ${o.pattern}`:`Nevalida ${n[o.format]??e.format}`}case"not_multiple_of":return`Nevalida nombro: devas esti oblo de ${e.divisor}`;case"unrecognized_keys":return`Nekonata${e.keys.length>1?"j":""} \u015Dlosilo${e.keys.length>1?"j":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Nevalida \u015Dlosilo en ${e.origin}`;case"invalid_union":return"Nevalida enigo";case"invalid_element":return`Nevalida valoro en ${e.origin}`;default:return"Nevalida enigo"}}}});function Jp(){return{localeError:$h()}}var $h,Vp=x(()=>{w();$h=()=>{let t={string:{unit:"caracteres",verb:"tener"},file:{unit:"bytes",verb:"tener"},array:{unit:"elementos",verb:"tener"},set:{unit:"elementos",verb:"tener"}};function r(e){return t[e]??null}let n={regex:"entrada",email:"direcci\xF3n de correo electr\xF3nico",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"fecha y hora ISO",date:"fecha ISO",time:"hora ISO",duration:"duraci\xF3n ISO",ipv4:"direcci\xF3n IPv4",ipv6:"direcci\xF3n IPv6",cidrv4:"rango IPv4",cidrv6:"rango IPv6",base64:"cadena codificada en base64",base64url:"URL codificada en base64",json_string:"cadena JSON",e164:"n\xFAmero E.164",jwt:"JWT",template_literal:"entrada"},i={nan:"NaN",string:"texto",number:"n\xFAmero",boolean:"booleano",array:"arreglo",object:"objeto",set:"conjunto",file:"archivo",date:"fecha",bigint:"n\xFAmero grande",symbol:"s\xEDmbolo",undefined:"indefinido",null:"nulo",function:"funci\xF3n",map:"mapa",record:"registro",tuple:"tupla",enum:"enumeraci\xF3n",union:"uni\xF3n",literal:"literal",promise:"promesa",void:"vac\xEDo",never:"nunca",unknown:"desconocido",any:"cualquiera"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Entrada inv\xE1lida: se esperaba instanceof ${e.expected}, recibido ${s}`:`Entrada inv\xE1lida: se esperaba ${o}, recibido ${s}`}case"invalid_value":return e.values.length===1?`Entrada inv\xE1lida: se esperaba ${y(e.values[0])}`:`Opci\xF3n inv\xE1lida: se esperaba una de ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin),s=i[e.origin]??e.origin;return a?`Demasiado grande: se esperaba que ${s??"valor"} tuviera ${o}${e.maximum.toString()} ${a.unit??"elementos"}`:`Demasiado grande: se esperaba que ${s??"valor"} fuera ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin),s=i[e.origin]??e.origin;return a?`Demasiado peque\xF1o: se esperaba que ${s} tuviera ${o}${e.minimum.toString()} ${a.unit}`:`Demasiado peque\xF1o: se esperaba que ${s} fuera ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Cadena inv\xE1lida: debe comenzar con "${o.prefix}"`:o.format==="ends_with"?`Cadena inv\xE1lida: debe terminar en "${o.suffix}"`:o.format==="includes"?`Cadena inv\xE1lida: debe incluir "${o.includes}"`:o.format==="regex"?`Cadena inv\xE1lida: debe coincidir con el patr\xF3n ${o.pattern}`:`Inv\xE1lido ${n[o.format]??e.format}`}case"not_multiple_of":return`N\xFAmero inv\xE1lido: debe ser m\xFAltiplo de ${e.divisor}`;case"unrecognized_keys":return`Llave${e.keys.length>1?"s":""} desconocida${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Llave inv\xE1lida en ${i[e.origin]??e.origin}`;case"invalid_union":return"Entrada inv\xE1lida";case"invalid_element":return`Valor inv\xE1lido en ${i[e.origin]??e.origin}`;default:return"Entrada inv\xE1lida"}}}});function Hp(){return{localeError:xh()}}var xh,Bp=x(()=>{w();xh=()=>{let t={string:{unit:"\u06A9\u0627\u0631\u0627\u06A9\u062A\u0631",verb:"\u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F"},file:{unit:"\u0628\u0627\u06CC\u062A",verb:"\u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F"},array:{unit:"\u0622\u06CC\u062A\u0645",verb:"\u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F"},set:{unit:"\u0622\u06CC\u062A\u0645",verb:"\u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F"}};function r(e){return t[e]??null}let n={regex:"\u0648\u0631\u0648\u062F\u06CC",email:"\u0622\u062F\u0631\u0633 \u0627\u06CC\u0645\u06CC\u0644",url:"URL",emoji:"\u0627\u06CC\u0645\u0648\u062C\u06CC",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u062A\u0627\u0631\u06CC\u062E \u0648 \u0632\u0645\u0627\u0646 \u0627\u06CC\u0632\u0648",date:"\u062A\u0627\u0631\u06CC\u062E \u0627\u06CC\u0632\u0648",time:"\u0632\u0645\u0627\u0646 \u0627\u06CC\u0632\u0648",duration:"\u0645\u062F\u062A \u0632\u0645\u0627\u0646 \u0627\u06CC\u0632\u0648",ipv4:"IPv4 \u0622\u062F\u0631\u0633",ipv6:"IPv6 \u0622\u062F\u0631\u0633",cidrv4:"IPv4 \u062F\u0627\u0645\u0646\u0647",cidrv6:"IPv6 \u062F\u0627\u0645\u0646\u0647",base64:"base64-encoded \u0631\u0634\u062A\u0647",base64url:"base64url-encoded \u0631\u0634\u062A\u0647",json_string:"JSON \u0631\u0634\u062A\u0647",e164:"E.164 \u0639\u062F\u062F",jwt:"JWT",template_literal:"\u0648\u0631\u0648\u062F\u06CC"},i={nan:"NaN",number:"\u0639\u062F\u062F",array:"\u0622\u0631\u0627\u06CC\u0647"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0648\u0631\u0648\u062F\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0645\u06CC\u200C\u0628\u0627\u06CC\u0633\u062A instanceof ${e.expected} \u0645\u06CC\u200C\u0628\u0648\u062F\u060C ${s} \u062F\u0631\u06CC\u0627\u0641\u062A \u0634\u062F`:`\u0648\u0631\u0648\u062F\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0645\u06CC\u200C\u0628\u0627\u06CC\u0633\u062A ${o} \u0645\u06CC\u200C\u0628\u0648\u062F\u060C ${s} \u062F\u0631\u06CC\u0627\u0641\u062A \u0634\u062F`}case"invalid_value":return e.values.length===1?`\u0648\u0631\u0648\u062F\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0645\u06CC\u200C\u0628\u0627\u06CC\u0633\u062A ${y(e.values[0])} \u0645\u06CC\u200C\u0628\u0648\u062F`:`\u06AF\u0632\u06CC\u0646\u0647 \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0645\u06CC\u200C\u0628\u0627\u06CC\u0633\u062A \u06CC\u06A9\u06CC \u0627\u0632 ${f(e.values,"|")} \u0645\u06CC\u200C\u0628\u0648\u062F`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u062E\u06CC\u0644\u06CC \u0628\u0632\u0631\u06AF: ${e.origin??"\u0645\u0642\u062F\u0627\u0631"} \u0628\u0627\u06CC\u062F ${o}${e.maximum.toString()} ${a.unit??"\u0639\u0646\u0635\u0631"} \u0628\u0627\u0634\u062F`:`\u062E\u06CC\u0644\u06CC \u0628\u0632\u0631\u06AF: ${e.origin??"\u0645\u0642\u062F\u0627\u0631"} \u0628\u0627\u06CC\u062F ${o}${e.maximum.toString()} \u0628\u0627\u0634\u062F`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u062E\u06CC\u0644\u06CC \u06A9\u0648\u0686\u06A9: ${e.origin} \u0628\u0627\u06CC\u062F ${o}${e.minimum.toString()} ${a.unit} \u0628\u0627\u0634\u062F`:`\u062E\u06CC\u0644\u06CC \u06A9\u0648\u0686\u06A9: ${e.origin} \u0628\u0627\u06CC\u062F ${o}${e.minimum.toString()} \u0628\u0627\u0634\u062F`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u0631\u0634\u062A\u0647 \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0628\u0627\u06CC\u062F \u0628\u0627 "${o.prefix}" \u0634\u0631\u0648\u0639 \u0634\u0648\u062F`:o.format==="ends_with"?`\u0631\u0634\u062A\u0647 \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0628\u0627\u06CC\u062F \u0628\u0627 "${o.suffix}" \u062A\u0645\u0627\u0645 \u0634\u0648\u062F`:o.format==="includes"?`\u0631\u0634\u062A\u0647 \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0628\u0627\u06CC\u062F \u0634\u0627\u0645\u0644 "${o.includes}" \u0628\u0627\u0634\u062F`:o.format==="regex"?`\u0631\u0634\u062A\u0647 \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0628\u0627\u06CC\u062F \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC ${o.pattern} \u0645\u0637\u0627\u0628\u0642\u062A \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F`:`${n[o.format]??e.format} \u0646\u0627\u0645\u0639\u062A\u0628\u0631`}case"not_multiple_of":return`\u0639\u062F\u062F \u0646\u0627\u0645\u0639\u062A\u0628\u0631: \u0628\u0627\u06CC\u062F \u0645\u0636\u0631\u0628 ${e.divisor} \u0628\u0627\u0634\u062F`;case"unrecognized_keys":return`\u06A9\u0644\u06CC\u062F${e.keys.length>1?"\u0647\u0627\u06CC":""} \u0646\u0627\u0634\u0646\u0627\u0633: ${f(e.keys,", ")}`;case"invalid_key":return`\u06A9\u0644\u06CC\u062F \u0646\u0627\u0634\u0646\u0627\u0633 \u062F\u0631 ${e.origin}`;case"invalid_union":return"\u0648\u0631\u0648\u062F\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631";case"invalid_element":return`\u0645\u0642\u062F\u0627\u0631 \u0646\u0627\u0645\u0639\u062A\u0628\u0631 \u062F\u0631 ${e.origin}`;default:return"\u0648\u0631\u0648\u062F\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631"}}}});function Wp(){return{localeError:kh()}}var kh,Kp=x(()=>{w();kh=()=>{let t={string:{unit:"merkki\xE4",subject:"merkkijonon"},file:{unit:"tavua",subject:"tiedoston"},array:{unit:"alkiota",subject:"listan"},set:{unit:"alkiota",subject:"joukon"},number:{unit:"",subject:"luvun"},bigint:{unit:"",subject:"suuren kokonaisluvun"},int:{unit:"",subject:"kokonaisluvun"},date:{unit:"",subject:"p\xE4iv\xE4m\xE4\xE4r\xE4n"}};function r(e){return t[e]??null}let n={regex:"s\xE4\xE4nn\xF6llinen lauseke",email:"s\xE4hk\xF6postiosoite",url:"URL-osoite",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO-aikaleima",date:"ISO-p\xE4iv\xE4m\xE4\xE4r\xE4",time:"ISO-aika",duration:"ISO-kesto",ipv4:"IPv4-osoite",ipv6:"IPv6-osoite",cidrv4:"IPv4-alue",cidrv6:"IPv6-alue",base64:"base64-koodattu merkkijono",base64url:"base64url-koodattu merkkijono",json_string:"JSON-merkkijono",e164:"E.164-luku",jwt:"JWT",template_literal:"templaattimerkkijono"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Virheellinen tyyppi: odotettiin instanceof ${e.expected}, oli ${s}`:`Virheellinen tyyppi: odotettiin ${o}, oli ${s}`}case"invalid_value":return e.values.length===1?`Virheellinen sy\xF6te: t\xE4ytyy olla ${y(e.values[0])}`:`Virheellinen valinta: t\xE4ytyy olla yksi seuraavista: ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Liian suuri: ${a.subject} t\xE4ytyy olla ${o}${e.maximum.toString()} ${a.unit}`.trim():`Liian suuri: arvon t\xE4ytyy olla ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Liian pieni: ${a.subject} t\xE4ytyy olla ${o}${e.minimum.toString()} ${a.unit}`.trim():`Liian pieni: arvon t\xE4ytyy olla ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Virheellinen sy\xF6te: t\xE4ytyy alkaa "${o.prefix}"`:o.format==="ends_with"?`Virheellinen sy\xF6te: t\xE4ytyy loppua "${o.suffix}"`:o.format==="includes"?`Virheellinen sy\xF6te: t\xE4ytyy sis\xE4lt\xE4\xE4 "${o.includes}"`:o.format==="regex"?`Virheellinen sy\xF6te: t\xE4ytyy vastata s\xE4\xE4nn\xF6llist\xE4 lauseketta ${o.pattern}`:`Virheellinen ${n[o.format]??e.format}`}case"not_multiple_of":return`Virheellinen luku: t\xE4ytyy olla luvun ${e.divisor} monikerta`;case"unrecognized_keys":return`${e.keys.length>1?"Tuntemattomat avaimet":"Tuntematon avain"}: ${f(e.keys,", ")}`;case"invalid_key":return"Virheellinen avain tietueessa";case"invalid_union":return"Virheellinen unioni";case"invalid_element":return"Virheellinen arvo joukossa";default:return"Virheellinen sy\xF6te"}}}});function Gp(){return{localeError:zh()}}var zh,Qp=x(()=>{w();zh=()=>{let t={string:{unit:"caract\xE8res",verb:"avoir"},file:{unit:"octets",verb:"avoir"},array:{unit:"\xE9l\xE9ments",verb:"avoir"},set:{unit:"\xE9l\xE9ments",verb:"avoir"}};function r(e){return t[e]??null}let n={regex:"entr\xE9e",email:"adresse e-mail",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"date et heure ISO",date:"date ISO",time:"heure ISO",duration:"dur\xE9e ISO",ipv4:"adresse IPv4",ipv6:"adresse IPv6",cidrv4:"plage IPv4",cidrv6:"plage IPv6",base64:"cha\xEEne encod\xE9e en base64",base64url:"cha\xEEne encod\xE9e en base64url",json_string:"cha\xEEne JSON",e164:"num\xE9ro E.164",jwt:"JWT",template_literal:"entr\xE9e"},i={string:"cha\xEEne",number:"nombre",int:"entier",boolean:"bool\xE9en",bigint:"grand entier",symbol:"symbole",undefined:"ind\xE9fini",null:"null",never:"jamais",void:"vide",date:"date",array:"tableau",object:"objet",tuple:"tuple",record:"enregistrement",map:"carte",set:"ensemble",file:"fichier",nonoptional:"non-optionnel",nan:"NaN",function:"fonction"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Entr\xE9e invalide : instanceof ${e.expected} attendu, ${s} re\xE7u`:`Entr\xE9e invalide : ${o} attendu, ${s} re\xE7u`}case"invalid_value":return e.values.length===1?`Entr\xE9e invalide : ${y(e.values[0])} attendu`:`Option invalide : une valeur parmi ${f(e.values,"|")} attendue`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Trop grand : ${i[e.origin]??"valeur"} doit ${a.verb} ${o}${e.maximum.toString()} ${a.unit??"\xE9l\xE9ment(s)"}`:`Trop grand : ${i[e.origin]??"valeur"} doit \xEAtre ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Trop petit : ${i[e.origin]??"valeur"} doit ${a.verb} ${o}${e.minimum.toString()} ${a.unit}`:`Trop petit : ${i[e.origin]??"valeur"} doit \xEAtre ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Cha\xEEne invalide : doit commencer par "${o.prefix}"`:o.format==="ends_with"?`Cha\xEEne invalide : doit se terminer par "${o.suffix}"`:o.format==="includes"?`Cha\xEEne invalide : doit inclure "${o.includes}"`:o.format==="regex"?`Cha\xEEne invalide : doit correspondre au mod\xE8le ${o.pattern}`:`${n[o.format]??e.format} invalide`}case"not_multiple_of":return`Nombre invalide : doit \xEAtre un multiple de ${e.divisor}`;case"unrecognized_keys":return`Cl\xE9${e.keys.length>1?"s":""} non reconnue${e.keys.length>1?"s":""} : ${f(e.keys,", ")}`;case"invalid_key":return`Cl\xE9 invalide dans ${e.origin}`;case"invalid_union":return"Entr\xE9e invalide";case"invalid_element":return`Valeur invalide dans ${e.origin}`;default:return"Entr\xE9e invalide"}}}});function Xp(){return{localeError:Sh()}}var Sh,Yp=x(()=>{w();Sh=()=>{let t={string:{unit:"caract\xE8res",verb:"avoir"},file:{unit:"octets",verb:"avoir"},array:{unit:"\xE9l\xE9ments",verb:"avoir"},set:{unit:"\xE9l\xE9ments",verb:"avoir"}};function r(e){return t[e]??null}let n={regex:"entr\xE9e",email:"adresse courriel",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"date-heure ISO",date:"date ISO",time:"heure ISO",duration:"dur\xE9e ISO",ipv4:"adresse IPv4",ipv6:"adresse IPv6",cidrv4:"plage IPv4",cidrv6:"plage IPv6",base64:"cha\xEEne encod\xE9e en base64",base64url:"cha\xEEne encod\xE9e en base64url",json_string:"cha\xEEne JSON",e164:"num\xE9ro E.164",jwt:"JWT",template_literal:"entr\xE9e"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Entr\xE9e invalide : attendu instanceof ${e.expected}, re\xE7u ${s}`:`Entr\xE9e invalide : attendu ${o}, re\xE7u ${s}`}case"invalid_value":return e.values.length===1?`Entr\xE9e invalide : attendu ${y(e.values[0])}`:`Option invalide : attendu l'une des valeurs suivantes ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"\u2264":"<",a=r(e.origin);return a?`Trop grand : attendu que ${e.origin??"la valeur"} ait ${o}${e.maximum.toString()} ${a.unit}`:`Trop grand : attendu que ${e.origin??"la valeur"} soit ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?"\u2265":">",a=r(e.origin);return a?`Trop petit : attendu que ${e.origin} ait ${o}${e.minimum.toString()} ${a.unit}`:`Trop petit : attendu que ${e.origin} soit ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Cha\xEEne invalide : doit commencer par "${o.prefix}"`:o.format==="ends_with"?`Cha\xEEne invalide : doit se terminer par "${o.suffix}"`:o.format==="includes"?`Cha\xEEne invalide : doit inclure "${o.includes}"`:o.format==="regex"?`Cha\xEEne invalide : doit correspondre au motif ${o.pattern}`:`${n[o.format]??e.format} invalide`}case"not_multiple_of":return`Nombre invalide : doit \xEAtre un multiple de ${e.divisor}`;case"unrecognized_keys":return`Cl\xE9${e.keys.length>1?"s":""} non reconnue${e.keys.length>1?"s":""} : ${f(e.keys,", ")}`;case"invalid_key":return`Cl\xE9 invalide dans ${e.origin}`;case"invalid_union":return"Entr\xE9e invalide";case"invalid_element":return`Valeur invalide dans ${e.origin}`;default:return"Entr\xE9e invalide"}}}});function em(){return{localeError:wh()}}var wh,tm=x(()=>{w();wh=()=>{let t={string:{label:"\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA",gender:"f"},number:{label:"\u05DE\u05E1\u05E4\u05E8",gender:"m"},boolean:{label:"\u05E2\u05E8\u05DA \u05D1\u05D5\u05DC\u05D9\u05D0\u05E0\u05D9",gender:"m"},bigint:{label:"BigInt",gender:"m"},date:{label:"\u05EA\u05D0\u05E8\u05D9\u05DA",gender:"m"},array:{label:"\u05DE\u05E2\u05E8\u05DA",gender:"m"},object:{label:"\u05D0\u05D5\u05D1\u05D9\u05D9\u05E7\u05D8",gender:"m"},null:{label:"\u05E2\u05E8\u05DA \u05E8\u05D9\u05E7 (null)",gender:"m"},undefined:{label:"\u05E2\u05E8\u05DA \u05DC\u05D0 \u05DE\u05D5\u05D2\u05D3\u05E8 (undefined)",gender:"m"},symbol:{label:"\u05E1\u05D9\u05DE\u05D1\u05D5\u05DC (Symbol)",gender:"m"},function:{label:"\u05E4\u05D5\u05E0\u05E7\u05E6\u05D9\u05D4",gender:"f"},map:{label:"\u05DE\u05E4\u05D4 (Map)",gender:"f"},set:{label:"\u05E7\u05D1\u05D5\u05E6\u05D4 (Set)",gender:"f"},file:{label:"\u05E7\u05D5\u05D1\u05E5",gender:"m"},promise:{label:"Promise",gender:"m"},NaN:{label:"NaN",gender:"m"},unknown:{label:"\u05E2\u05E8\u05DA \u05DC\u05D0 \u05D9\u05D3\u05D5\u05E2",gender:"m"},value:{label:"\u05E2\u05E8\u05DA",gender:"m"}},r={string:{unit:"\u05EA\u05D5\u05D5\u05D9\u05DD",shortLabel:"\u05E7\u05E6\u05E8",longLabel:"\u05D0\u05E8\u05D5\u05DA"},file:{unit:"\u05D1\u05D9\u05D9\u05D8\u05D9\u05DD",shortLabel:"\u05E7\u05D8\u05DF",longLabel:"\u05D2\u05D3\u05D5\u05DC"},array:{unit:"\u05E4\u05E8\u05D9\u05D8\u05D9\u05DD",shortLabel:"\u05E7\u05D8\u05DF",longLabel:"\u05D2\u05D3\u05D5\u05DC"},set:{unit:"\u05E4\u05E8\u05D9\u05D8\u05D9\u05DD",shortLabel:"\u05E7\u05D8\u05DF",longLabel:"\u05D2\u05D3\u05D5\u05DC"},number:{unit:"",shortLabel:"\u05E7\u05D8\u05DF",longLabel:"\u05D2\u05D3\u05D5\u05DC"}},n=u=>u?t[u]:void 0,i=u=>{let d=n(u);return d?d.label:u??t.unknown.label},e=u=>`\u05D4${i(u)}`,o=u=>(n(u)?.gender??"m")==="f"?"\u05E6\u05E8\u05D9\u05DB\u05D4 \u05DC\u05D4\u05D9\u05D5\u05EA":"\u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA",a=u=>u?r[u]??null:null,s={regex:{label:"\u05E7\u05DC\u05D8",gender:"m"},email:{label:"\u05DB\u05EA\u05D5\u05D1\u05EA \u05D0\u05D9\u05DE\u05D9\u05D9\u05DC",gender:"f"},url:{label:"\u05DB\u05EA\u05D5\u05D1\u05EA \u05E8\u05E9\u05EA",gender:"f"},emoji:{label:"\u05D0\u05D9\u05DE\u05D5\u05D2'\u05D9",gender:"m"},uuid:{label:"UUID",gender:"m"},nanoid:{label:"nanoid",gender:"m"},guid:{label:"GUID",gender:"m"},cuid:{label:"cuid",gender:"m"},cuid2:{label:"cuid2",gender:"m"},ulid:{label:"ULID",gender:"m"},xid:{label:"XID",gender:"m"},ksuid:{label:"KSUID",gender:"m"},datetime:{label:"\u05EA\u05D0\u05E8\u05D9\u05DA \u05D5\u05D6\u05DE\u05DF ISO",gender:"m"},date:{label:"\u05EA\u05D0\u05E8\u05D9\u05DA ISO",gender:"m"},time:{label:"\u05D6\u05DE\u05DF ISO",gender:"m"},duration:{label:"\u05DE\u05E9\u05DA \u05D6\u05DE\u05DF ISO",gender:"m"},ipv4:{label:"\u05DB\u05EA\u05D5\u05D1\u05EA IPv4",gender:"f"},ipv6:{label:"\u05DB\u05EA\u05D5\u05D1\u05EA IPv6",gender:"f"},cidrv4:{label:"\u05D8\u05D5\u05D5\u05D7 IPv4",gender:"m"},cidrv6:{label:"\u05D8\u05D5\u05D5\u05D7 IPv6",gender:"m"},base64:{label:"\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA \u05D1\u05D1\u05E1\u05D9\u05E1 64",gender:"f"},base64url:{label:"\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA \u05D1\u05D1\u05E1\u05D9\u05E1 64 \u05DC\u05DB\u05EA\u05D5\u05D1\u05D5\u05EA \u05E8\u05E9\u05EA",gender:"f"},json_string:{label:"\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA JSON",gender:"f"},e164:{label:"\u05DE\u05E1\u05E4\u05E8 E.164",gender:"m"},jwt:{label:"JWT",gender:"m"},ends_with:{label:"\u05E7\u05DC\u05D8",gender:"m"},includes:{label:"\u05E7\u05DC\u05D8",gender:"m"},lowercase:{label:"\u05E7\u05DC\u05D8",gender:"m"},starts_with:{label:"\u05E7\u05DC\u05D8",gender:"m"},uppercase:{label:"\u05E7\u05DC\u05D8",gender:"m"}},c={nan:"NaN"};return u=>{switch(u.code){case"invalid_type":{let d=u.expected,m=c[d??""]??i(d),h=b(u.input),v=c[h]??t[h]?.label??h;return/^[A-Z]/.test(u.expected)?`\u05E7\u05DC\u05D8 \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA instanceof ${u.expected}, \u05D4\u05EA\u05E7\u05D1\u05DC ${v}`:`\u05E7\u05DC\u05D8 \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA ${m}, \u05D4\u05EA\u05E7\u05D1\u05DC ${v}`}case"invalid_value":{if(u.values.length===1)return`\u05E2\u05E8\u05DA \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05D4\u05E2\u05E8\u05DA \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA ${y(u.values[0])}`;let d=u.values.map(v=>y(v));if(u.values.length===2)return`\u05E2\u05E8\u05DA \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05D4\u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA \u05D4\u05DE\u05EA\u05D0\u05D9\u05DE\u05D5\u05EA \u05D4\u05DF ${d[0]} \u05D0\u05D5 ${d[1]}`;let m=d[d.length-1];return`\u05E2\u05E8\u05DA \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05D4\u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA \u05D4\u05DE\u05EA\u05D0\u05D9\u05DE\u05D5\u05EA \u05D4\u05DF ${d.slice(0,-1).join(", ")} \u05D0\u05D5 ${m}`}case"too_big":{let d=a(u.origin),m=e(u.origin??"value");if(u.origin==="string")return`${d?.longLabel??"\u05D0\u05E8\u05D5\u05DA"} \u05DE\u05D3\u05D9: ${m} \u05E6\u05E8\u05D9\u05DB\u05D4 \u05DC\u05D4\u05DB\u05D9\u05DC ${u.maximum.toString()} ${d?.unit??""} ${u.inclusive?"\u05D0\u05D5 \u05E4\u05D7\u05D5\u05EA":"\u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8"}`.trim();if(u.origin==="number"){let S=u.inclusive?`\u05E7\u05D8\u05DF \u05D0\u05D5 \u05E9\u05D5\u05D5\u05D4 \u05DC-${u.maximum}`:`\u05E7\u05D8\u05DF \u05DE-${u.maximum}`;return`\u05D2\u05D3\u05D5\u05DC \u05DE\u05D3\u05D9: ${m} \u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA ${S}`}if(u.origin==="array"||u.origin==="set"){let S=u.origin==="set"?"\u05E6\u05E8\u05D9\u05DB\u05D4":"\u05E6\u05E8\u05D9\u05DA",G=u.inclusive?`${u.maximum} ${d?.unit??""} \u05D0\u05D5 \u05E4\u05D7\u05D5\u05EA`:`\u05E4\u05D7\u05D5\u05EA \u05DE-${u.maximum} ${d?.unit??""}`;return`\u05D2\u05D3\u05D5\u05DC \u05DE\u05D3\u05D9: ${m} ${S} \u05DC\u05D4\u05DB\u05D9\u05DC ${G}`.trim()}let h=u.inclusive?"<=":"<",v=o(u.origin??"value");return d?.unit?`${d.longLabel} \u05DE\u05D3\u05D9: ${m} ${v} ${h}${u.maximum.toString()} ${d.unit}`:`${d?.longLabel??"\u05D2\u05D3\u05D5\u05DC"} \u05DE\u05D3\u05D9: ${m} ${v} ${h}${u.maximum.toString()}`}case"too_small":{let d=a(u.origin),m=e(u.origin??"value");if(u.origin==="string")return`${d?.shortLabel??"\u05E7\u05E6\u05E8"} \u05DE\u05D3\u05D9: ${m} \u05E6\u05E8\u05D9\u05DB\u05D4 \u05DC\u05D4\u05DB\u05D9\u05DC ${u.minimum.toString()} ${d?.unit??""} ${u.inclusive?"\u05D0\u05D5 \u05D9\u05D5\u05EA\u05E8":"\u05DC\u05E4\u05D7\u05D5\u05EA"}`.trim();if(u.origin==="number"){let S=u.inclusive?`\u05D2\u05D3\u05D5\u05DC \u05D0\u05D5 \u05E9\u05D5\u05D5\u05D4 \u05DC-${u.minimum}`:`\u05D2\u05D3\u05D5\u05DC \u05DE-${u.minimum}`;return`\u05E7\u05D8\u05DF \u05DE\u05D3\u05D9: ${m} \u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA ${S}`}if(u.origin==="array"||u.origin==="set"){let S=u.origin==="set"?"\u05E6\u05E8\u05D9\u05DB\u05D4":"\u05E6\u05E8\u05D9\u05DA";if(u.minimum===1&&u.inclusive){let V=(u.origin==="set","\u05DC\u05E4\u05D7\u05D5\u05EA \u05E4\u05E8\u05D9\u05D8 \u05D0\u05D7\u05D3");return`\u05E7\u05D8\u05DF \u05DE\u05D3\u05D9: ${m} ${S} \u05DC\u05D4\u05DB\u05D9\u05DC ${V}`}let G=u.inclusive?`${u.minimum} ${d?.unit??""} \u05D0\u05D5 \u05D9\u05D5\u05EA\u05E8`:`\u05D9\u05D5\u05EA\u05E8 \u05DE-${u.minimum} ${d?.unit??""}`;return`\u05E7\u05D8\u05DF \u05DE\u05D3\u05D9: ${m} ${S} \u05DC\u05D4\u05DB\u05D9\u05DC ${G}`.trim()}let h=u.inclusive?">=":">",v=o(u.origin??"value");return d?.unit?`${d.shortLabel} \u05DE\u05D3\u05D9: ${m} ${v} ${h}${u.minimum.toString()} ${d.unit}`:`${d?.shortLabel??"\u05E7\u05D8\u05DF"} \u05DE\u05D3\u05D9: ${m} ${v} ${h}${u.minimum.toString()}`}case"invalid_format":{let d=u;if(d.format==="starts_with")return`\u05D4\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05EA\u05D7\u05D9\u05DC \u05D1 "${d.prefix}"`;if(d.format==="ends_with")return`\u05D4\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05E1\u05EA\u05D9\u05D9\u05DD \u05D1 "${d.suffix}"`;if(d.format==="includes")return`\u05D4\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05DB\u05DC\u05D5\u05DC "${d.includes}"`;if(d.format==="regex")return`\u05D4\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05EA\u05D0\u05D9\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA ${d.pattern}`;let m=s[d.format],h=m?.label??d.format,S=(m?.gender??"m")==="f"?"\u05EA\u05E7\u05D9\u05E0\u05D4":"\u05EA\u05E7\u05D9\u05DF";return`${h} \u05DC\u05D0 ${S}`}case"not_multiple_of":return`\u05DE\u05E1\u05E4\u05E8 \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05DB\u05E4\u05DC\u05D4 \u05E9\u05DC ${u.divisor}`;case"unrecognized_keys":return`\u05DE\u05E4\u05EA\u05D7${u.keys.length>1?"\u05D5\u05EA":""} \u05DC\u05D0 \u05DE\u05D6\u05D5\u05D4${u.keys.length>1?"\u05D9\u05DD":"\u05D4"}: ${f(u.keys,", ")}`;case"invalid_key":return"\u05E9\u05D3\u05D4 \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF \u05D1\u05D0\u05D5\u05D1\u05D9\u05D9\u05E7\u05D8";case"invalid_union":return"\u05E7\u05DC\u05D8 \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF";case"invalid_element":return`\u05E2\u05E8\u05DA \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF \u05D1${e(u.origin??"array")}`;default:return"\u05E7\u05DC\u05D8 \u05DC\u05D0 \u05EA\u05E7\u05D9\u05DF"}}}});function rm(){return{localeError:Ih()}}var Ih,nm=x(()=>{w();Ih=()=>{let t={string:{unit:"znakova",verb:"imati"},file:{unit:"bajtova",verb:"imati"},array:{unit:"stavki",verb:"imati"},set:{unit:"stavki",verb:"imati"}};function r(e){return t[e]??null}let n={regex:"unos",email:"email adresa",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datum i vrijeme",date:"ISO datum",time:"ISO vrijeme",duration:"ISO trajanje",ipv4:"IPv4 adresa",ipv6:"IPv6 adresa",cidrv4:"IPv4 raspon",cidrv6:"IPv6 raspon",base64:"base64 kodirani tekst",base64url:"base64url kodirani tekst",json_string:"JSON tekst",e164:"E.164 broj",jwt:"JWT",template_literal:"unos"},i={nan:"NaN",string:"tekst",number:"broj",boolean:"boolean",array:"niz",object:"objekt",set:"skup",file:"datoteka",date:"datum",bigint:"bigint",symbol:"simbol",undefined:"undefined",null:"null",function:"funkcija",map:"mapa"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Neispravan unos: o\u010Dekuje se instanceof ${e.expected}, a primljeno je ${s}`:`Neispravan unos: o\u010Dekuje se ${o}, a primljeno je ${s}`}case"invalid_value":return e.values.length===1?`Neispravna vrijednost: o\u010Dekivano ${y(e.values[0])}`:`Neispravna opcija: o\u010Dekivano jedno od ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin),s=i[e.origin]??e.origin;return a?`Preveliko: o\u010Dekivano da ${s??"vrijednost"} ima ${o}${e.maximum.toString()} ${a.unit??"elemenata"}`:`Preveliko: o\u010Dekivano da ${s??"vrijednost"} bude ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin),s=i[e.origin]??e.origin;return a?`Premalo: o\u010Dekivano da ${s} ima ${o}${e.minimum.toString()} ${a.unit}`:`Premalo: o\u010Dekivano da ${s} bude ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Neispravan tekst: mora zapo\u010Dinjati s "${o.prefix}"`:o.format==="ends_with"?`Neispravan tekst: mora zavr\u0161avati s "${o.suffix}"`:o.format==="includes"?`Neispravan tekst: mora sadr\u017Eavati "${o.includes}"`:o.format==="regex"?`Neispravan tekst: mora odgovarati uzorku ${o.pattern}`:`Neispravna ${n[o.format]??e.format}`}case"not_multiple_of":return`Neispravan broj: mora biti vi\u0161ekratnik od ${e.divisor}`;case"unrecognized_keys":return`Neprepoznat${e.keys.length>1?"i klju\u010Devi":" klju\u010D"}: ${f(e.keys,", ")}`;case"invalid_key":return`Neispravan klju\u010D u ${i[e.origin]??e.origin}`;case"invalid_union":return"Neispravan unos";case"invalid_element":return`Neispravna vrijednost u ${i[e.origin]??e.origin}`;default:return"Neispravan unos"}}}});function om(){return{localeError:Ph()}}var Ph,im=x(()=>{w();Ph=()=>{let t={string:{unit:"karakter",verb:"legyen"},file:{unit:"byte",verb:"legyen"},array:{unit:"elem",verb:"legyen"},set:{unit:"elem",verb:"legyen"}};function r(e){return t[e]??null}let n={regex:"bemenet",email:"email c\xEDm",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO id\u0151b\xE9lyeg",date:"ISO d\xE1tum",time:"ISO id\u0151",duration:"ISO id\u0151intervallum",ipv4:"IPv4 c\xEDm",ipv6:"IPv6 c\xEDm",cidrv4:"IPv4 tartom\xE1ny",cidrv6:"IPv6 tartom\xE1ny",base64:"base64-k\xF3dolt string",base64url:"base64url-k\xF3dolt string",json_string:"JSON string",e164:"E.164 sz\xE1m",jwt:"JWT",template_literal:"bemenet"},i={nan:"NaN",number:"sz\xE1m",array:"t\xF6mb"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\xC9rv\xE9nytelen bemenet: a v\xE1rt \xE9rt\xE9k instanceof ${e.expected}, a kapott \xE9rt\xE9k ${s}`:`\xC9rv\xE9nytelen bemenet: a v\xE1rt \xE9rt\xE9k ${o}, a kapott \xE9rt\xE9k ${s}`}case"invalid_value":return e.values.length===1?`\xC9rv\xE9nytelen bemenet: a v\xE1rt \xE9rt\xE9k ${y(e.values[0])}`:`\xC9rv\xE9nytelen opci\xF3: valamelyik \xE9rt\xE9k v\xE1rt ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`T\xFAl nagy: ${e.origin??"\xE9rt\xE9k"} m\xE9rete t\xFAl nagy ${o}${e.maximum.toString()} ${a.unit??"elem"}`:`T\xFAl nagy: a bemeneti \xE9rt\xE9k ${e.origin??"\xE9rt\xE9k"} t\xFAl nagy: ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`T\xFAl kicsi: a bemeneti \xE9rt\xE9k ${e.origin} m\xE9rete t\xFAl kicsi ${o}${e.minimum.toString()} ${a.unit}`:`T\xFAl kicsi: a bemeneti \xE9rt\xE9k ${e.origin} t\xFAl kicsi ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\xC9rv\xE9nytelen string: "${o.prefix}" \xE9rt\xE9kkel kell kezd\u0151dnie`:o.format==="ends_with"?`\xC9rv\xE9nytelen string: "${o.suffix}" \xE9rt\xE9kkel kell v\xE9gz\u0151dnie`:o.format==="includes"?`\xC9rv\xE9nytelen string: "${o.includes}" \xE9rt\xE9ket kell tartalmaznia`:o.format==="regex"?`\xC9rv\xE9nytelen string: ${o.pattern} mint\xE1nak kell megfelelnie`:`\xC9rv\xE9nytelen ${n[o.format]??e.format}`}case"not_multiple_of":return`\xC9rv\xE9nytelen sz\xE1m: ${e.divisor} t\xF6bbsz\xF6r\xF6s\xE9nek kell lennie`;case"unrecognized_keys":return`Ismeretlen kulcs${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`\xC9rv\xE9nytelen kulcs ${e.origin}`;case"invalid_union":return"\xC9rv\xE9nytelen bemenet";case"invalid_element":return`\xC9rv\xE9nytelen \xE9rt\xE9k: ${e.origin}`;default:return"\xC9rv\xE9nytelen bemenet"}}}});function am(t,r,n){return Math.abs(t)===1?r:n}function Dt(t){if(!t)return"";let r=["\u0561","\u0565","\u0568","\u056B","\u0578","\u0578\u0582","\u0585"],n=t[t.length-1];return t+(r.includes(n)?"\u0576":"\u0568")}function sm(){return{localeError:jh()}}var jh,cm=x(()=>{w();jh=()=>{let t={string:{unit:{one:"\u0576\u0577\u0561\u0576",many:"\u0576\u0577\u0561\u0576\u0576\u0565\u0580"},verb:"\u0578\u0582\u0576\u0565\u0576\u0561\u056C"},file:{unit:{one:"\u0562\u0561\u0575\u0569",many:"\u0562\u0561\u0575\u0569\u0565\u0580"},verb:"\u0578\u0582\u0576\u0565\u0576\u0561\u056C"},array:{unit:{one:"\u057F\u0561\u0580\u0580",many:"\u057F\u0561\u0580\u0580\u0565\u0580"},verb:"\u0578\u0582\u0576\u0565\u0576\u0561\u056C"},set:{unit:{one:"\u057F\u0561\u0580\u0580",many:"\u057F\u0561\u0580\u0580\u0565\u0580"},verb:"\u0578\u0582\u0576\u0565\u0576\u0561\u056C"}};function r(e){return t[e]??null}let n={regex:"\u0574\u0578\u0582\u057F\u0584",email:"\u0567\u056C. \u0570\u0561\u057D\u0581\u0565",url:"URL",emoji:"\u0567\u0574\u0578\u057B\u056B",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u0561\u0574\u057D\u0561\u0569\u056B\u057E \u0587 \u056A\u0561\u0574",date:"ISO \u0561\u0574\u057D\u0561\u0569\u056B\u057E",time:"ISO \u056A\u0561\u0574",duration:"ISO \u057F\u0587\u0578\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576",ipv4:"IPv4 \u0570\u0561\u057D\u0581\u0565",ipv6:"IPv6 \u0570\u0561\u057D\u0581\u0565",cidrv4:"IPv4 \u0574\u056B\u057B\u0561\u056F\u0561\u0575\u0584",cidrv6:"IPv6 \u0574\u056B\u057B\u0561\u056F\u0561\u0575\u0584",base64:"base64 \u0571\u0587\u0561\u0579\u0561\u0583\u0578\u057E \u057F\u0578\u0572",base64url:"base64url \u0571\u0587\u0561\u0579\u0561\u0583\u0578\u057E \u057F\u0578\u0572",json_string:"JSON \u057F\u0578\u0572",e164:"E.164 \u0570\u0561\u0574\u0561\u0580",jwt:"JWT",template_literal:"\u0574\u0578\u0582\u057F\u0584"},i={nan:"NaN",number:"\u0569\u056B\u057E",array:"\u0566\u0561\u0576\u0563\u057E\u0561\u056E"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u054D\u056D\u0561\u056C \u0574\u0578\u0582\u057F\u0584\u0561\u0563\u0580\u0578\u0582\u0574\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567\u0580 instanceof ${e.expected}, \u057D\u057F\u0561\u0581\u057E\u0565\u056C \u0567 ${s}`:`\u054D\u056D\u0561\u056C \u0574\u0578\u0582\u057F\u0584\u0561\u0563\u0580\u0578\u0582\u0574\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567\u0580 ${o}, \u057D\u057F\u0561\u0581\u057E\u0565\u056C \u0567 ${s}`}case"invalid_value":return e.values.length===1?`\u054D\u056D\u0561\u056C \u0574\u0578\u0582\u057F\u0584\u0561\u0563\u0580\u0578\u0582\u0574\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567\u0580 ${y(e.values[1])}`:`\u054D\u056D\u0561\u056C \u057F\u0561\u0580\u0562\u0565\u0580\u0561\u056F\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567\u0580 \u0570\u0565\u057F\u0587\u0575\u0561\u056C\u0576\u0565\u0580\u056B\u0581 \u0574\u0565\u056F\u0568\u055D ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);if(a){let s=Number(e.maximum),c=am(s,a.unit.one,a.unit.many);return`\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0574\u0565\u056E \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${Dt(e.origin??"\u0561\u0580\u056A\u0565\u0584")} \u056F\u0578\u0582\u0576\u0565\u0576\u0561 ${o}${e.maximum.toString()} ${c}`}return`\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0574\u0565\u056E \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${Dt(e.origin??"\u0561\u0580\u056A\u0565\u0584")} \u056C\u056B\u0576\u056B ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);if(a){let s=Number(e.minimum),c=am(s,a.unit.one,a.unit.many);return`\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0583\u0578\u0584\u0580 \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${Dt(e.origin)} \u056F\u0578\u0582\u0576\u0565\u0576\u0561 ${o}${e.minimum.toString()} ${c}`}return`\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0583\u0578\u0584\u0580 \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${Dt(e.origin)} \u056C\u056B\u0576\u056B ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u054D\u056D\u0561\u056C \u057F\u0578\u0572\u2024 \u057A\u0565\u057F\u0584 \u0567 \u057D\u056F\u057D\u057E\u056B "${o.prefix}"-\u0578\u057E`:o.format==="ends_with"?`\u054D\u056D\u0561\u056C \u057F\u0578\u0572\u2024 \u057A\u0565\u057F\u0584 \u0567 \u0561\u057E\u0561\u0580\u057F\u057E\u056B "${o.suffix}"-\u0578\u057E`:o.format==="includes"?`\u054D\u056D\u0561\u056C \u057F\u0578\u0572\u2024 \u057A\u0565\u057F\u0584 \u0567 \u057A\u0561\u0580\u0578\u0582\u0576\u0561\u056F\u056B "${o.includes}"`:o.format==="regex"?`\u054D\u056D\u0561\u056C \u057F\u0578\u0572\u2024 \u057A\u0565\u057F\u0584 \u0567 \u0570\u0561\u0574\u0561\u057A\u0561\u057F\u0561\u057D\u056D\u0561\u0576\u056B ${o.pattern} \u0571\u0587\u0561\u0579\u0561\u0583\u056B\u0576`:`\u054D\u056D\u0561\u056C ${n[o.format]??e.format}`}case"not_multiple_of":return`\u054D\u056D\u0561\u056C \u0569\u056B\u057E\u2024 \u057A\u0565\u057F\u0584 \u0567 \u0562\u0561\u0566\u0574\u0561\u057A\u0561\u057F\u056B\u056F \u056C\u056B\u0576\u056B ${e.divisor}-\u056B`;case"unrecognized_keys":return`\u0549\u0573\u0561\u0576\u0561\u0579\u057E\u0561\u056E \u0562\u0561\u0576\u0561\u056C\u056B${e.keys.length>1?"\u0576\u0565\u0580":""}. ${f(e.keys,", ")}`;case"invalid_key":return`\u054D\u056D\u0561\u056C \u0562\u0561\u0576\u0561\u056C\u056B ${Dt(e.origin)}-\u0578\u0582\u0574`;case"invalid_union":return"\u054D\u056D\u0561\u056C \u0574\u0578\u0582\u057F\u0584\u0561\u0563\u0580\u0578\u0582\u0574";case"invalid_element":return`\u054D\u056D\u0561\u056C \u0561\u0580\u056A\u0565\u0584 ${Dt(e.origin)}-\u0578\u0582\u0574`;default:return"\u054D\u056D\u0561\u056C \u0574\u0578\u0582\u057F\u0584\u0561\u0563\u0580\u0578\u0582\u0574"}}}});function um(){return{localeError:Th()}}var Th,lm=x(()=>{w();Th=()=>{let t={string:{unit:"karakter",verb:"memiliki"},file:{unit:"byte",verb:"memiliki"},array:{unit:"item",verb:"memiliki"},set:{unit:"item",verb:"memiliki"}};function r(e){return t[e]??null}let n={regex:"input",email:"alamat email",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"tanggal dan waktu format ISO",date:"tanggal format ISO",time:"jam format ISO",duration:"durasi format ISO",ipv4:"alamat IPv4",ipv6:"alamat IPv6",cidrv4:"rentang alamat IPv4",cidrv6:"rentang alamat IPv6",base64:"string dengan enkode base64",base64url:"string dengan enkode base64url",json_string:"string JSON",e164:"angka E.164",jwt:"JWT",template_literal:"input"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Input tidak valid: diharapkan instanceof ${e.expected}, diterima ${s}`:`Input tidak valid: diharapkan ${o}, diterima ${s}`}case"invalid_value":return e.values.length===1?`Input tidak valid: diharapkan ${y(e.values[0])}`:`Pilihan tidak valid: diharapkan salah satu dari ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Terlalu besar: diharapkan ${e.origin??"value"} memiliki ${o}${e.maximum.toString()} ${a.unit??"elemen"}`:`Terlalu besar: diharapkan ${e.origin??"value"} menjadi ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Terlalu kecil: diharapkan ${e.origin} memiliki ${o}${e.minimum.toString()} ${a.unit}`:`Terlalu kecil: diharapkan ${e.origin} menjadi ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`String tidak valid: harus dimulai dengan "${o.prefix}"`:o.format==="ends_with"?`String tidak valid: harus berakhir dengan "${o.suffix}"`:o.format==="includes"?`String tidak valid: harus menyertakan "${o.includes}"`:o.format==="regex"?`String tidak valid: harus sesuai pola ${o.pattern}`:`${n[o.format]??e.format} tidak valid`}case"not_multiple_of":return`Angka tidak valid: harus kelipatan dari ${e.divisor}`;case"unrecognized_keys":return`Kunci tidak dikenali ${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Kunci tidak valid di ${e.origin}`;case"invalid_union":return"Input tidak valid";case"invalid_element":return`Nilai tidak valid di ${e.origin}`;default:return"Input tidak valid"}}}});function dm(){return{localeError:Oh()}}var Oh,pm=x(()=>{w();Oh=()=>{let t={string:{unit:"stafi",verb:"a\xF0 hafa"},file:{unit:"b\xE6ti",verb:"a\xF0 hafa"},array:{unit:"hluti",verb:"a\xF0 hafa"},set:{unit:"hluti",verb:"a\xF0 hafa"}};function r(e){return t[e]??null}let n={regex:"gildi",email:"netfang",url:"vefsl\xF3\xF0",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO dagsetning og t\xEDmi",date:"ISO dagsetning",time:"ISO t\xEDmi",duration:"ISO t\xEDmalengd",ipv4:"IPv4 address",ipv6:"IPv6 address",cidrv4:"IPv4 range",cidrv6:"IPv6 range",base64:"base64-encoded strengur",base64url:"base64url-encoded strengur",json_string:"JSON strengur",e164:"E.164 t\xF6lugildi",jwt:"JWT",template_literal:"gildi"},i={nan:"NaN",number:"n\xFAmer",array:"fylki"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Rangt gildi: \xDE\xFA sl\xF3st inn ${s} \xFEar sem \xE1 a\xF0 vera instanceof ${e.expected}`:`Rangt gildi: \xDE\xFA sl\xF3st inn ${s} \xFEar sem \xE1 a\xF0 vera ${o}`}case"invalid_value":return e.values.length===1?`Rangt gildi: gert r\xE1\xF0 fyrir ${y(e.values[0])}`:`\xD3gilt val: m\xE1 vera eitt af eftirfarandi ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Of st\xF3rt: gert er r\xE1\xF0 fyrir a\xF0 ${e.origin??"gildi"} hafi ${o}${e.maximum.toString()} ${a.unit??"hluti"}`:`Of st\xF3rt: gert er r\xE1\xF0 fyrir a\xF0 ${e.origin??"gildi"} s\xE9 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Of l\xEDti\xF0: gert er r\xE1\xF0 fyrir a\xF0 ${e.origin} hafi ${o}${e.minimum.toString()} ${a.unit}`:`Of l\xEDti\xF0: gert er r\xE1\xF0 fyrir a\xF0 ${e.origin} s\xE9 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\xD3gildur strengur: ver\xF0ur a\xF0 byrja \xE1 "${o.prefix}"`:o.format==="ends_with"?`\xD3gildur strengur: ver\xF0ur a\xF0 enda \xE1 "${o.suffix}"`:o.format==="includes"?`\xD3gildur strengur: ver\xF0ur a\xF0 innihalda "${o.includes}"`:o.format==="regex"?`\xD3gildur strengur: ver\xF0ur a\xF0 fylgja mynstri ${o.pattern}`:`Rangt ${n[o.format]??e.format}`}case"not_multiple_of":return`R\xF6ng tala: ver\xF0ur a\xF0 vera margfeldi af ${e.divisor}`;case"unrecognized_keys":return`\xD3\xFEekkt ${e.keys.length>1?"ir lyklar":"ur lykill"}: ${f(e.keys,", ")}`;case"invalid_key":return`Rangur lykill \xED ${e.origin}`;case"invalid_union":return"Rangt gildi";case"invalid_element":return`Rangt gildi \xED ${e.origin}`;default:return"Rangt gildi"}}}});function mm(){return{localeError:Dh()}}var Dh,fm=x(()=>{w();Dh=()=>{let t={string:{unit:"caratteri",verb:"avere"},file:{unit:"byte",verb:"avere"},array:{unit:"elementi",verb:"avere"},set:{unit:"elementi",verb:"avere"}};function r(e){return t[e]??null}let n={regex:"input",email:"indirizzo email",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"data e ora ISO",date:"data ISO",time:"ora ISO",duration:"durata ISO",ipv4:"indirizzo IPv4",ipv6:"indirizzo IPv6",cidrv4:"intervallo IPv4",cidrv6:"intervallo IPv6",base64:"stringa codificata in base64",base64url:"URL codificata in base64",json_string:"stringa JSON",e164:"numero E.164",jwt:"JWT",template_literal:"input"},i={nan:"NaN",number:"numero",array:"vettore"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Input non valido: atteso instanceof ${e.expected}, ricevuto ${s}`:`Input non valido: atteso ${o}, ricevuto ${s}`}case"invalid_value":return e.values.length===1?`Input non valido: atteso ${y(e.values[0])}`:`Opzione non valida: atteso uno tra ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Troppo grande: ${e.origin??"valore"} deve avere ${o}${e.maximum.toString()} ${a.unit??"elementi"}`:`Troppo grande: ${e.origin??"valore"} deve essere ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Troppo piccolo: ${e.origin} deve avere ${o}${e.minimum.toString()} ${a.unit}`:`Troppo piccolo: ${e.origin} deve essere ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Stringa non valida: deve iniziare con "${o.prefix}"`:o.format==="ends_with"?`Stringa non valida: deve terminare con "${o.suffix}"`:o.format==="includes"?`Stringa non valida: deve includere "${o.includes}"`:o.format==="regex"?`Stringa non valida: deve corrispondere al pattern ${o.pattern}`:`Input non valido: ${n[o.format]??e.format}`}case"not_multiple_of":return`Numero non valido: deve essere un multiplo di ${e.divisor}`;case"unrecognized_keys":return`Chiav${e.keys.length>1?"i":"e"} non riconosciut${e.keys.length>1?"e":"a"}: ${f(e.keys,", ")}`;case"invalid_key":return`Chiave non valida in ${e.origin}`;case"invalid_union":return"Input non valido";case"invalid_element":return`Valore non valido in ${e.origin}`;default:return"Input non valido"}}}});function gm(){return{localeError:Uh()}}var Uh,hm=x(()=>{w();Uh=()=>{let t={string:{unit:"\u6587\u5B57",verb:"\u3067\u3042\u308B"},file:{unit:"\u30D0\u30A4\u30C8",verb:"\u3067\u3042\u308B"},array:{unit:"\u8981\u7D20",verb:"\u3067\u3042\u308B"},set:{unit:"\u8981\u7D20",verb:"\u3067\u3042\u308B"}};function r(e){return t[e]??null}let n={regex:"\u5165\u529B\u5024",email:"\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9",url:"URL",emoji:"\u7D75\u6587\u5B57",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO\u65E5\u6642",date:"ISO\u65E5\u4ED8",time:"ISO\u6642\u523B",duration:"ISO\u671F\u9593",ipv4:"IPv4\u30A2\u30C9\u30EC\u30B9",ipv6:"IPv6\u30A2\u30C9\u30EC\u30B9",cidrv4:"IPv4\u7BC4\u56F2",cidrv6:"IPv6\u7BC4\u56F2",base64:"base64\u30A8\u30F3\u30B3\u30FC\u30C9\u6587\u5B57\u5217",base64url:"base64url\u30A8\u30F3\u30B3\u30FC\u30C9\u6587\u5B57\u5217",json_string:"JSON\u6587\u5B57\u5217",e164:"E.164\u756A\u53F7",jwt:"JWT",template_literal:"\u5165\u529B\u5024"},i={nan:"NaN",number:"\u6570\u5024",array:"\u914D\u5217"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u7121\u52B9\u306A\u5165\u529B: instanceof ${e.expected}\u304C\u671F\u5F85\u3055\u308C\u307E\u3057\u305F\u304C\u3001${s}\u304C\u5165\u529B\u3055\u308C\u307E\u3057\u305F`:`\u7121\u52B9\u306A\u5165\u529B: ${o}\u304C\u671F\u5F85\u3055\u308C\u307E\u3057\u305F\u304C\u3001${s}\u304C\u5165\u529B\u3055\u308C\u307E\u3057\u305F`}case"invalid_value":return e.values.length===1?`\u7121\u52B9\u306A\u5165\u529B: ${y(e.values[0])}\u304C\u671F\u5F85\u3055\u308C\u307E\u3057\u305F`:`\u7121\u52B9\u306A\u9078\u629E: ${f(e.values,"\u3001")}\u306E\u3044\u305A\u308C\u304B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`;case"too_big":{let o=e.inclusive?"\u4EE5\u4E0B\u3067\u3042\u308B":"\u3088\u308A\u5C0F\u3055\u3044",a=r(e.origin);return a?`\u5927\u304D\u3059\u304E\u308B\u5024: ${e.origin??"\u5024"}\u306F${e.maximum.toString()}${a.unit??"\u8981\u7D20"}${o}\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`:`\u5927\u304D\u3059\u304E\u308B\u5024: ${e.origin??"\u5024"}\u306F${e.maximum.toString()}${o}\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`}case"too_small":{let o=e.inclusive?"\u4EE5\u4E0A\u3067\u3042\u308B":"\u3088\u308A\u5927\u304D\u3044",a=r(e.origin);return a?`\u5C0F\u3055\u3059\u304E\u308B\u5024: ${e.origin}\u306F${e.minimum.toString()}${a.unit}${o}\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`:`\u5C0F\u3055\u3059\u304E\u308B\u5024: ${e.origin}\u306F${e.minimum.toString()}${o}\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u7121\u52B9\u306A\u6587\u5B57\u5217: "${o.prefix}"\u3067\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`:o.format==="ends_with"?`\u7121\u52B9\u306A\u6587\u5B57\u5217: "${o.suffix}"\u3067\u7D42\u308F\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`:o.format==="includes"?`\u7121\u52B9\u306A\u6587\u5B57\u5217: "${o.includes}"\u3092\u542B\u3080\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`:o.format==="regex"?`\u7121\u52B9\u306A\u6587\u5B57\u5217: \u30D1\u30BF\u30FC\u30F3${o.pattern}\u306B\u4E00\u81F4\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`:`\u7121\u52B9\u306A${n[o.format]??e.format}`}case"not_multiple_of":return`\u7121\u52B9\u306A\u6570\u5024: ${e.divisor}\u306E\u500D\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`;case"unrecognized_keys":return`\u8A8D\u8B58\u3055\u308C\u3066\u3044\u306A\u3044\u30AD\u30FC${e.keys.length>1?"\u7FA4":""}: ${f(e.keys,"\u3001")}`;case"invalid_key":return`${e.origin}\u5185\u306E\u7121\u52B9\u306A\u30AD\u30FC`;case"invalid_union":return"\u7121\u52B9\u306A\u5165\u529B";case"invalid_element":return`${e.origin}\u5185\u306E\u7121\u52B9\u306A\u5024`;default:return"\u7121\u52B9\u306A\u5165\u529B"}}}});function vm(){return{localeError:Nh()}}var Nh,ym=x(()=>{w();Nh=()=>{let t={string:{unit:"\u10E1\u10D8\u10DB\u10D1\u10DD\u10DA\u10DD",verb:"\u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D8\u10EA\u10D0\u10D5\u10D3\u10D4\u10E1"},file:{unit:"\u10D1\u10D0\u10D8\u10E2\u10D8",verb:"\u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D8\u10EA\u10D0\u10D5\u10D3\u10D4\u10E1"},array:{unit:"\u10D4\u10DA\u10D4\u10DB\u10D4\u10DC\u10E2\u10D8",verb:"\u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D8\u10EA\u10D0\u10D5\u10D3\u10D4\u10E1"},set:{unit:"\u10D4\u10DA\u10D4\u10DB\u10D4\u10DC\u10E2\u10D8",verb:"\u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D8\u10EA\u10D0\u10D5\u10D3\u10D4\u10E1"}};function r(e){return t[e]??null}let n={regex:"\u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0",email:"\u10D4\u10DA-\u10E4\u10DD\u10E1\u10E2\u10D8\u10E1 \u10DB\u10D8\u10E1\u10D0\u10DB\u10D0\u10E0\u10D7\u10D8",url:"URL",emoji:"\u10D4\u10DB\u10DD\u10EF\u10D8",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u10D7\u10D0\u10E0\u10D8\u10E6\u10D8-\u10D3\u10E0\u10DD",date:"\u10D7\u10D0\u10E0\u10D8\u10E6\u10D8",time:"\u10D3\u10E0\u10DD",duration:"\u10EE\u10D0\u10DC\u10D2\u10E0\u10EB\u10DA\u10D8\u10D5\u10DD\u10D1\u10D0",ipv4:"IPv4 \u10DB\u10D8\u10E1\u10D0\u10DB\u10D0\u10E0\u10D7\u10D8",ipv6:"IPv6 \u10DB\u10D8\u10E1\u10D0\u10DB\u10D0\u10E0\u10D7\u10D8",cidrv4:"IPv4 \u10D3\u10D8\u10D0\u10DE\u10D0\u10D6\u10DD\u10DC\u10D8",cidrv6:"IPv6 \u10D3\u10D8\u10D0\u10DE\u10D0\u10D6\u10DD\u10DC\u10D8",base64:"base64-\u10D9\u10DD\u10D3\u10D8\u10E0\u10D4\u10D1\u10E3\u10DA\u10D8 \u10D5\u10D4\u10DA\u10D8",base64url:"base64url-\u10D9\u10DD\u10D3\u10D8\u10E0\u10D4\u10D1\u10E3\u10DA\u10D8 \u10D5\u10D4\u10DA\u10D8",json_string:"JSON \u10D5\u10D4\u10DA\u10D8",e164:"E.164 \u10DC\u10DD\u10DB\u10D4\u10E0\u10D8",jwt:"JWT",template_literal:"\u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0"},i={nan:"NaN",number:"\u10E0\u10D8\u10EA\u10EE\u10D5\u10D8",string:"\u10D5\u10D4\u10DA\u10D8",boolean:"\u10D1\u10E3\u10DA\u10D4\u10D0\u10DC\u10D8",function:"\u10E4\u10E3\u10DC\u10E5\u10EA\u10D8\u10D0",array:"\u10DB\u10D0\u10E1\u10D8\u10D5\u10D8"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 instanceof ${e.expected}, \u10DB\u10D8\u10E6\u10D4\u10D1\u10E3\u10DA\u10D8 ${s}`:`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 ${o}, \u10DB\u10D8\u10E6\u10D4\u10D1\u10E3\u10DA\u10D8 ${s}`}case"invalid_value":return e.values.length===1?`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 ${y(e.values[0])}`:`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10D5\u10D0\u10E0\u10D8\u10D0\u10DC\u10E2\u10D8: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8\u10D0 \u10D4\u10E0\u10D7-\u10D4\u10E0\u10D7\u10D8 ${f(e.values,"|")}-\u10D3\u10D0\u10DC`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u10D6\u10D4\u10D3\u10DB\u10D4\u10E2\u10D0\u10D3 \u10D3\u10D8\u10D3\u10D8: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 ${e.origin??"\u10DB\u10DC\u10D8\u10E8\u10D5\u10DC\u10D4\u10DA\u10DD\u10D1\u10D0"} ${a.verb} ${o}${e.maximum.toString()} ${a.unit}`:`\u10D6\u10D4\u10D3\u10DB\u10D4\u10E2\u10D0\u10D3 \u10D3\u10D8\u10D3\u10D8: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 ${e.origin??"\u10DB\u10DC\u10D8\u10E8\u10D5\u10DC\u10D4\u10DA\u10DD\u10D1\u10D0"} \u10D8\u10E7\u10DD\u10E1 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u10D6\u10D4\u10D3\u10DB\u10D4\u10E2\u10D0\u10D3 \u10DE\u10D0\u10E2\u10D0\u10E0\u10D0: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 ${e.origin} ${a.verb} ${o}${e.minimum.toString()} ${a.unit}`:`\u10D6\u10D4\u10D3\u10DB\u10D4\u10E2\u10D0\u10D3 \u10DE\u10D0\u10E2\u10D0\u10E0\u10D0: \u10DB\u10DD\u10E1\u10D0\u10DA\u10DD\u10D3\u10DC\u10D4\u10DA\u10D8 ${e.origin} \u10D8\u10E7\u10DD\u10E1 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10D5\u10D4\u10DA\u10D8: \u10E3\u10DC\u10D3\u10D0 \u10D8\u10EC\u10E7\u10D4\u10D1\u10DD\u10D3\u10D4\u10E1 "${o.prefix}"-\u10D8\u10D7`:o.format==="ends_with"?`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10D5\u10D4\u10DA\u10D8: \u10E3\u10DC\u10D3\u10D0 \u10DB\u10D7\u10D0\u10D5\u10E0\u10D3\u10D4\u10D1\u10DD\u10D3\u10D4\u10E1 "${o.suffix}"-\u10D8\u10D7`:o.format==="includes"?`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10D5\u10D4\u10DA\u10D8: \u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D8\u10EA\u10D0\u10D5\u10D3\u10D4\u10E1 "${o.includes}"-\u10E1`:o.format==="regex"?`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10D5\u10D4\u10DA\u10D8: \u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D4\u10E1\u10D0\u10D1\u10D0\u10DB\u10D4\u10D1\u10DD\u10D3\u10D4\u10E1 \u10E8\u10D0\u10D1\u10DA\u10DD\u10DC\u10E1 ${o.pattern}`:`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10E0\u10D8\u10EA\u10EE\u10D5\u10D8: \u10E3\u10DC\u10D3\u10D0 \u10D8\u10E7\u10DD\u10E1 ${e.divisor}-\u10D8\u10E1 \u10EF\u10D4\u10E0\u10D0\u10D3\u10D8`;case"unrecognized_keys":return`\u10E3\u10EA\u10DC\u10DD\u10D1\u10D8 \u10D2\u10D0\u10E1\u10D0\u10E6\u10D4\u10D1${e.keys.length>1?"\u10D4\u10D1\u10D8":"\u10D8"}: ${f(e.keys,", ")}`;case"invalid_key":return`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10D2\u10D0\u10E1\u10D0\u10E6\u10D4\u10D1\u10D8 ${e.origin}-\u10E8\u10D8`;case"invalid_union":return"\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0";case"invalid_element":return`\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10DB\u10DC\u10D8\u10E8\u10D5\u10DC\u10D4\u10DA\u10DD\u10D1\u10D0 ${e.origin}-\u10E8\u10D8`;default:return"\u10D0\u10E0\u10D0\u10E1\u10EC\u10DD\u10E0\u10D8 \u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0"}}}});function Xn(){return{localeError:Eh()}}var Eh,_c=x(()=>{w();Eh=()=>{let t={string:{unit:"\u178F\u17BD\u17A2\u1780\u17D2\u179F\u179A",verb:"\u1782\u17BD\u179A\u1798\u17B6\u1793"},file:{unit:"\u1794\u17C3",verb:"\u1782\u17BD\u179A\u1798\u17B6\u1793"},array:{unit:"\u1792\u17B6\u178F\u17BB",verb:"\u1782\u17BD\u179A\u1798\u17B6\u1793"},set:{unit:"\u1792\u17B6\u178F\u17BB",verb:"\u1782\u17BD\u179A\u1798\u17B6\u1793"}};function r(e){return t[e]??null}let n={regex:"\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1794\u1789\u17D2\u1785\u17BC\u179B",email:"\u17A2\u17B6\u179F\u1799\u178A\u17D2\u178B\u17B6\u1793\u17A2\u17CA\u17B8\u1798\u17C2\u179B",url:"URL",emoji:"\u179F\u1789\u17D2\u1789\u17B6\u17A2\u17B6\u179A\u1798\u17D2\u1798\u178E\u17CD",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u1780\u17B6\u179B\u1794\u179A\u17B7\u1785\u17D2\u1786\u17C1\u1791 \u1793\u17B7\u1784\u1798\u17C9\u17C4\u1784 ISO",date:"\u1780\u17B6\u179B\u1794\u179A\u17B7\u1785\u17D2\u1786\u17C1\u1791 ISO",time:"\u1798\u17C9\u17C4\u1784 ISO",duration:"\u179A\u1799\u17C8\u1796\u17C1\u179B ISO",ipv4:"\u17A2\u17B6\u179F\u1799\u178A\u17D2\u178B\u17B6\u1793 IPv4",ipv6:"\u17A2\u17B6\u179F\u1799\u178A\u17D2\u178B\u17B6\u1793 IPv6",cidrv4:"\u178A\u17C2\u1793\u17A2\u17B6\u179F\u1799\u178A\u17D2\u178B\u17B6\u1793 IPv4",cidrv6:"\u178A\u17C2\u1793\u17A2\u17B6\u179F\u1799\u178A\u17D2\u178B\u17B6\u1793 IPv6",base64:"\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A\u17A2\u17CA\u17B7\u1780\u17BC\u178A base64",base64url:"\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A\u17A2\u17CA\u17B7\u1780\u17BC\u178A base64url",json_string:"\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A JSON",e164:"\u179B\u17C1\u1781 E.164",jwt:"JWT",template_literal:"\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1794\u1789\u17D2\u1785\u17BC\u179B"},i={nan:"NaN",number:"\u179B\u17C1\u1781",array:"\u17A2\u17B6\u179A\u17C1 (Array)",null:"\u1782\u17D2\u1798\u17B6\u1793\u178F\u1798\u17D2\u179B\u17C3 (null)"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1794\u1789\u17D2\u1785\u17BC\u179B\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A instanceof ${e.expected} \u1794\u17C9\u17BB\u1793\u17D2\u178F\u17C2\u1791\u1791\u17BD\u179B\u1794\u17B6\u1793 ${s}`:`\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1794\u1789\u17D2\u1785\u17BC\u179B\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A ${o} \u1794\u17C9\u17BB\u1793\u17D2\u178F\u17C2\u1791\u1791\u17BD\u179B\u1794\u17B6\u1793 ${s}`}case"invalid_value":return e.values.length===1?`\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1794\u1789\u17D2\u1785\u17BC\u179B\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A ${y(e.values[0])}`:`\u1787\u1798\u17D2\u179A\u17BE\u179F\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1787\u17B6\u1798\u17BD\u1799\u1780\u17D2\u1793\u17BB\u1784\u1785\u17C6\u178E\u17C4\u1798 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u1792\u17C6\u1796\u17C1\u1780\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A ${e.origin??"\u178F\u1798\u17D2\u179B\u17C3"} ${o} ${e.maximum.toString()} ${a.unit??"\u1792\u17B6\u178F\u17BB"}`:`\u1792\u17C6\u1796\u17C1\u1780\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A ${e.origin??"\u178F\u1798\u17D2\u179B\u17C3"} ${o} ${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u178F\u17BC\u1785\u1796\u17C1\u1780\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A ${e.origin} ${o} ${e.minimum.toString()} ${a.unit}`:`\u178F\u17BC\u1785\u1796\u17C1\u1780\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1780\u17B6\u179A ${e.origin} ${o} ${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1785\u17B6\u1794\u17CB\u1795\u17D2\u178F\u17BE\u1798\u178A\u17C4\u1799 "${o.prefix}"`:o.format==="ends_with"?`\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1794\u1789\u17D2\u1785\u1794\u17CB\u178A\u17C4\u1799 "${o.suffix}"`:o.format==="includes"?`\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u1798\u17B6\u1793 "${o.includes}"`:o.format==="regex"?`\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u178F\u17C2\u1795\u17D2\u1782\u17BC\u1795\u17D2\u1782\u1784\u1793\u17B9\u1784\u1791\u1798\u17D2\u179A\u1784\u17CB\u178A\u17C2\u179B\u1794\u17B6\u1793\u1780\u17C6\u178E\u178F\u17CB ${o.pattern}`:`\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u179B\u17C1\u1781\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u17D6 \u178F\u17D2\u179A\u17BC\u179C\u178F\u17C2\u1787\u17B6\u1796\u17A0\u17BB\u1782\u17BB\u178E\u1793\u17C3 ${e.divisor}`;case"unrecognized_keys":return`\u179A\u1780\u1783\u17BE\u1789\u179F\u17C4\u1798\u17B7\u1793\u179F\u17D2\u1782\u17B6\u179B\u17CB\u17D6 ${f(e.keys,", ")}`;case"invalid_key":return`\u179F\u17C4\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u1793\u17C5\u1780\u17D2\u1793\u17BB\u1784 ${e.origin}`;case"invalid_union":return"\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C";case"invalid_element":return`\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C\u1793\u17C5\u1780\u17D2\u1793\u17BB\u1784 ${e.origin}`;default:return"\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1798\u17B7\u1793\u178F\u17D2\u179A\u17B9\u1798\u178F\u17D2\u179A\u17BC\u179C"}}}});function bm(){return Xn()}var _m=x(()=>{_c()});function $m(){return{localeError:Zh()}}var Zh,xm=x(()=>{w();Zh=()=>{let t={string:{unit:"\uBB38\uC790",verb:"to have"},file:{unit:"\uBC14\uC774\uD2B8",verb:"to have"},array:{unit:"\uAC1C",verb:"to have"},set:{unit:"\uAC1C",verb:"to have"}};function r(e){return t[e]??null}let n={regex:"\uC785\uB825",email:"\uC774\uBA54\uC77C \uC8FC\uC18C",url:"URL",emoji:"\uC774\uBAA8\uC9C0",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \uB0A0\uC9DC\uC2DC\uAC04",date:"ISO \uB0A0\uC9DC",time:"ISO \uC2DC\uAC04",duration:"ISO \uAE30\uAC04",ipv4:"IPv4 \uC8FC\uC18C",ipv6:"IPv6 \uC8FC\uC18C",cidrv4:"IPv4 \uBC94\uC704",cidrv6:"IPv6 \uBC94\uC704",base64:"base64 \uC778\uCF54\uB529 \uBB38\uC790\uC5F4",base64url:"base64url \uC778\uCF54\uB529 \uBB38\uC790\uC5F4",json_string:"JSON \uBB38\uC790\uC5F4",e164:"E.164 \uBC88\uD638",jwt:"JWT",template_literal:"\uC785\uB825"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\uC798\uBABB\uB41C \uC785\uB825: \uC608\uC0C1 \uD0C0\uC785\uC740 instanceof ${e.expected}, \uBC1B\uC740 \uD0C0\uC785\uC740 ${s}\uC785\uB2C8\uB2E4`:`\uC798\uBABB\uB41C \uC785\uB825: \uC608\uC0C1 \uD0C0\uC785\uC740 ${o}, \uBC1B\uC740 \uD0C0\uC785\uC740 ${s}\uC785\uB2C8\uB2E4`}case"invalid_value":return e.values.length===1?`\uC798\uBABB\uB41C \uC785\uB825: \uAC12\uC740 ${y(e.values[0])} \uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4`:`\uC798\uBABB\uB41C \uC635\uC158: ${f(e.values,"\uB610\uB294 ")} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4`;case"too_big":{let o=e.inclusive?"\uC774\uD558":"\uBBF8\uB9CC",a=o==="\uBBF8\uB9CC"?"\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4":"\uC5EC\uC57C \uD569\uB2C8\uB2E4",s=r(e.origin),c=s?.unit??"\uC694\uC18C";return s?`${e.origin??"\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${e.maximum.toString()}${c} ${o}${a}`:`${e.origin??"\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${e.maximum.toString()} ${o}${a}`}case"too_small":{let o=e.inclusive?"\uC774\uC0C1":"\uCD08\uACFC",a=o==="\uC774\uC0C1"?"\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4":"\uC5EC\uC57C \uD569\uB2C8\uB2E4",s=r(e.origin),c=s?.unit??"\uC694\uC18C";return s?`${e.origin??"\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${e.minimum.toString()}${c} ${o}${a}`:`${e.origin??"\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${e.minimum.toString()} ${o}${a}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\uC798\uBABB\uB41C \uBB38\uC790\uC5F4: "${o.prefix}"(\uC73C)\uB85C \uC2DC\uC791\uD574\uC57C \uD569\uB2C8\uB2E4`:o.format==="ends_with"?`\uC798\uBABB\uB41C \uBB38\uC790\uC5F4: "${o.suffix}"(\uC73C)\uB85C \uB05D\uB098\uC57C \uD569\uB2C8\uB2E4`:o.format==="includes"?`\uC798\uBABB\uB41C \uBB38\uC790\uC5F4: "${o.includes}"\uC744(\uB97C) \uD3EC\uD568\uD574\uC57C \uD569\uB2C8\uB2E4`:o.format==="regex"?`\uC798\uBABB\uB41C \uBB38\uC790\uC5F4: \uC815\uADDC\uC2DD ${o.pattern} \uD328\uD134\uACFC \uC77C\uCE58\uD574\uC57C \uD569\uB2C8\uB2E4`:`\uC798\uBABB\uB41C ${n[o.format]??e.format}`}case"not_multiple_of":return`\uC798\uBABB\uB41C \uC22B\uC790: ${e.divisor}\uC758 \uBC30\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4`;case"unrecognized_keys":return`\uC778\uC2DD\uD560 \uC218 \uC5C6\uB294 \uD0A4: ${f(e.keys,", ")}`;case"invalid_key":return`\uC798\uBABB\uB41C \uD0A4: ${e.origin}`;case"invalid_union":return"\uC798\uBABB\uB41C \uC785\uB825";case"invalid_element":return`\uC798\uBABB\uB41C \uAC12: ${e.origin}`;default:return"\uC798\uBABB\uB41C \uC785\uB825"}}}});function km(t){let r=Math.abs(t),n=r%10,i=r%100;return i>=11&&i<=19||n===0?"many":n===1?"one":"few"}function zm(){return{localeError:Rh()}}var vr,Rh,Sm=x(()=>{w();vr=t=>t.charAt(0).toUpperCase()+t.slice(1);Rh=()=>{let t={string:{unit:{one:"simbolis",few:"simboliai",many:"simboli\u0173"},verb:{smaller:{inclusive:"turi b\u016Bti ne ilgesn\u0117 kaip",notInclusive:"turi b\u016Bti trumpesn\u0117 kaip"},bigger:{inclusive:"turi b\u016Bti ne trumpesn\u0117 kaip",notInclusive:"turi b\u016Bti ilgesn\u0117 kaip"}}},file:{unit:{one:"baitas",few:"baitai",many:"bait\u0173"},verb:{smaller:{inclusive:"turi b\u016Bti ne didesnis kaip",notInclusive:"turi b\u016Bti ma\u017Eesnis kaip"},bigger:{inclusive:"turi b\u016Bti ne ma\u017Eesnis kaip",notInclusive:"turi b\u016Bti didesnis kaip"}}},array:{unit:{one:"element\u0105",few:"elementus",many:"element\u0173"},verb:{smaller:{inclusive:"turi tur\u0117ti ne daugiau kaip",notInclusive:"turi tur\u0117ti ma\u017Eiau kaip"},bigger:{inclusive:"turi tur\u0117ti ne ma\u017Eiau kaip",notInclusive:"turi tur\u0117ti daugiau kaip"}}},set:{unit:{one:"element\u0105",few:"elementus",many:"element\u0173"},verb:{smaller:{inclusive:"turi tur\u0117ti ne daugiau kaip",notInclusive:"turi tur\u0117ti ma\u017Eiau kaip"},bigger:{inclusive:"turi tur\u0117ti ne ma\u017Eiau kaip",notInclusive:"turi tur\u0117ti daugiau kaip"}}}};function r(e,o,a,s){let c=t[e]??null;return c===null?c:{unit:c.unit[o],verb:c.verb[s][a?"inclusive":"notInclusive"]}}let n={regex:"\u012Fvestis",email:"el. pa\u0161to adresas",url:"URL",emoji:"jaustukas",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO data ir laikas",date:"ISO data",time:"ISO laikas",duration:"ISO trukm\u0117",ipv4:"IPv4 adresas",ipv6:"IPv6 adresas",cidrv4:"IPv4 tinklo prefiksas (CIDR)",cidrv6:"IPv6 tinklo prefiksas (CIDR)",base64:"base64 u\u017Ekoduota eilut\u0117",base64url:"base64url u\u017Ekoduota eilut\u0117",json_string:"JSON eilut\u0117",e164:"E.164 numeris",jwt:"JWT",template_literal:"\u012Fvestis"},i={nan:"NaN",number:"skai\u010Dius",bigint:"sveikasis skai\u010Dius",string:"eilut\u0117",boolean:"login\u0117 reik\u0161m\u0117",undefined:"neapibr\u0117\u017Eta reik\u0161m\u0117",function:"funkcija",symbol:"simbolis",array:"masyvas",object:"objektas",null:"nulin\u0117 reik\u0161m\u0117"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Gautas tipas ${s}, o tik\u0117tasi - instanceof ${e.expected}`:`Gautas tipas ${s}, o tik\u0117tasi - ${o}`}case"invalid_value":return e.values.length===1?`Privalo b\u016Bti ${y(e.values[0])}`:`Privalo b\u016Bti vienas i\u0161 ${f(e.values,"|")} pasirinkim\u0173`;case"too_big":{let o=i[e.origin]??e.origin,a=r(e.origin,km(Number(e.maximum)),e.inclusive??!1,"smaller");if(a?.verb)return`${vr(o??e.origin??"reik\u0161m\u0117")} ${a.verb} ${e.maximum.toString()} ${a.unit??"element\u0173"}`;let s=e.inclusive?"ne didesnis kaip":"ma\u017Eesnis kaip";return`${vr(o??e.origin??"reik\u0161m\u0117")} turi b\u016Bti ${s} ${e.maximum.toString()} ${a?.unit}`}case"too_small":{let o=i[e.origin]??e.origin,a=r(e.origin,km(Number(e.minimum)),e.inclusive??!1,"bigger");if(a?.verb)return`${vr(o??e.origin??"reik\u0161m\u0117")} ${a.verb} ${e.minimum.toString()} ${a.unit??"element\u0173"}`;let s=e.inclusive?"ne ma\u017Eesnis kaip":"didesnis kaip";return`${vr(o??e.origin??"reik\u0161m\u0117")} turi b\u016Bti ${s} ${e.minimum.toString()} ${a?.unit}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Eilut\u0117 privalo prasid\u0117ti "${o.prefix}"`:o.format==="ends_with"?`Eilut\u0117 privalo pasibaigti "${o.suffix}"`:o.format==="includes"?`Eilut\u0117 privalo \u012Ftraukti "${o.includes}"`:o.format==="regex"?`Eilut\u0117 privalo atitikti ${o.pattern}`:`Neteisingas ${n[o.format]??e.format}`}case"not_multiple_of":return`Skai\u010Dius privalo b\u016Bti ${e.divisor} kartotinis.`;case"unrecognized_keys":return`Neatpa\u017Eint${e.keys.length>1?"i":"as"} rakt${e.keys.length>1?"ai":"as"}: ${f(e.keys,", ")}`;case"invalid_key":return"Rastas klaidingas raktas";case"invalid_union":return"Klaidinga \u012Fvestis";case"invalid_element":{let o=i[e.origin]??e.origin;return`${vr(o??e.origin??"reik\u0161m\u0117")} turi klaiding\u0105 \u012Fvest\u012F`}default:return"Klaidinga \u012Fvestis"}}}});function wm(){return{localeError:Ah()}}var Ah,Im=x(()=>{w();Ah=()=>{let t={string:{unit:"\u0437\u043D\u0430\u0446\u0438",verb:"\u0434\u0430 \u0438\u043C\u0430\u0430\u0442"},file:{unit:"\u0431\u0430\u0458\u0442\u0438",verb:"\u0434\u0430 \u0438\u043C\u0430\u0430\u0442"},array:{unit:"\u0441\u0442\u0430\u0432\u043A\u0438",verb:"\u0434\u0430 \u0438\u043C\u0430\u0430\u0442"},set:{unit:"\u0441\u0442\u0430\u0432\u043A\u0438",verb:"\u0434\u0430 \u0438\u043C\u0430\u0430\u0442"}};function r(e){return t[e]??null}let n={regex:"\u0432\u043D\u0435\u0441",email:"\u0430\u0434\u0440\u0435\u0441\u0430 \u043D\u0430 \u0435-\u043F\u043E\u0448\u0442\u0430",url:"URL",emoji:"\u0435\u043C\u043E\u045F\u0438",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u0434\u0430\u0442\u0443\u043C \u0438 \u0432\u0440\u0435\u043C\u0435",date:"ISO \u0434\u0430\u0442\u0443\u043C",time:"ISO \u0432\u0440\u0435\u043C\u0435",duration:"ISO \u0432\u0440\u0435\u043C\u0435\u0442\u0440\u0430\u0435\u045A\u0435",ipv4:"IPv4 \u0430\u0434\u0440\u0435\u0441\u0430",ipv6:"IPv6 \u0430\u0434\u0440\u0435\u0441\u0430",cidrv4:"IPv4 \u043E\u043F\u0441\u0435\u0433",cidrv6:"IPv6 \u043E\u043F\u0441\u0435\u0433",base64:"base64-\u0435\u043D\u043A\u043E\u0434\u0438\u0440\u0430\u043D\u0430 \u043D\u0438\u0437\u0430",base64url:"base64url-\u0435\u043D\u043A\u043E\u0434\u0438\u0440\u0430\u043D\u0430 \u043D\u0438\u0437\u0430",json_string:"JSON \u043D\u0438\u0437\u0430",e164:"E.164 \u0431\u0440\u043E\u0458",jwt:"JWT",template_literal:"\u0432\u043D\u0435\u0441"},i={nan:"NaN",number:"\u0431\u0440\u043E\u0458",array:"\u043D\u0438\u0437\u0430"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0413\u0440\u0435\u0448\u0435\u043D \u0432\u043D\u0435\u0441: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 instanceof ${e.expected}, \u043F\u0440\u0438\u043C\u0435\u043D\u043E ${s}`:`\u0413\u0440\u0435\u0448\u0435\u043D \u0432\u043D\u0435\u0441: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 ${o}, \u043F\u0440\u0438\u043C\u0435\u043D\u043E ${s}`}case"invalid_value":return e.values.length===1?`Invalid input: expected ${y(e.values[0])}`:`\u0413\u0440\u0435\u0448\u0430\u043D\u0430 \u043E\u043F\u0446\u0438\u0458\u0430: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 \u0435\u0434\u043D\u0430 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u041F\u0440\u0435\u043C\u043D\u043E\u0433\u0443 \u0433\u043E\u043B\u0435\u043C: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 ${e.origin??"\u0432\u0440\u0435\u0434\u043D\u043E\u0441\u0442\u0430"} \u0434\u0430 \u0438\u043C\u0430 ${o}${e.maximum.toString()} ${a.unit??"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438"}`:`\u041F\u0440\u0435\u043C\u043D\u043E\u0433\u0443 \u0433\u043E\u043B\u0435\u043C: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 ${e.origin??"\u0432\u0440\u0435\u0434\u043D\u043E\u0441\u0442\u0430"} \u0434\u0430 \u0431\u0438\u0434\u0435 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u041F\u0440\u0435\u043C\u043D\u043E\u0433\u0443 \u043C\u0430\u043B: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 ${e.origin} \u0434\u0430 \u0438\u043C\u0430 ${o}${e.minimum.toString()} ${a.unit}`:`\u041F\u0440\u0435\u043C\u043D\u043E\u0433\u0443 \u043C\u0430\u043B: \u0441\u0435 \u043E\u0447\u0435\u043A\u0443\u0432\u0430 ${e.origin} \u0434\u0430 \u0431\u0438\u0434\u0435 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u041D\u0435\u0432\u0430\u0436\u0435\u0447\u043A\u0430 \u043D\u0438\u0437\u0430: \u043C\u043E\u0440\u0430 \u0434\u0430 \u0437\u0430\u043F\u043E\u0447\u043D\u0443\u0432\u0430 \u0441\u043E "${o.prefix}"`:o.format==="ends_with"?`\u041D\u0435\u0432\u0430\u0436\u0435\u0447\u043A\u0430 \u043D\u0438\u0437\u0430: \u043C\u043E\u0440\u0430 \u0434\u0430 \u0437\u0430\u0432\u0440\u0448\u0443\u0432\u0430 \u0441\u043E "${o.suffix}"`:o.format==="includes"?`\u041D\u0435\u0432\u0430\u0436\u0435\u0447\u043A\u0430 \u043D\u0438\u0437\u0430: \u043C\u043E\u0440\u0430 \u0434\u0430 \u0432\u043A\u043B\u0443\u0447\u0443\u0432\u0430 "${o.includes}"`:o.format==="regex"?`\u041D\u0435\u0432\u0430\u0436\u0435\u0447\u043A\u0430 \u043D\u0438\u0437\u0430: \u043C\u043E\u0440\u0430 \u0434\u0430 \u043E\u0434\u0433\u043E\u0430\u0440\u0430 \u043D\u0430 \u043F\u0430\u0442\u0435\u0440\u043D\u043E\u0442 ${o.pattern}`:`Invalid ${n[o.format]??e.format}`}case"not_multiple_of":return`\u0413\u0440\u0435\u0448\u0435\u043D \u0431\u0440\u043E\u0458: \u043C\u043E\u0440\u0430 \u0434\u0430 \u0431\u0438\u0434\u0435 \u0434\u0435\u043B\u0438\u0432 \u0441\u043E ${e.divisor}`;case"unrecognized_keys":return`${e.keys.length>1?"\u041D\u0435\u043F\u0440\u0435\u043F\u043E\u0437\u043D\u0430\u0435\u043D\u0438 \u043A\u043B\u0443\u0447\u0435\u0432\u0438":"\u041D\u0435\u043F\u0440\u0435\u043F\u043E\u0437\u043D\u0430\u0435\u043D \u043A\u043B\u0443\u0447"}: ${f(e.keys,", ")}`;case"invalid_key":return`\u0413\u0440\u0435\u0448\u0435\u043D \u043A\u043B\u0443\u0447 \u0432\u043E ${e.origin}`;case"invalid_union":return"\u0413\u0440\u0435\u0448\u0435\u043D \u0432\u043D\u0435\u0441";case"invalid_element":return`\u0413\u0440\u0435\u0448\u043D\u0430 \u0432\u0440\u0435\u0434\u043D\u043E\u0441\u0442 \u0432\u043E ${e.origin}`;default:return"\u0413\u0440\u0435\u0448\u0435\u043D \u0432\u043D\u0435\u0441"}}}});function Pm(){return{localeError:Ch()}}var Ch,jm=x(()=>{w();Ch=()=>{let t={string:{unit:"aksara",verb:"mempunyai"},file:{unit:"bait",verb:"mempunyai"},array:{unit:"elemen",verb:"mempunyai"},set:{unit:"elemen",verb:"mempunyai"}};function r(e){return t[e]??null}let n={regex:"input",email:"alamat e-mel",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"tarikh masa ISO",date:"tarikh ISO",time:"masa ISO",duration:"tempoh ISO",ipv4:"alamat IPv4",ipv6:"alamat IPv6",cidrv4:"julat IPv4",cidrv6:"julat IPv6",base64:"string dikodkan base64",base64url:"string dikodkan base64url",json_string:"string JSON",e164:"nombor E.164",jwt:"JWT",template_literal:"input"},i={nan:"NaN",number:"nombor"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Input tidak sah: dijangka instanceof ${e.expected}, diterima ${s}`:`Input tidak sah: dijangka ${o}, diterima ${s}`}case"invalid_value":return e.values.length===1?`Input tidak sah: dijangka ${y(e.values[0])}`:`Pilihan tidak sah: dijangka salah satu daripada ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Terlalu besar: dijangka ${e.origin??"nilai"} ${a.verb} ${o}${e.maximum.toString()} ${a.unit??"elemen"}`:`Terlalu besar: dijangka ${e.origin??"nilai"} adalah ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Terlalu kecil: dijangka ${e.origin} ${a.verb} ${o}${e.minimum.toString()} ${a.unit}`:`Terlalu kecil: dijangka ${e.origin} adalah ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`String tidak sah: mesti bermula dengan "${o.prefix}"`:o.format==="ends_with"?`String tidak sah: mesti berakhir dengan "${o.suffix}"`:o.format==="includes"?`String tidak sah: mesti mengandungi "${o.includes}"`:o.format==="regex"?`String tidak sah: mesti sepadan dengan corak ${o.pattern}`:`${n[o.format]??e.format} tidak sah`}case"not_multiple_of":return`Nombor tidak sah: perlu gandaan ${e.divisor}`;case"unrecognized_keys":return`Kunci tidak dikenali: ${f(e.keys,", ")}`;case"invalid_key":return`Kunci tidak sah dalam ${e.origin}`;case"invalid_union":return"Input tidak sah";case"invalid_element":return`Nilai tidak sah dalam ${e.origin}`;default:return"Input tidak sah"}}}});function Tm(){return{localeError:Mh()}}var Mh,Om=x(()=>{w();Mh=()=>{let t={string:{unit:"tekens",verb:"heeft"},file:{unit:"bytes",verb:"heeft"},array:{unit:"elementen",verb:"heeft"},set:{unit:"elementen",verb:"heeft"}};function r(e){return t[e]??null}let n={regex:"invoer",email:"emailadres",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datum en tijd",date:"ISO datum",time:"ISO tijd",duration:"ISO duur",ipv4:"IPv4-adres",ipv6:"IPv6-adres",cidrv4:"IPv4-bereik",cidrv6:"IPv6-bereik",base64:"base64-gecodeerde tekst",base64url:"base64 URL-gecodeerde tekst",json_string:"JSON string",e164:"E.164-nummer",jwt:"JWT",template_literal:"invoer"},i={nan:"NaN",number:"getal"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Ongeldige invoer: verwacht instanceof ${e.expected}, ontving ${s}`:`Ongeldige invoer: verwacht ${o}, ontving ${s}`}case"invalid_value":return e.values.length===1?`Ongeldige invoer: verwacht ${y(e.values[0])}`:`Ongeldige optie: verwacht \xE9\xE9n van ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin),s=e.origin==="date"?"laat":e.origin==="string"?"lang":"groot";return a?`Te ${s}: verwacht dat ${e.origin??"waarde"} ${o}${e.maximum.toString()} ${a.unit??"elementen"} ${a.verb}`:`Te ${s}: verwacht dat ${e.origin??"waarde"} ${o}${e.maximum.toString()} is`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin),s=e.origin==="date"?"vroeg":e.origin==="string"?"kort":"klein";return a?`Te ${s}: verwacht dat ${e.origin} ${o}${e.minimum.toString()} ${a.unit} ${a.verb}`:`Te ${s}: verwacht dat ${e.origin} ${o}${e.minimum.toString()} is`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Ongeldige tekst: moet met "${o.prefix}" beginnen`:o.format==="ends_with"?`Ongeldige tekst: moet op "${o.suffix}" eindigen`:o.format==="includes"?`Ongeldige tekst: moet "${o.includes}" bevatten`:o.format==="regex"?`Ongeldige tekst: moet overeenkomen met patroon ${o.pattern}`:`Ongeldig: ${n[o.format]??e.format}`}case"not_multiple_of":return`Ongeldig getal: moet een veelvoud van ${e.divisor} zijn`;case"unrecognized_keys":return`Onbekende key${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Ongeldige key in ${e.origin}`;case"invalid_union":return"Ongeldige invoer";case"invalid_element":return`Ongeldige waarde in ${e.origin}`;default:return"Ongeldige invoer"}}}});function Dm(){return{localeError:Lh()}}var Lh,Um=x(()=>{w();Lh=()=>{let t={string:{unit:"tegn",verb:"\xE5 ha"},file:{unit:"bytes",verb:"\xE5 ha"},array:{unit:"elementer",verb:"\xE5 inneholde"},set:{unit:"elementer",verb:"\xE5 inneholde"}};function r(e){return t[e]??null}let n={regex:"input",email:"e-postadresse",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO dato- og klokkeslett",date:"ISO-dato",time:"ISO-klokkeslett",duration:"ISO-varighet",ipv4:"IPv4-omr\xE5de",ipv6:"IPv6-omr\xE5de",cidrv4:"IPv4-spekter",cidrv6:"IPv6-spekter",base64:"base64-enkodet streng",base64url:"base64url-enkodet streng",json_string:"JSON-streng",e164:"E.164-nummer",jwt:"JWT",template_literal:"input"},i={nan:"NaN",number:"tall",array:"liste"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Ugyldig input: forventet instanceof ${e.expected}, fikk ${s}`:`Ugyldig input: forventet ${o}, fikk ${s}`}case"invalid_value":return e.values.length===1?`Ugyldig verdi: forventet ${y(e.values[0])}`:`Ugyldig valg: forventet en av ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`For stor(t): forventet ${e.origin??"value"} til \xE5 ha ${o}${e.maximum.toString()} ${a.unit??"elementer"}`:`For stor(t): forventet ${e.origin??"value"} til \xE5 ha ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`For lite(n): forventet ${e.origin} til \xE5 ha ${o}${e.minimum.toString()} ${a.unit}`:`For lite(n): forventet ${e.origin} til \xE5 ha ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Ugyldig streng: m\xE5 starte med "${o.prefix}"`:o.format==="ends_with"?`Ugyldig streng: m\xE5 ende med "${o.suffix}"`:o.format==="includes"?`Ugyldig streng: m\xE5 inneholde "${o.includes}"`:o.format==="regex"?`Ugyldig streng: m\xE5 matche m\xF8nsteret ${o.pattern}`:`Ugyldig ${n[o.format]??e.format}`}case"not_multiple_of":return`Ugyldig tall: m\xE5 v\xE6re et multiplum av ${e.divisor}`;case"unrecognized_keys":return`${e.keys.length>1?"Ukjente n\xF8kler":"Ukjent n\xF8kkel"}: ${f(e.keys,", ")}`;case"invalid_key":return`Ugyldig n\xF8kkel i ${e.origin}`;case"invalid_union":return"Ugyldig input";case"invalid_element":return`Ugyldig verdi i ${e.origin}`;default:return"Ugyldig input"}}}});function Nm(){return{localeError:qh()}}var qh,Em=x(()=>{w();qh=()=>{let t={string:{unit:"harf",verb:"olmal\u0131d\u0131r"},file:{unit:"bayt",verb:"olmal\u0131d\u0131r"},array:{unit:"unsur",verb:"olmal\u0131d\u0131r"},set:{unit:"unsur",verb:"olmal\u0131d\u0131r"}};function r(e){return t[e]??null}let n={regex:"giren",email:"epostag\xE2h",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO heng\xE2m\u0131",date:"ISO tarihi",time:"ISO zaman\u0131",duration:"ISO m\xFCddeti",ipv4:"IPv4 ni\u015F\xE2n\u0131",ipv6:"IPv6 ni\u015F\xE2n\u0131",cidrv4:"IPv4 menzili",cidrv6:"IPv6 menzili",base64:"base64-\u015Fifreli metin",base64url:"base64url-\u015Fifreli metin",json_string:"JSON metin",e164:"E.164 say\u0131s\u0131",jwt:"JWT",template_literal:"giren"},i={nan:"NaN",number:"numara",array:"saf",null:"gayb"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`F\xE2sit giren: umulan instanceof ${e.expected}, al\u0131nan ${s}`:`F\xE2sit giren: umulan ${o}, al\u0131nan ${s}`}case"invalid_value":return e.values.length===1?`F\xE2sit giren: umulan ${y(e.values[0])}`:`F\xE2sit tercih: m\xFBteberler ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Fazla b\xFCy\xFCk: ${e.origin??"value"}, ${o}${e.maximum.toString()} ${a.unit??"elements"} sahip olmal\u0131yd\u0131.`:`Fazla b\xFCy\xFCk: ${e.origin??"value"}, ${o}${e.maximum.toString()} olmal\u0131yd\u0131.`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Fazla k\xFC\xE7\xFCk: ${e.origin}, ${o}${e.minimum.toString()} ${a.unit} sahip olmal\u0131yd\u0131.`:`Fazla k\xFC\xE7\xFCk: ${e.origin}, ${o}${e.minimum.toString()} olmal\u0131yd\u0131.`}case"invalid_format":{let o=e;return o.format==="starts_with"?`F\xE2sit metin: "${o.prefix}" ile ba\u015Flamal\u0131.`:o.format==="ends_with"?`F\xE2sit metin: "${o.suffix}" ile bitmeli.`:o.format==="includes"?`F\xE2sit metin: "${o.includes}" ihtiv\xE2 etmeli.`:o.format==="regex"?`F\xE2sit metin: ${o.pattern} nak\u015F\u0131na uymal\u0131.`:`F\xE2sit ${n[o.format]??e.format}`}case"not_multiple_of":return`F\xE2sit say\u0131: ${e.divisor} kat\u0131 olmal\u0131yd\u0131.`;case"unrecognized_keys":return`Tan\u0131nmayan anahtar ${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`${e.origin} i\xE7in tan\u0131nmayan anahtar var.`;case"invalid_union":return"Giren tan\u0131namad\u0131.";case"invalid_element":return`${e.origin} i\xE7in tan\u0131nmayan k\u0131ymet var.`;default:return"K\u0131ymet tan\u0131namad\u0131."}}}});function Zm(){return{localeError:Fh()}}var Fh,Rm=x(()=>{w();Fh=()=>{let t={string:{unit:"\u062A\u0648\u06A9\u064A",verb:"\u0648\u0644\u0631\u064A"},file:{unit:"\u0628\u0627\u06CC\u067C\u0633",verb:"\u0648\u0644\u0631\u064A"},array:{unit:"\u062A\u0648\u06A9\u064A",verb:"\u0648\u0644\u0631\u064A"},set:{unit:"\u062A\u0648\u06A9\u064A",verb:"\u0648\u0644\u0631\u064A"}};function r(e){return t[e]??null}let n={regex:"\u0648\u0631\u0648\u062F\u064A",email:"\u0628\u0631\u06CC\u069A\u0646\u0627\u0644\u06CC\u06A9",url:"\u06CC\u0648 \u0622\u0631 \u0627\u0644",emoji:"\u0627\u06CC\u0645\u0648\u062C\u064A",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u0646\u06CC\u067C\u0647 \u0627\u0648 \u0648\u062E\u062A",date:"\u0646\u06D0\u067C\u0647",time:"\u0648\u062E\u062A",duration:"\u0645\u0648\u062F\u0647",ipv4:"\u062F IPv4 \u067E\u062A\u0647",ipv6:"\u062F IPv6 \u067E\u062A\u0647",cidrv4:"\u062F IPv4 \u0633\u0627\u062D\u0647",cidrv6:"\u062F IPv6 \u0633\u0627\u062D\u0647",base64:"base64-encoded \u0645\u062A\u0646",base64url:"base64url-encoded \u0645\u062A\u0646",json_string:"JSON \u0645\u062A\u0646",e164:"\u062F E.164 \u0634\u0645\u06D0\u0631\u0647",jwt:"JWT",template_literal:"\u0648\u0631\u0648\u062F\u064A"},i={nan:"NaN",number:"\u0639\u062F\u062F",array:"\u0627\u0631\u06D0"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0646\u0627\u0633\u0645 \u0648\u0631\u0648\u062F\u064A: \u0628\u0627\u06CC\u062F instanceof ${e.expected} \u0648\u0627\u06CC, \u0645\u06AB\u0631 ${s} \u062A\u0631\u0644\u0627\u0633\u0647 \u0634\u0648`:`\u0646\u0627\u0633\u0645 \u0648\u0631\u0648\u062F\u064A: \u0628\u0627\u06CC\u062F ${o} \u0648\u0627\u06CC, \u0645\u06AB\u0631 ${s} \u062A\u0631\u0644\u0627\u0633\u0647 \u0634\u0648`}case"invalid_value":return e.values.length===1?`\u0646\u0627\u0633\u0645 \u0648\u0631\u0648\u062F\u064A: \u0628\u0627\u06CC\u062F ${y(e.values[0])} \u0648\u0627\u06CC`:`\u0646\u0627\u0633\u0645 \u0627\u0646\u062A\u062E\u0627\u0628: \u0628\u0627\u06CC\u062F \u06CC\u0648 \u0644\u0647 ${f(e.values,"|")} \u0685\u062E\u0647 \u0648\u0627\u06CC`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u0689\u06CC\u0631 \u0644\u0648\u06CC: ${e.origin??"\u0627\u0631\u0632\u069A\u062A"} \u0628\u0627\u06CC\u062F ${o}${e.maximum.toString()} ${a.unit??"\u0639\u0646\u0635\u0631\u0648\u0646\u0647"} \u0648\u0644\u0631\u064A`:`\u0689\u06CC\u0631 \u0644\u0648\u06CC: ${e.origin??"\u0627\u0631\u0632\u069A\u062A"} \u0628\u0627\u06CC\u062F ${o}${e.maximum.toString()} \u0648\u064A`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u0689\u06CC\u0631 \u06A9\u0648\u0686\u0646\u06CC: ${e.origin} \u0628\u0627\u06CC\u062F ${o}${e.minimum.toString()} ${a.unit} \u0648\u0644\u0631\u064A`:`\u0689\u06CC\u0631 \u06A9\u0648\u0686\u0646\u06CC: ${e.origin} \u0628\u0627\u06CC\u062F ${o}${e.minimum.toString()} \u0648\u064A`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u0646\u0627\u0633\u0645 \u0645\u062A\u0646: \u0628\u0627\u06CC\u062F \u062F "${o.prefix}" \u0633\u0631\u0647 \u067E\u06CC\u0644 \u0634\u064A`:o.format==="ends_with"?`\u0646\u0627\u0633\u0645 \u0645\u062A\u0646: \u0628\u0627\u06CC\u062F \u062F "${o.suffix}" \u0633\u0631\u0647 \u067E\u0627\u06CC \u062A\u0647 \u0648\u0631\u0633\u064A\u0696\u064A`:o.format==="includes"?`\u0646\u0627\u0633\u0645 \u0645\u062A\u0646: \u0628\u0627\u06CC\u062F "${o.includes}" \u0648\u0644\u0631\u064A`:o.format==="regex"?`\u0646\u0627\u0633\u0645 \u0645\u062A\u0646: \u0628\u0627\u06CC\u062F \u062F ${o.pattern} \u0633\u0631\u0647 \u0645\u0637\u0627\u0628\u0642\u062A \u0648\u0644\u0631\u064A`:`${n[o.format]??e.format} \u0646\u0627\u0633\u0645 \u062F\u06CC`}case"not_multiple_of":return`\u0646\u0627\u0633\u0645 \u0639\u062F\u062F: \u0628\u0627\u06CC\u062F \u062F ${e.divisor} \u0645\u0636\u0631\u0628 \u0648\u064A`;case"unrecognized_keys":return`\u0646\u0627\u0633\u0645 ${e.keys.length>1?"\u06A9\u0644\u06CC\u0689\u0648\u0646\u0647":"\u06A9\u0644\u06CC\u0689"}: ${f(e.keys,", ")}`;case"invalid_key":return`\u0646\u0627\u0633\u0645 \u06A9\u0644\u06CC\u0689 \u067E\u0647 ${e.origin} \u06A9\u06D0`;case"invalid_union":return"\u0646\u0627\u0633\u0645\u0647 \u0648\u0631\u0648\u062F\u064A";case"invalid_element":return`\u0646\u0627\u0633\u0645 \u0639\u0646\u0635\u0631 \u067E\u0647 ${e.origin} \u06A9\u06D0`;default:return"\u0646\u0627\u0633\u0645\u0647 \u0648\u0631\u0648\u062F\u064A"}}}});function Am(){return{localeError:Jh()}}var Jh,Cm=x(()=>{w();Jh=()=>{let t={string:{unit:"znak\xF3w",verb:"mie\u0107"},file:{unit:"bajt\xF3w",verb:"mie\u0107"},array:{unit:"element\xF3w",verb:"mie\u0107"},set:{unit:"element\xF3w",verb:"mie\u0107"}};function r(e){return t[e]??null}let n={regex:"wyra\u017Cenie",email:"adres email",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"data i godzina w formacie ISO",date:"data w formacie ISO",time:"godzina w formacie ISO",duration:"czas trwania ISO",ipv4:"adres IPv4",ipv6:"adres IPv6",cidrv4:"zakres IPv4",cidrv6:"zakres IPv6",base64:"ci\u0105g znak\xF3w zakodowany w formacie base64",base64url:"ci\u0105g znak\xF3w zakodowany w formacie base64url",json_string:"ci\u0105g znak\xF3w w formacie JSON",e164:"liczba E.164",jwt:"JWT",template_literal:"wej\u015Bcie"},i={nan:"NaN",number:"liczba",array:"tablica"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Nieprawid\u0142owe dane wej\u015Bciowe: oczekiwano instanceof ${e.expected}, otrzymano ${s}`:`Nieprawid\u0142owe dane wej\u015Bciowe: oczekiwano ${o}, otrzymano ${s}`}case"invalid_value":return e.values.length===1?`Nieprawid\u0142owe dane wej\u015Bciowe: oczekiwano ${y(e.values[0])}`:`Nieprawid\u0142owa opcja: oczekiwano jednej z warto\u015Bci ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Za du\u017Ca warto\u015B\u0107: oczekiwano, \u017Ce ${e.origin??"warto\u015B\u0107"} b\u0119dzie mie\u0107 ${o}${e.maximum.toString()} ${a.unit??"element\xF3w"}`:`Zbyt du\u017C(y/a/e): oczekiwano, \u017Ce ${e.origin??"warto\u015B\u0107"} b\u0119dzie wynosi\u0107 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Za ma\u0142a warto\u015B\u0107: oczekiwano, \u017Ce ${e.origin??"warto\u015B\u0107"} b\u0119dzie mie\u0107 ${o}${e.minimum.toString()} ${a.unit??"element\xF3w"}`:`Zbyt ma\u0142(y/a/e): oczekiwano, \u017Ce ${e.origin??"warto\u015B\u0107"} b\u0119dzie wynosi\u0107 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Nieprawid\u0142owy ci\u0105g znak\xF3w: musi zaczyna\u0107 si\u0119 od "${o.prefix}"`:o.format==="ends_with"?`Nieprawid\u0142owy ci\u0105g znak\xF3w: musi ko\u0144czy\u0107 si\u0119 na "${o.suffix}"`:o.format==="includes"?`Nieprawid\u0142owy ci\u0105g znak\xF3w: musi zawiera\u0107 "${o.includes}"`:o.format==="regex"?`Nieprawid\u0142owy ci\u0105g znak\xF3w: musi odpowiada\u0107 wzorcowi ${o.pattern}`:`Nieprawid\u0142ow(y/a/e) ${n[o.format]??e.format}`}case"not_multiple_of":return`Nieprawid\u0142owa liczba: musi by\u0107 wielokrotno\u015Bci\u0105 ${e.divisor}`;case"unrecognized_keys":return`Nierozpoznane klucze${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Nieprawid\u0142owy klucz w ${e.origin}`;case"invalid_union":return"Nieprawid\u0142owe dane wej\u015Bciowe";case"invalid_element":return`Nieprawid\u0142owa warto\u015B\u0107 w ${e.origin}`;default:return"Nieprawid\u0142owe dane wej\u015Bciowe"}}}});function Mm(){return{localeError:Vh()}}var Vh,Lm=x(()=>{w();Vh=()=>{let t={string:{unit:"caracteres",verb:"ter"},file:{unit:"bytes",verb:"ter"},array:{unit:"itens",verb:"ter"},set:{unit:"itens",verb:"ter"}};function r(e){return t[e]??null}let n={regex:"padr\xE3o",email:"endere\xE7o de e-mail",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"data e hora ISO",date:"data ISO",time:"hora ISO",duration:"dura\xE7\xE3o ISO",ipv4:"endere\xE7o IPv4",ipv6:"endere\xE7o IPv6",cidrv4:"faixa de IPv4",cidrv6:"faixa de IPv6",base64:"texto codificado em base64",base64url:"URL codificada em base64",json_string:"texto JSON",e164:"n\xFAmero E.164",jwt:"JWT",template_literal:"entrada"},i={nan:"NaN",number:"n\xFAmero",null:"nulo"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Tipo inv\xE1lido: esperado instanceof ${e.expected}, recebido ${s}`:`Tipo inv\xE1lido: esperado ${o}, recebido ${s}`}case"invalid_value":return e.values.length===1?`Entrada inv\xE1lida: esperado ${y(e.values[0])}`:`Op\xE7\xE3o inv\xE1lida: esperada uma das ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Muito grande: esperado que ${e.origin??"valor"} tivesse ${o}${e.maximum.toString()} ${a.unit??"elementos"}`:`Muito grande: esperado que ${e.origin??"valor"} fosse ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Muito pequeno: esperado que ${e.origin} tivesse ${o}${e.minimum.toString()} ${a.unit}`:`Muito pequeno: esperado que ${e.origin} fosse ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Texto inv\xE1lido: deve come\xE7ar com "${o.prefix}"`:o.format==="ends_with"?`Texto inv\xE1lido: deve terminar com "${o.suffix}"`:o.format==="includes"?`Texto inv\xE1lido: deve incluir "${o.includes}"`:o.format==="regex"?`Texto inv\xE1lido: deve corresponder ao padr\xE3o ${o.pattern}`:`${n[o.format]??e.format} inv\xE1lido`}case"not_multiple_of":return`N\xFAmero inv\xE1lido: deve ser m\xFAltiplo de ${e.divisor}`;case"unrecognized_keys":return`Chave${e.keys.length>1?"s":""} desconhecida${e.keys.length>1?"s":""}: ${f(e.keys,", ")}`;case"invalid_key":return`Chave inv\xE1lida em ${e.origin}`;case"invalid_union":return"Entrada inv\xE1lida";case"invalid_element":return`Valor inv\xE1lido em ${e.origin}`;default:return"Campo inv\xE1lido"}}}});function qm(){return{localeError:Hh()}}var Hh,Fm=x(()=>{w();Hh=()=>{let t={string:{unit:"caractere",verb:"s\u0103 aib\u0103"},file:{unit:"octe\u021Bi",verb:"s\u0103 aib\u0103"},array:{unit:"elemente",verb:"s\u0103 aib\u0103"},set:{unit:"elemente",verb:"s\u0103 aib\u0103"},map:{unit:"intr\u0103ri",verb:"s\u0103 aib\u0103"}};function r(e){return t[e]??null}let n={regex:"intrare",email:"adres\u0103 de email",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"dat\u0103 \u0219i or\u0103 ISO",date:"dat\u0103 ISO",time:"or\u0103 ISO",duration:"durat\u0103 ISO",ipv4:"adres\u0103 IPv4",ipv6:"adres\u0103 IPv6",mac:"adres\u0103 MAC",cidrv4:"interval IPv4",cidrv6:"interval IPv6",base64:"\u0219ir codat base64",base64url:"\u0219ir codat base64url",json_string:"\u0219ir JSON",e164:"num\u0103r E.164",jwt:"JWT",template_literal:"intrare"},i={nan:"NaN",string:"\u0219ir",number:"num\u0103r",boolean:"boolean",function:"func\u021Bie",array:"matrice",object:"obiect",undefined:"nedefinit",symbol:"simbol",bigint:"num\u0103r mare",void:"void",never:"never",map:"hart\u0103",set:"set"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return`Intrare invalid\u0103: a\u0219teptat ${o}, primit ${s}`}case"invalid_value":return e.values.length===1?`Intrare invalid\u0103: a\u0219teptat ${y(e.values[0])}`:`Op\u021Biune invalid\u0103: a\u0219teptat una dintre ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Prea mare: a\u0219teptat ca ${e.origin??"valoarea"} ${a.verb} ${o}${e.maximum.toString()} ${a.unit??"elemente"}`:`Prea mare: a\u0219teptat ca ${e.origin??"valoarea"} s\u0103 fie ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Prea mic: a\u0219teptat ca ${e.origin} ${a.verb} ${o}${e.minimum.toString()} ${a.unit}`:`Prea mic: a\u0219teptat ca ${e.origin} s\u0103 fie ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u0218ir invalid: trebuie s\u0103 \xEEnceap\u0103 cu "${o.prefix}"`:o.format==="ends_with"?`\u0218ir invalid: trebuie s\u0103 se termine cu "${o.suffix}"`:o.format==="includes"?`\u0218ir invalid: trebuie s\u0103 includ\u0103 "${o.includes}"`:o.format==="regex"?`\u0218ir invalid: trebuie s\u0103 se potriveasc\u0103 cu modelul ${o.pattern}`:`Format invalid: ${n[o.format]??e.format}`}case"not_multiple_of":return`Num\u0103r invalid: trebuie s\u0103 fie multiplu de ${e.divisor}`;case"unrecognized_keys":return`Chei nerecunoscute: ${f(e.keys,", ")}`;case"invalid_key":return`Cheie invalid\u0103 \xEEn ${e.origin}`;case"invalid_union":return"Intrare invalid\u0103";case"invalid_element":return`Valoare invalid\u0103 \xEEn ${e.origin}`;default:return"Intrare invalid\u0103"}}}});function Jm(t,r,n,i){let e=Math.abs(t),o=e%10,a=e%100;return a>=11&&a<=19?i:o===1?r:o>=2&&o<=4?n:i}function Vm(){return{localeError:Bh()}}var Bh,Hm=x(()=>{w();Bh=()=>{let t={string:{unit:{one:"\u0441\u0438\u043C\u0432\u043E\u043B",few:"\u0441\u0438\u043C\u0432\u043E\u043B\u0430",many:"\u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432"},verb:"\u0438\u043C\u0435\u0442\u044C"},file:{unit:{one:"\u0431\u0430\u0439\u0442",few:"\u0431\u0430\u0439\u0442\u0430",many:"\u0431\u0430\u0439\u0442"},verb:"\u0438\u043C\u0435\u0442\u044C"},array:{unit:{one:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442",few:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430",many:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432"},verb:"\u0438\u043C\u0435\u0442\u044C"},set:{unit:{one:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442",few:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430",many:"\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432"},verb:"\u0438\u043C\u0435\u0442\u044C"}};function r(e){return t[e]??null}let n={regex:"\u0432\u0432\u043E\u0434",email:"email \u0430\u0434\u0440\u0435\u0441",url:"URL",emoji:"\u044D\u043C\u043E\u0434\u0437\u0438",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u0434\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F",date:"ISO \u0434\u0430\u0442\u0430",time:"ISO \u0432\u0440\u0435\u043C\u044F",duration:"ISO \u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C",ipv4:"IPv4 \u0430\u0434\u0440\u0435\u0441",ipv6:"IPv6 \u0430\u0434\u0440\u0435\u0441",cidrv4:"IPv4 \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D",cidrv6:"IPv6 \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D",base64:"\u0441\u0442\u0440\u043E\u043A\u0430 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 base64",base64url:"\u0441\u0442\u0440\u043E\u043A\u0430 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 base64url",json_string:"JSON \u0441\u0442\u0440\u043E\u043A\u0430",e164:"\u043D\u043E\u043C\u0435\u0440 E.164",jwt:"JWT",template_literal:"\u0432\u0432\u043E\u0434"},i={nan:"NaN",number:"\u0447\u0438\u0441\u043B\u043E",array:"\u043C\u0430\u0441\u0441\u0438\u0432"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0432\u0432\u043E\u0434: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C instanceof ${e.expected}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E ${s}`:`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0432\u0432\u043E\u0434: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C ${o}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E ${s}`}case"invalid_value":return e.values.length===1?`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0432\u0432\u043E\u0434: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C ${y(e.values[0])}`:`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0434\u043D\u043E \u0438\u0437 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);if(a){let s=Number(e.maximum),c=Jm(s,a.unit.one,a.unit.few,a.unit.many);return`\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${e.origin??"\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"} \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C ${o}${e.maximum.toString()} ${c}`}return`\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${e.origin??"\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"} \u0431\u0443\u0434\u0435\u0442 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);if(a){let s=Number(e.minimum),c=Jm(s,a.unit.one,a.unit.few,a.unit.many);return`\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${e.origin} \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C ${o}${e.minimum.toString()} ${c}`}return`\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${e.origin} \u0431\u0443\u0434\u0435\u0442 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u041D\u0435\u0432\u0435\u0440\u043D\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430: \u0434\u043E\u043B\u0436\u043D\u0430 \u043D\u0430\u0447\u0438\u043D\u0430\u0442\u044C\u0441\u044F \u0441 "${o.prefix}"`:o.format==="ends_with"?`\u041D\u0435\u0432\u0435\u0440\u043D\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430: \u0434\u043E\u043B\u0436\u043D\u0430 \u0437\u0430\u043A\u0430\u043D\u0447\u0438\u0432\u0430\u0442\u044C\u0441\u044F \u043D\u0430 "${o.suffix}"`:o.format==="includes"?`\u041D\u0435\u0432\u0435\u0440\u043D\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430: \u0434\u043E\u043B\u0436\u043D\u0430 \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C "${o.includes}"`:o.format==="regex"?`\u041D\u0435\u0432\u0435\u0440\u043D\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430: \u0434\u043E\u043B\u0436\u043D\u0430 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043E\u0432\u0430\u0442\u044C \u0448\u0430\u0431\u043B\u043E\u043D\u0443 ${o.pattern}`:`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u041D\u0435\u0432\u0435\u0440\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043A\u0440\u0430\u0442\u043D\u044B\u043C ${e.divisor}`;case"unrecognized_keys":return`\u041D\u0435\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u043D\u043D${e.keys.length>1?"\u044B\u0435":"\u044B\u0439"} \u043A\u043B\u044E\u0447${e.keys.length>1?"\u0438":""}: ${f(e.keys,", ")}`;case"invalid_key":return`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043A\u043B\u044E\u0447 \u0432 ${e.origin}`;case"invalid_union":return"\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u0432\u0445\u043E\u0434\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435";case"invalid_element":return`\u041D\u0435\u0432\u0435\u0440\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0432 ${e.origin}`;default:return"\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u0432\u0445\u043E\u0434\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435"}}}});function Bm(){return{localeError:Wh()}}var Wh,Wm=x(()=>{w();Wh=()=>{let t={string:{unit:"znakov",verb:"imeti"},file:{unit:"bajtov",verb:"imeti"},array:{unit:"elementov",verb:"imeti"},set:{unit:"elementov",verb:"imeti"}};function r(e){return t[e]??null}let n={regex:"vnos",email:"e-po\u0161tni naslov",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datum in \u010Das",date:"ISO datum",time:"ISO \u010Das",duration:"ISO trajanje",ipv4:"IPv4 naslov",ipv6:"IPv6 naslov",cidrv4:"obseg IPv4",cidrv6:"obseg IPv6",base64:"base64 kodiran niz",base64url:"base64url kodiran niz",json_string:"JSON niz",e164:"E.164 \u0161tevilka",jwt:"JWT",template_literal:"vnos"},i={nan:"NaN",number:"\u0161tevilo",array:"tabela"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Neveljaven vnos: pri\u010Dakovano instanceof ${e.expected}, prejeto ${s}`:`Neveljaven vnos: pri\u010Dakovano ${o}, prejeto ${s}`}case"invalid_value":return e.values.length===1?`Neveljaven vnos: pri\u010Dakovano ${y(e.values[0])}`:`Neveljavna mo\u017Enost: pri\u010Dakovano eno izmed ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Preveliko: pri\u010Dakovano, da bo ${e.origin??"vrednost"} imelo ${o}${e.maximum.toString()} ${a.unit??"elementov"}`:`Preveliko: pri\u010Dakovano, da bo ${e.origin??"vrednost"} ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Premajhno: pri\u010Dakovano, da bo ${e.origin} imelo ${o}${e.minimum.toString()} ${a.unit}`:`Premajhno: pri\u010Dakovano, da bo ${e.origin} ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Neveljaven niz: mora se za\u010Deti z "${o.prefix}"`:o.format==="ends_with"?`Neveljaven niz: mora se kon\u010Dati z "${o.suffix}"`:o.format==="includes"?`Neveljaven niz: mora vsebovati "${o.includes}"`:o.format==="regex"?`Neveljaven niz: mora ustrezati vzorcu ${o.pattern}`:`Neveljaven ${n[o.format]??e.format}`}case"not_multiple_of":return`Neveljavno \u0161tevilo: mora biti ve\u010Dkratnik ${e.divisor}`;case"unrecognized_keys":return`Neprepoznan${e.keys.length>1?"i klju\u010Di":" klju\u010D"}: ${f(e.keys,", ")}`;case"invalid_key":return`Neveljaven klju\u010D v ${e.origin}`;case"invalid_union":return"Neveljaven vnos";case"invalid_element":return`Neveljavna vrednost v ${e.origin}`;default:return"Neveljaven vnos"}}}});function Km(){return{localeError:Kh()}}var Kh,Gm=x(()=>{w();Kh=()=>{let t={string:{unit:"tecken",verb:"att ha"},file:{unit:"bytes",verb:"att ha"},array:{unit:"objekt",verb:"att inneh\xE5lla"},set:{unit:"objekt",verb:"att inneh\xE5lla"}};function r(e){return t[e]??null}let n={regex:"regulj\xE4rt uttryck",email:"e-postadress",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO-datum och tid",date:"ISO-datum",time:"ISO-tid",duration:"ISO-varaktighet",ipv4:"IPv4-intervall",ipv6:"IPv6-intervall",cidrv4:"IPv4-spektrum",cidrv6:"IPv6-spektrum",base64:"base64-kodad str\xE4ng",base64url:"base64url-kodad str\xE4ng",json_string:"JSON-str\xE4ng",e164:"E.164-nummer",jwt:"JWT",template_literal:"mall-literal"},i={nan:"NaN",number:"antal",array:"lista"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Ogiltig inmatning: f\xF6rv\xE4ntat instanceof ${e.expected}, fick ${s}`:`Ogiltig inmatning: f\xF6rv\xE4ntat ${o}, fick ${s}`}case"invalid_value":return e.values.length===1?`Ogiltig inmatning: f\xF6rv\xE4ntat ${y(e.values[0])}`:`Ogiltigt val: f\xF6rv\xE4ntade en av ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`F\xF6r stor(t): f\xF6rv\xE4ntade ${e.origin??"v\xE4rdet"} att ha ${o}${e.maximum.toString()} ${a.unit??"element"}`:`F\xF6r stor(t): f\xF6rv\xE4ntat ${e.origin??"v\xE4rdet"} att ha ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`F\xF6r lite(t): f\xF6rv\xE4ntade ${e.origin??"v\xE4rdet"} att ha ${o}${e.minimum.toString()} ${a.unit}`:`F\xF6r lite(t): f\xF6rv\xE4ntade ${e.origin??"v\xE4rdet"} att ha ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Ogiltig str\xE4ng: m\xE5ste b\xF6rja med "${o.prefix}"`:o.format==="ends_with"?`Ogiltig str\xE4ng: m\xE5ste sluta med "${o.suffix}"`:o.format==="includes"?`Ogiltig str\xE4ng: m\xE5ste inneh\xE5lla "${o.includes}"`:o.format==="regex"?`Ogiltig str\xE4ng: m\xE5ste matcha m\xF6nstret "${o.pattern}"`:`Ogiltig(t) ${n[o.format]??e.format}`}case"not_multiple_of":return`Ogiltigt tal: m\xE5ste vara en multipel av ${e.divisor}`;case"unrecognized_keys":return`${e.keys.length>1?"Ok\xE4nda nycklar":"Ok\xE4nd nyckel"}: ${f(e.keys,", ")}`;case"invalid_key":return`Ogiltig nyckel i ${e.origin??"v\xE4rdet"}`;case"invalid_union":return"Ogiltig input";case"invalid_element":return`Ogiltigt v\xE4rde i ${e.origin??"v\xE4rdet"}`;default:return"Ogiltig input"}}}});function Qm(){return{localeError:Gh()}}var Gh,Xm=x(()=>{w();Gh=()=>{let t={string:{unit:"\u0B8E\u0BB4\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1\u0B95\u0BCD\u0B95\u0BB3\u0BCD",verb:"\u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BBF\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD"},file:{unit:"\u0BAA\u0BC8\u0B9F\u0BCD\u0B9F\u0BC1\u0B95\u0BB3\u0BCD",verb:"\u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BBF\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD"},array:{unit:"\u0B89\u0BB1\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD",verb:"\u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BBF\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD"},set:{unit:"\u0B89\u0BB1\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD",verb:"\u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BBF\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD"}};function r(e){return t[e]??null}let n={regex:"\u0B89\u0BB3\u0BCD\u0BB3\u0BC0\u0B9F\u0BC1",email:"\u0BAE\u0BBF\u0BA9\u0BCD\u0BA9\u0B9E\u0BCD\u0B9A\u0BB2\u0BCD \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u0BA4\u0BC7\u0BA4\u0BBF \u0BA8\u0BC7\u0BB0\u0BAE\u0BCD",date:"ISO \u0BA4\u0BC7\u0BA4\u0BBF",time:"ISO \u0BA8\u0BC7\u0BB0\u0BAE\u0BCD",duration:"ISO \u0B95\u0BBE\u0BB2 \u0B85\u0BB3\u0BB5\u0BC1",ipv4:"IPv4 \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF",ipv6:"IPv6 \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF",cidrv4:"IPv4 \u0BB5\u0BB0\u0BAE\u0BCD\u0BAA\u0BC1",cidrv6:"IPv6 \u0BB5\u0BB0\u0BAE\u0BCD\u0BAA\u0BC1",base64:"base64-encoded \u0B9A\u0BB0\u0BAE\u0BCD",base64url:"base64url-encoded \u0B9A\u0BB0\u0BAE\u0BCD",json_string:"JSON \u0B9A\u0BB0\u0BAE\u0BCD",e164:"E.164 \u0B8E\u0BA3\u0BCD",jwt:"JWT",template_literal:"input"},i={nan:"NaN",number:"\u0B8E\u0BA3\u0BCD",array:"\u0B85\u0BA3\u0BBF",null:"\u0BB5\u0BC6\u0BB1\u0BC1\u0BAE\u0BC8"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B89\u0BB3\u0BCD\u0BB3\u0BC0\u0B9F\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 instanceof ${e.expected}, \u0BAA\u0BC6\u0BB1\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${s}`:`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B89\u0BB3\u0BCD\u0BB3\u0BC0\u0B9F\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${o}, \u0BAA\u0BC6\u0BB1\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${s}`}case"invalid_value":return e.values.length===1?`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B89\u0BB3\u0BCD\u0BB3\u0BC0\u0B9F\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${y(e.values[0])}`:`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0BB5\u0BBF\u0BB0\u0BC1\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${f(e.values,"|")} \u0B87\u0BB2\u0BCD \u0B92\u0BA9\u0BCD\u0BB1\u0BC1`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u0BAE\u0BBF\u0B95 \u0BAA\u0BC6\u0BB0\u0BBF\u0BAF\u0BA4\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${e.origin??"\u0BAE\u0BA4\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1"} ${o}${e.maximum.toString()} ${a.unit??"\u0B89\u0BB1\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD"} \u0B86\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`:`\u0BAE\u0BBF\u0B95 \u0BAA\u0BC6\u0BB0\u0BBF\u0BAF\u0BA4\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${e.origin??"\u0BAE\u0BA4\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1"} ${o}${e.maximum.toString()} \u0B86\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u0BAE\u0BBF\u0B95\u0B9A\u0BCD \u0B9A\u0BBF\u0BB1\u0BBF\u0BAF\u0BA4\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${e.origin} ${o}${e.minimum.toString()} ${a.unit} \u0B86\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`:`\u0BAE\u0BBF\u0B95\u0B9A\u0BCD \u0B9A\u0BBF\u0BB1\u0BBF\u0BAF\u0BA4\u0BC1: \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1 ${e.origin} ${o}${e.minimum.toString()} \u0B86\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B9A\u0BB0\u0BAE\u0BCD: "${o.prefix}" \u0B87\u0BB2\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`:o.format==="ends_with"?`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B9A\u0BB0\u0BAE\u0BCD: "${o.suffix}" \u0B87\u0BB2\u0BCD \u0BAE\u0BC1\u0B9F\u0BBF\u0BB5\u0B9F\u0BC8\u0BAF \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`:o.format==="includes"?`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B9A\u0BB0\u0BAE\u0BCD: "${o.includes}" \u0B90 \u0B89\u0BB3\u0BCD\u0BB3\u0B9F\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`:o.format==="regex"?`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B9A\u0BB0\u0BAE\u0BCD: ${o.pattern} \u0BAE\u0BC1\u0BB1\u0BC8\u0BAA\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1\u0B9F\u0BA9\u0BCD \u0BAA\u0BCA\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`:`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B8E\u0BA3\u0BCD: ${e.divisor} \u0B87\u0BA9\u0BCD \u0BAA\u0BB2\u0BAE\u0BBE\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD`;case"unrecognized_keys":return`\u0B85\u0B9F\u0BC8\u0BAF\u0BBE\u0BB3\u0BAE\u0BCD \u0BA4\u0BC6\u0BB0\u0BBF\u0BAF\u0BBE\u0BA4 \u0BB5\u0BBF\u0B9A\u0BC8${e.keys.length>1?"\u0B95\u0BB3\u0BCD":""}: ${f(e.keys,", ")}`;case"invalid_key":return`${e.origin} \u0B87\u0BB2\u0BCD \u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0BB5\u0BBF\u0B9A\u0BC8`;case"invalid_union":return"\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B89\u0BB3\u0BCD\u0BB3\u0BC0\u0B9F\u0BC1";case"invalid_element":return`${e.origin} \u0B87\u0BB2\u0BCD \u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0BAE\u0BA4\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1`;default:return"\u0BA4\u0BB5\u0BB1\u0BBE\u0BA9 \u0B89\u0BB3\u0BCD\u0BB3\u0BC0\u0B9F\u0BC1"}}}});function Ym(){return{localeError:Qh()}}var Qh,ef=x(()=>{w();Qh=()=>{let t={string:{unit:"\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23",verb:"\u0E04\u0E27\u0E23\u0E21\u0E35"},file:{unit:"\u0E44\u0E1A\u0E15\u0E4C",verb:"\u0E04\u0E27\u0E23\u0E21\u0E35"},array:{unit:"\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23",verb:"\u0E04\u0E27\u0E23\u0E21\u0E35"},set:{unit:"\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23",verb:"\u0E04\u0E27\u0E23\u0E21\u0E35"}};function r(e){return t[e]??null}let n={regex:"\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E1B\u0E49\u0E2D\u0E19",email:"\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E2D\u0E35\u0E40\u0E21\u0E25",url:"URL",emoji:"\u0E2D\u0E34\u0E42\u0E21\u0E08\u0E34",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO",date:"\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E41\u0E1A\u0E1A ISO",time:"\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO",duration:"\u0E0A\u0E48\u0E27\u0E07\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO",ipv4:"\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IPv4",ipv6:"\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IPv6",cidrv4:"\u0E0A\u0E48\u0E27\u0E07 IP \u0E41\u0E1A\u0E1A IPv4",cidrv6:"\u0E0A\u0E48\u0E27\u0E07 IP \u0E41\u0E1A\u0E1A IPv6",base64:"\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A Base64",base64url:"\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A Base64 \u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A URL",json_string:"\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A JSON",e164:"\u0E40\u0E1A\u0E2D\u0E23\u0E4C\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07\u0E1B\u0E23\u0E30\u0E40\u0E17\u0E28 (E.164)",jwt:"\u0E42\u0E17\u0E40\u0E04\u0E19 JWT",template_literal:"\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E1B\u0E49\u0E2D\u0E19"},i={nan:"NaN",number:"\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02",array:"\u0E2D\u0E32\u0E23\u0E4C\u0E40\u0E23\u0E22\u0E4C (Array)",null:"\u0E44\u0E21\u0E48\u0E21\u0E35\u0E04\u0E48\u0E32 (null)"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0E1B\u0E23\u0E30\u0E40\u0E20\u0E17\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E04\u0E27\u0E23\u0E40\u0E1B\u0E47\u0E19 instanceof ${e.expected} \u0E41\u0E15\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A ${s}`:`\u0E1B\u0E23\u0E30\u0E40\u0E20\u0E17\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E04\u0E27\u0E23\u0E40\u0E1B\u0E47\u0E19 ${o} \u0E41\u0E15\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A ${s}`}case"invalid_value":return e.values.length===1?`\u0E04\u0E48\u0E32\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E04\u0E27\u0E23\u0E40\u0E1B\u0E47\u0E19 ${y(e.values[0])}`:`\u0E15\u0E31\u0E27\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E04\u0E27\u0E23\u0E40\u0E1B\u0E47\u0E19\u0E2B\u0E19\u0E36\u0E48\u0E07\u0E43\u0E19 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19":"\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32",a=r(e.origin);return a?`\u0E40\u0E01\u0E34\u0E19\u0E01\u0E33\u0E2B\u0E19\u0E14: ${e.origin??"\u0E04\u0E48\u0E32"} \u0E04\u0E27\u0E23\u0E21\u0E35${o} ${e.maximum.toString()} ${a.unit??"\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23"}`:`\u0E40\u0E01\u0E34\u0E19\u0E01\u0E33\u0E2B\u0E19\u0E14: ${e.origin??"\u0E04\u0E48\u0E32"} \u0E04\u0E27\u0E23\u0E21\u0E35${o} ${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?"\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22":"\u0E21\u0E32\u0E01\u0E01\u0E27\u0E48\u0E32",a=r(e.origin);return a?`\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32\u0E01\u0E33\u0E2B\u0E19\u0E14: ${e.origin} \u0E04\u0E27\u0E23\u0E21\u0E35${o} ${e.minimum.toString()} ${a.unit}`:`\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32\u0E01\u0E33\u0E2B\u0E19\u0E14: ${e.origin} \u0E04\u0E27\u0E23\u0E21\u0E35${o} ${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E15\u0E49\u0E2D\u0E07\u0E02\u0E36\u0E49\u0E19\u0E15\u0E49\u0E19\u0E14\u0E49\u0E27\u0E22 "${o.prefix}"`:o.format==="ends_with"?`\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E15\u0E49\u0E2D\u0E07\u0E25\u0E07\u0E17\u0E49\u0E32\u0E22\u0E14\u0E49\u0E27\u0E22 "${o.suffix}"`:o.format==="includes"?`\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35 "${o.includes}" \u0E2D\u0E22\u0E39\u0E48\u0E43\u0E19\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21`:o.format==="regex"?`\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E15\u0E49\u0E2D\u0E07\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E17\u0E35\u0E48\u0E01\u0E33\u0E2B\u0E19\u0E14 ${o.pattern}`:`\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: ${n[o.format]??e.format}`}case"not_multiple_of":return`\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E08\u0E33\u0E19\u0E27\u0E19\u0E17\u0E35\u0E48\u0E2B\u0E32\u0E23\u0E14\u0E49\u0E27\u0E22 ${e.divisor} \u0E44\u0E14\u0E49\u0E25\u0E07\u0E15\u0E31\u0E27`;case"unrecognized_keys":return`\u0E1E\u0E1A\u0E04\u0E35\u0E22\u0E4C\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E23\u0E39\u0E49\u0E08\u0E31\u0E01: ${f(e.keys,", ")}`;case"invalid_key":return`\u0E04\u0E35\u0E22\u0E4C\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E43\u0E19 ${e.origin}`;case"invalid_union":return"\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E22\u0E39\u0E40\u0E19\u0E35\u0E22\u0E19\u0E17\u0E35\u0E48\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49";case"invalid_element":return`\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E43\u0E19 ${e.origin}`;default:return"\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07"}}}});function tf(){return{localeError:Xh()}}var Xh,rf=x(()=>{w();Xh=()=>{let t={string:{unit:"karakter",verb:"olmal\u0131"},file:{unit:"bayt",verb:"olmal\u0131"},array:{unit:"\xF6\u011Fe",verb:"olmal\u0131"},set:{unit:"\xF6\u011Fe",verb:"olmal\u0131"}};function r(e){return t[e]??null}let n={regex:"girdi",email:"e-posta adresi",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO tarih ve saat",date:"ISO tarih",time:"ISO saat",duration:"ISO s\xFCre",ipv4:"IPv4 adresi",ipv6:"IPv6 adresi",cidrv4:"IPv4 aral\u0131\u011F\u0131",cidrv6:"IPv6 aral\u0131\u011F\u0131",base64:"base64 ile \u015Fifrelenmi\u015F metin",base64url:"base64url ile \u015Fifrelenmi\u015F metin",json_string:"JSON dizesi",e164:"E.164 say\u0131s\u0131",jwt:"JWT",template_literal:"\u015Eablon dizesi"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Ge\xE7ersiz de\u011Fer: beklenen instanceof ${e.expected}, al\u0131nan ${s}`:`Ge\xE7ersiz de\u011Fer: beklenen ${o}, al\u0131nan ${s}`}case"invalid_value":return e.values.length===1?`Ge\xE7ersiz de\u011Fer: beklenen ${y(e.values[0])}`:`Ge\xE7ersiz se\xE7enek: a\u015Fa\u011F\u0131dakilerden biri olmal\u0131: ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\xC7ok b\xFCy\xFCk: beklenen ${e.origin??"de\u011Fer"} ${o}${e.maximum.toString()} ${a.unit??"\xF6\u011Fe"}`:`\xC7ok b\xFCy\xFCk: beklenen ${e.origin??"de\u011Fer"} ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\xC7ok k\xFC\xE7\xFCk: beklenen ${e.origin} ${o}${e.minimum.toString()} ${a.unit}`:`\xC7ok k\xFC\xE7\xFCk: beklenen ${e.origin} ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Ge\xE7ersiz metin: "${o.prefix}" ile ba\u015Flamal\u0131`:o.format==="ends_with"?`Ge\xE7ersiz metin: "${o.suffix}" ile bitmeli`:o.format==="includes"?`Ge\xE7ersiz metin: "${o.includes}" i\xE7ermeli`:o.format==="regex"?`Ge\xE7ersiz metin: ${o.pattern} desenine uymal\u0131`:`Ge\xE7ersiz ${n[o.format]??e.format}`}case"not_multiple_of":return`Ge\xE7ersiz say\u0131: ${e.divisor} ile tam b\xF6l\xFCnebilmeli`;case"unrecognized_keys":return`Tan\u0131nmayan anahtar${e.keys.length>1?"lar":""}: ${f(e.keys,", ")}`;case"invalid_key":return`${e.origin} i\xE7inde ge\xE7ersiz anahtar`;case"invalid_union":return"Ge\xE7ersiz de\u011Fer";case"invalid_element":return`${e.origin} i\xE7inde ge\xE7ersiz de\u011Fer`;default:return"Ge\xE7ersiz de\u011Fer"}}}});function Yn(){return{localeError:Yh()}}var Yh,$c=x(()=>{w();Yh=()=>{let t={string:{unit:"\u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432",verb:"\u043C\u0430\u0442\u0438\u043C\u0435"},file:{unit:"\u0431\u0430\u0439\u0442\u0456\u0432",verb:"\u043C\u0430\u0442\u0438\u043C\u0435"},array:{unit:"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432",verb:"\u043C\u0430\u0442\u0438\u043C\u0435"},set:{unit:"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432",verb:"\u043C\u0430\u0442\u0438\u043C\u0435"}};function r(e){return t[e]??null}let n={regex:"\u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456",email:"\u0430\u0434\u0440\u0435\u0441\u0430 \u0435\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0457 \u043F\u043E\u0448\u0442\u0438",url:"URL",emoji:"\u0435\u043C\u043E\u0434\u0437\u0456",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\u0434\u0430\u0442\u0430 \u0442\u0430 \u0447\u0430\u0441 ISO",date:"\u0434\u0430\u0442\u0430 ISO",time:"\u0447\u0430\u0441 ISO",duration:"\u0442\u0440\u0438\u0432\u0430\u043B\u0456\u0441\u0442\u044C ISO",ipv4:"\u0430\u0434\u0440\u0435\u0441\u0430 IPv4",ipv6:"\u0430\u0434\u0440\u0435\u0441\u0430 IPv6",cidrv4:"\u0434\u0456\u0430\u043F\u0430\u0437\u043E\u043D IPv4",cidrv6:"\u0434\u0456\u0430\u043F\u0430\u0437\u043E\u043D IPv6",base64:"\u0440\u044F\u0434\u043E\u043A \u0443 \u043A\u043E\u0434\u0443\u0432\u0430\u043D\u043D\u0456 base64",base64url:"\u0440\u044F\u0434\u043E\u043A \u0443 \u043A\u043E\u0434\u0443\u0432\u0430\u043D\u043D\u0456 base64url",json_string:"\u0440\u044F\u0434\u043E\u043A JSON",e164:"\u043D\u043E\u043C\u0435\u0440 E.164",jwt:"JWT",template_literal:"\u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456"},i={nan:"NaN",number:"\u0447\u0438\u0441\u043B\u043E",array:"\u043C\u0430\u0441\u0438\u0432"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0456 \u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F instanceof ${e.expected}, \u043E\u0442\u0440\u0438\u043C\u0430\u043D\u043E ${s}`:`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0456 \u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F ${o}, \u043E\u0442\u0440\u0438\u043C\u0430\u043D\u043E ${s}`}case"invalid_value":return e.values.length===1?`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0456 \u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F ${y(e.values[0])}`:`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0430 \u043E\u043F\u0446\u0456\u044F: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F \u043E\u0434\u043D\u0435 \u0437 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u0417\u0430\u043D\u0430\u0434\u0442\u043E \u0432\u0435\u043B\u0438\u043A\u0435: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F, \u0449\u043E ${e.origin??"\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F"} ${a.verb} ${o}${e.maximum.toString()} ${a.unit??"\u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432"}`:`\u0417\u0430\u043D\u0430\u0434\u0442\u043E \u0432\u0435\u043B\u0438\u043A\u0435: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F, \u0449\u043E ${e.origin??"\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F"} \u0431\u0443\u0434\u0435 ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u0417\u0430\u043D\u0430\u0434\u0442\u043E \u043C\u0430\u043B\u0435: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F, \u0449\u043E ${e.origin} ${a.verb} ${o}${e.minimum.toString()} ${a.unit}`:`\u0417\u0430\u043D\u0430\u0434\u0442\u043E \u043C\u0430\u043B\u0435: \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F, \u0449\u043E ${e.origin} \u0431\u0443\u0434\u0435 ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0438\u0439 \u0440\u044F\u0434\u043E\u043A: \u043F\u043E\u0432\u0438\u043D\u0435\u043D \u043F\u043E\u0447\u0438\u043D\u0430\u0442\u0438\u0441\u044F \u0437 "${o.prefix}"`:o.format==="ends_with"?`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0438\u0439 \u0440\u044F\u0434\u043E\u043A: \u043F\u043E\u0432\u0438\u043D\u0435\u043D \u0437\u0430\u043A\u0456\u043D\u0447\u0443\u0432\u0430\u0442\u0438\u0441\u044F \u043D\u0430 "${o.suffix}"`:o.format==="includes"?`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0438\u0439 \u0440\u044F\u0434\u043E\u043A: \u043F\u043E\u0432\u0438\u043D\u0435\u043D \u043C\u0456\u0441\u0442\u0438\u0442\u0438 "${o.includes}"`:o.format==="regex"?`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0438\u0439 \u0440\u044F\u0434\u043E\u043A: \u043F\u043E\u0432\u0438\u043D\u0435\u043D \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0442\u0438 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 ${o.pattern}`:`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0438\u0439 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0435 \u0447\u0438\u0441\u043B\u043E: \u043F\u043E\u0432\u0438\u043D\u043D\u043E \u0431\u0443\u0442\u0438 \u043A\u0440\u0430\u0442\u043D\u0438\u043C ${e.divisor}`;case"unrecognized_keys":return`\u041D\u0435\u0440\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0438\u0439 \u043A\u043B\u044E\u0447${e.keys.length>1?"\u0456":""}: ${f(e.keys,", ")}`;case"invalid_key":return`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0438\u0439 \u043A\u043B\u044E\u0447 \u0443 ${e.origin}`;case"invalid_union":return"\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0456 \u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456";case"invalid_element":return`\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0443 ${e.origin}`;default:return"\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0456 \u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456"}}}});function nf(){return Yn()}var of=x(()=>{$c()});function af(){return{localeError:ev()}}var ev,sf=x(()=>{w();ev=()=>{let t={string:{unit:"\u062D\u0631\u0648\u0641",verb:"\u06C1\u0648\u0646\u0627"},file:{unit:"\u0628\u0627\u0626\u0679\u0633",verb:"\u06C1\u0648\u0646\u0627"},array:{unit:"\u0622\u0626\u0679\u0645\u0632",verb:"\u06C1\u0648\u0646\u0627"},set:{unit:"\u0622\u0626\u0679\u0645\u0632",verb:"\u06C1\u0648\u0646\u0627"}};function r(e){return t[e]??null}let n={regex:"\u0627\u0646 \u067E\u0679",email:"\u0627\u06CC \u0645\u06CC\u0644 \u0627\u06CC\u0688\u0631\u06CC\u0633",url:"\u06CC\u0648 \u0622\u0631 \u0627\u06CC\u0644",emoji:"\u0627\u06CC\u0645\u0648\u062C\u06CC",uuid:"\u06CC\u0648 \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC",uuidv4:"\u06CC\u0648 \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC \u0648\u06CC 4",uuidv6:"\u06CC\u0648 \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC \u0648\u06CC 6",nanoid:"\u0646\u06CC\u0646\u0648 \u0622\u0626\u06CC \u0688\u06CC",guid:"\u062C\u06CC \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC",cuid:"\u0633\u06CC \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC",cuid2:"\u0633\u06CC \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC 2",ulid:"\u06CC\u0648 \u0627\u06CC\u0644 \u0622\u0626\u06CC \u0688\u06CC",xid:"\u0627\u06CC\u06A9\u0633 \u0622\u0626\u06CC \u0688\u06CC",ksuid:"\u06A9\u06D2 \u0627\u06CC\u0633 \u06CC\u0648 \u0622\u0626\u06CC \u0688\u06CC",datetime:"\u0622\u0626\u06CC \u0627\u06CC\u0633 \u0627\u0648 \u0688\u06CC\u0679 \u0679\u0627\u0626\u0645",date:"\u0622\u0626\u06CC \u0627\u06CC\u0633 \u0627\u0648 \u062A\u0627\u0631\u06CC\u062E",time:"\u0622\u0626\u06CC \u0627\u06CC\u0633 \u0627\u0648 \u0648\u0642\u062A",duration:"\u0622\u0626\u06CC \u0627\u06CC\u0633 \u0627\u0648 \u0645\u062F\u062A",ipv4:"\u0622\u0626\u06CC \u067E\u06CC \u0648\u06CC 4 \u0627\u06CC\u0688\u0631\u06CC\u0633",ipv6:"\u0622\u0626\u06CC \u067E\u06CC \u0648\u06CC 6 \u0627\u06CC\u0688\u0631\u06CC\u0633",cidrv4:"\u0622\u0626\u06CC \u067E\u06CC \u0648\u06CC 4 \u0631\u06CC\u0646\u062C",cidrv6:"\u0622\u0626\u06CC \u067E\u06CC \u0648\u06CC 6 \u0631\u06CC\u0646\u062C",base64:"\u0628\u06CC\u0633 64 \u0627\u0646 \u06A9\u0648\u0688\u0688 \u0633\u0679\u0631\u0646\u06AF",base64url:"\u0628\u06CC\u0633 64 \u06CC\u0648 \u0622\u0631 \u0627\u06CC\u0644 \u0627\u0646 \u06A9\u0648\u0688\u0688 \u0633\u0679\u0631\u0646\u06AF",json_string:"\u062C\u06D2 \u0627\u06CC\u0633 \u0627\u0648 \u0627\u06CC\u0646 \u0633\u0679\u0631\u0646\u06AF",e164:"\u0627\u06CC 164 \u0646\u0645\u0628\u0631",jwt:"\u062C\u06D2 \u0688\u0628\u0644\u06CC\u0648 \u0679\u06CC",template_literal:"\u0627\u0646 \u067E\u0679"},i={nan:"NaN",number:"\u0646\u0645\u0628\u0631",array:"\u0622\u0631\u06D2",null:"\u0646\u0644"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u063A\u0644\u0637 \u0627\u0646 \u067E\u0679: instanceof ${e.expected} \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u0627\u060C ${s} \u0645\u0648\u0635\u0648\u0644 \u06C1\u0648\u0627`:`\u063A\u0644\u0637 \u0627\u0646 \u067E\u0679: ${o} \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u0627\u060C ${s} \u0645\u0648\u0635\u0648\u0644 \u06C1\u0648\u0627`}case"invalid_value":return e.values.length===1?`\u063A\u0644\u0637 \u0627\u0646 \u067E\u0679: ${y(e.values[0])} \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u0627`:`\u063A\u0644\u0637 \u0622\u067E\u0634\u0646: ${f(e.values,"|")} \u0645\u06CC\u06BA \u0633\u06D2 \u0627\u06CC\u06A9 \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u0627`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u0628\u06C1\u062A \u0628\u0691\u0627: ${e.origin??"\u0648\u06CC\u0644\u06CC\u0648"} \u06A9\u06D2 ${o}${e.maximum.toString()} ${a.unit??"\u0639\u0646\u0627\u0635\u0631"} \u06C1\u0648\u0646\u06D2 \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u06D2`:`\u0628\u06C1\u062A \u0628\u0691\u0627: ${e.origin??"\u0648\u06CC\u0644\u06CC\u0648"} \u06A9\u0627 ${o}${e.maximum.toString()} \u06C1\u0648\u0646\u0627 \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u0627`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u0628\u06C1\u062A \u0686\u06BE\u0648\u0679\u0627: ${e.origin} \u06A9\u06D2 ${o}${e.minimum.toString()} ${a.unit} \u06C1\u0648\u0646\u06D2 \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u06D2`:`\u0628\u06C1\u062A \u0686\u06BE\u0648\u0679\u0627: ${e.origin} \u06A9\u0627 ${o}${e.minimum.toString()} \u06C1\u0648\u0646\u0627 \u0645\u062A\u0648\u0642\u0639 \u062A\u06BE\u0627`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u063A\u0644\u0637 \u0633\u0679\u0631\u0646\u06AF: "${o.prefix}" \u0633\u06D2 \u0634\u0631\u0648\u0639 \u06C1\u0648\u0646\u0627 \u0686\u0627\u06C1\u06CC\u06D2`:o.format==="ends_with"?`\u063A\u0644\u0637 \u0633\u0679\u0631\u0646\u06AF: "${o.suffix}" \u067E\u0631 \u062E\u062A\u0645 \u06C1\u0648\u0646\u0627 \u0686\u0627\u06C1\u06CC\u06D2`:o.format==="includes"?`\u063A\u0644\u0637 \u0633\u0679\u0631\u0646\u06AF: "${o.includes}" \u0634\u0627\u0645\u0644 \u06C1\u0648\u0646\u0627 \u0686\u0627\u06C1\u06CC\u06D2`:o.format==="regex"?`\u063A\u0644\u0637 \u0633\u0679\u0631\u0646\u06AF: \u067E\u06CC\u0679\u0631\u0646 ${o.pattern} \u0633\u06D2 \u0645\u06CC\u0686 \u06C1\u0648\u0646\u0627 \u0686\u0627\u06C1\u06CC\u06D2`:`\u063A\u0644\u0637 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u063A\u0644\u0637 \u0646\u0645\u0628\u0631: ${e.divisor} \u06A9\u0627 \u0645\u0636\u0627\u0639\u0641 \u06C1\u0648\u0646\u0627 \u0686\u0627\u06C1\u06CC\u06D2`;case"unrecognized_keys":return`\u063A\u06CC\u0631 \u062A\u0633\u0644\u06CC\u0645 \u0634\u062F\u06C1 \u06A9\u06CC${e.keys.length>1?"\u0632":""}: ${f(e.keys,"\u060C ")}`;case"invalid_key":return`${e.origin} \u0645\u06CC\u06BA \u063A\u0644\u0637 \u06A9\u06CC`;case"invalid_union":return"\u063A\u0644\u0637 \u0627\u0646 \u067E\u0679";case"invalid_element":return`${e.origin} \u0645\u06CC\u06BA \u063A\u0644\u0637 \u0648\u06CC\u0644\u06CC\u0648`;default:return"\u063A\u0644\u0637 \u0627\u0646 \u067E\u0679"}}}});function cf(){return{localeError:tv()}}var tv,uf=x(()=>{w();tv=()=>{let t={string:{unit:"belgi",verb:"bo\u2018lishi kerak"},file:{unit:"bayt",verb:"bo\u2018lishi kerak"},array:{unit:"element",verb:"bo\u2018lishi kerak"},set:{unit:"element",verb:"bo\u2018lishi kerak"},map:{unit:"yozuv",verb:"bo\u2018lishi kerak"}};function r(e){return t[e]??null}let n={regex:"kirish",email:"elektron pochta manzili",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO sana va vaqti",date:"ISO sana",time:"ISO vaqt",duration:"ISO davomiylik",ipv4:"IPv4 manzil",ipv6:"IPv6 manzil",mac:"MAC manzil",cidrv4:"IPv4 diapazon",cidrv6:"IPv6 diapazon",base64:"base64 kodlangan satr",base64url:"base64url kodlangan satr",json_string:"JSON satr",e164:"E.164 raqam",jwt:"JWT",template_literal:"kirish"},i={nan:"NaN",number:"raqam",array:"massiv"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`Noto\u2018g\u2018ri kirish: kutilgan instanceof ${e.expected}, qabul qilingan ${s}`:`Noto\u2018g\u2018ri kirish: kutilgan ${o}, qabul qilingan ${s}`}case"invalid_value":return e.values.length===1?`Noto\u2018g\u2018ri kirish: kutilgan ${y(e.values[0])}`:`Noto\u2018g\u2018ri variant: quyidagilardan biri kutilgan ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Juda katta: kutilgan ${e.origin??"qiymat"} ${o}${e.maximum.toString()} ${a.unit} ${a.verb}`:`Juda katta: kutilgan ${e.origin??"qiymat"} ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Juda kichik: kutilgan ${e.origin} ${o}${e.minimum.toString()} ${a.unit} ${a.verb}`:`Juda kichik: kutilgan ${e.origin} ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Noto\u2018g\u2018ri satr: "${o.prefix}" bilan boshlanishi kerak`:o.format==="ends_with"?`Noto\u2018g\u2018ri satr: "${o.suffix}" bilan tugashi kerak`:o.format==="includes"?`Noto\u2018g\u2018ri satr: "${o.includes}" ni o\u2018z ichiga olishi kerak`:o.format==="regex"?`Noto\u2018g\u2018ri satr: ${o.pattern} shabloniga mos kelishi kerak`:`Noto\u2018g\u2018ri ${n[o.format]??e.format}`}case"not_multiple_of":return`Noto\u2018g\u2018ri raqam: ${e.divisor} ning karralisi bo\u2018lishi kerak`;case"unrecognized_keys":return`Noma\u2019lum kalit${e.keys.length>1?"lar":""}: ${f(e.keys,", ")}`;case"invalid_key":return`${e.origin} dagi kalit noto\u2018g\u2018ri`;case"invalid_union":return"Noto\u2018g\u2018ri kirish";case"invalid_element":return`${e.origin} da noto\u2018g\u2018ri qiymat`;default:return"Noto\u2018g\u2018ri kirish"}}}});function lf(){return{localeError:rv()}}var rv,df=x(()=>{w();rv=()=>{let t={string:{unit:"k\xFD t\u1EF1",verb:"c\xF3"},file:{unit:"byte",verb:"c\xF3"},array:{unit:"ph\u1EA7n t\u1EED",verb:"c\xF3"},set:{unit:"ph\u1EA7n t\u1EED",verb:"c\xF3"}};function r(e){return t[e]??null}let n={regex:"\u0111\u1EA7u v\xE0o",email:"\u0111\u1ECBa ch\u1EC9 email",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ng\xE0y gi\u1EDD ISO",date:"ng\xE0y ISO",time:"gi\u1EDD ISO",duration:"kho\u1EA3ng th\u1EDDi gian ISO",ipv4:"\u0111\u1ECBa ch\u1EC9 IPv4",ipv6:"\u0111\u1ECBa ch\u1EC9 IPv6",cidrv4:"d\u1EA3i IPv4",cidrv6:"d\u1EA3i IPv6",base64:"chu\u1ED7i m\xE3 h\xF3a base64",base64url:"chu\u1ED7i m\xE3 h\xF3a base64url",json_string:"chu\u1ED7i JSON",e164:"s\u1ED1 E.164",jwt:"JWT",template_literal:"\u0111\u1EA7u v\xE0o"},i={nan:"NaN",number:"s\u1ED1",array:"m\u1EA3ng"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u0110\u1EA7u v\xE0o kh\xF4ng h\u1EE3p l\u1EC7: mong \u0111\u1EE3i instanceof ${e.expected}, nh\u1EADn \u0111\u01B0\u1EE3c ${s}`:`\u0110\u1EA7u v\xE0o kh\xF4ng h\u1EE3p l\u1EC7: mong \u0111\u1EE3i ${o}, nh\u1EADn \u0111\u01B0\u1EE3c ${s}`}case"invalid_value":return e.values.length===1?`\u0110\u1EA7u v\xE0o kh\xF4ng h\u1EE3p l\u1EC7: mong \u0111\u1EE3i ${y(e.values[0])}`:`T\xF9y ch\u1ECDn kh\xF4ng h\u1EE3p l\u1EC7: mong \u0111\u1EE3i m\u1ED9t trong c\xE1c gi\xE1 tr\u1ECB ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`Qu\xE1 l\u1EDBn: mong \u0111\u1EE3i ${e.origin??"gi\xE1 tr\u1ECB"} ${a.verb} ${o}${e.maximum.toString()} ${a.unit??"ph\u1EA7n t\u1EED"}`:`Qu\xE1 l\u1EDBn: mong \u0111\u1EE3i ${e.origin??"gi\xE1 tr\u1ECB"} ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`Qu\xE1 nh\u1ECF: mong \u0111\u1EE3i ${e.origin} ${a.verb} ${o}${e.minimum.toString()} ${a.unit}`:`Qu\xE1 nh\u1ECF: mong \u0111\u1EE3i ${e.origin} ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`Chu\u1ED7i kh\xF4ng h\u1EE3p l\u1EC7: ph\u1EA3i b\u1EAFt \u0111\u1EA7u b\u1EB1ng "${o.prefix}"`:o.format==="ends_with"?`Chu\u1ED7i kh\xF4ng h\u1EE3p l\u1EC7: ph\u1EA3i k\u1EBFt th\xFAc b\u1EB1ng "${o.suffix}"`:o.format==="includes"?`Chu\u1ED7i kh\xF4ng h\u1EE3p l\u1EC7: ph\u1EA3i bao g\u1ED3m "${o.includes}"`:o.format==="regex"?`Chu\u1ED7i kh\xF4ng h\u1EE3p l\u1EC7: ph\u1EA3i kh\u1EDBp v\u1EDBi m\u1EABu ${o.pattern}`:`${n[o.format]??e.format} kh\xF4ng h\u1EE3p l\u1EC7`}case"not_multiple_of":return`S\u1ED1 kh\xF4ng h\u1EE3p l\u1EC7: ph\u1EA3i l\xE0 b\u1ED9i s\u1ED1 c\u1EE7a ${e.divisor}`;case"unrecognized_keys":return`Kh\xF3a kh\xF4ng \u0111\u01B0\u1EE3c nh\u1EADn d\u1EA1ng: ${f(e.keys,", ")}`;case"invalid_key":return`Kh\xF3a kh\xF4ng h\u1EE3p l\u1EC7 trong ${e.origin}`;case"invalid_union":return"\u0110\u1EA7u v\xE0o kh\xF4ng h\u1EE3p l\u1EC7";case"invalid_element":return`Gi\xE1 tr\u1ECB kh\xF4ng h\u1EE3p l\u1EC7 trong ${e.origin}`;default:return"\u0110\u1EA7u v\xE0o kh\xF4ng h\u1EE3p l\u1EC7"}}}});function pf(){return{localeError:nv()}}var nv,mf=x(()=>{w();nv=()=>{let t={string:{unit:"\u5B57\u7B26",verb:"\u5305\u542B"},file:{unit:"\u5B57\u8282",verb:"\u5305\u542B"},array:{unit:"\u9879",verb:"\u5305\u542B"},set:{unit:"\u9879",verb:"\u5305\u542B"}};function r(e){return t[e]??null}let n={regex:"\u8F93\u5165",email:"\u7535\u5B50\u90AE\u4EF6",url:"URL",emoji:"\u8868\u60C5\u7B26\u53F7",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO\u65E5\u671F\u65F6\u95F4",date:"ISO\u65E5\u671F",time:"ISO\u65F6\u95F4",duration:"ISO\u65F6\u957F",ipv4:"IPv4\u5730\u5740",ipv6:"IPv6\u5730\u5740",cidrv4:"IPv4\u7F51\u6BB5",cidrv6:"IPv6\u7F51\u6BB5",base64:"base64\u7F16\u7801\u5B57\u7B26\u4E32",base64url:"base64url\u7F16\u7801\u5B57\u7B26\u4E32",json_string:"JSON\u5B57\u7B26\u4E32",e164:"E.164\u53F7\u7801",jwt:"JWT",template_literal:"\u8F93\u5165"},i={nan:"NaN",number:"\u6570\u5B57",array:"\u6570\u7EC4",null:"\u7A7A\u503C(null)"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u65E0\u6548\u8F93\u5165\uFF1A\u671F\u671B instanceof ${e.expected}\uFF0C\u5B9E\u9645\u63A5\u6536 ${s}`:`\u65E0\u6548\u8F93\u5165\uFF1A\u671F\u671B ${o}\uFF0C\u5B9E\u9645\u63A5\u6536 ${s}`}case"invalid_value":return e.values.length===1?`\u65E0\u6548\u8F93\u5165\uFF1A\u671F\u671B ${y(e.values[0])}`:`\u65E0\u6548\u9009\u9879\uFF1A\u671F\u671B\u4EE5\u4E0B\u4E4B\u4E00 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u6570\u503C\u8FC7\u5927\uFF1A\u671F\u671B ${e.origin??"\u503C"} ${o}${e.maximum.toString()} ${a.unit??"\u4E2A\u5143\u7D20"}`:`\u6570\u503C\u8FC7\u5927\uFF1A\u671F\u671B ${e.origin??"\u503C"} ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u6570\u503C\u8FC7\u5C0F\uFF1A\u671F\u671B ${e.origin} ${o}${e.minimum.toString()} ${a.unit}`:`\u6570\u503C\u8FC7\u5C0F\uFF1A\u671F\u671B ${e.origin} ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u65E0\u6548\u5B57\u7B26\u4E32\uFF1A\u5FC5\u987B\u4EE5 "${o.prefix}" \u5F00\u5934`:o.format==="ends_with"?`\u65E0\u6548\u5B57\u7B26\u4E32\uFF1A\u5FC5\u987B\u4EE5 "${o.suffix}" \u7ED3\u5C3E`:o.format==="includes"?`\u65E0\u6548\u5B57\u7B26\u4E32\uFF1A\u5FC5\u987B\u5305\u542B "${o.includes}"`:o.format==="regex"?`\u65E0\u6548\u5B57\u7B26\u4E32\uFF1A\u5FC5\u987B\u6EE1\u8DB3\u6B63\u5219\u8868\u8FBE\u5F0F ${o.pattern}`:`\u65E0\u6548${n[o.format]??e.format}`}case"not_multiple_of":return`\u65E0\u6548\u6570\u5B57\uFF1A\u5FC5\u987B\u662F ${e.divisor} \u7684\u500D\u6570`;case"unrecognized_keys":return`\u51FA\u73B0\u672A\u77E5\u7684\u952E(key): ${f(e.keys,", ")}`;case"invalid_key":return`${e.origin} \u4E2D\u7684\u952E(key)\u65E0\u6548`;case"invalid_union":return"\u65E0\u6548\u8F93\u5165";case"invalid_element":return`${e.origin} \u4E2D\u5305\u542B\u65E0\u6548\u503C(value)`;default:return"\u65E0\u6548\u8F93\u5165"}}}});function ff(){return{localeError:ov()}}var ov,gf=x(()=>{w();ov=()=>{let t={string:{unit:"\u5B57\u5143",verb:"\u64C1\u6709"},file:{unit:"\u4F4D\u5143\u7D44",verb:"\u64C1\u6709"},array:{unit:"\u9805\u76EE",verb:"\u64C1\u6709"},set:{unit:"\u9805\u76EE",verb:"\u64C1\u6709"}};function r(e){return t[e]??null}let n={regex:"\u8F38\u5165",email:"\u90F5\u4EF6\u5730\u5740",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO \u65E5\u671F\u6642\u9593",date:"ISO \u65E5\u671F",time:"ISO \u6642\u9593",duration:"ISO \u671F\u9593",ipv4:"IPv4 \u4F4D\u5740",ipv6:"IPv6 \u4F4D\u5740",cidrv4:"IPv4 \u7BC4\u570D",cidrv6:"IPv6 \u7BC4\u570D",base64:"base64 \u7DE8\u78BC\u5B57\u4E32",base64url:"base64url \u7DE8\u78BC\u5B57\u4E32",json_string:"JSON \u5B57\u4E32",e164:"E.164 \u6578\u503C",jwt:"JWT",template_literal:"\u8F38\u5165"},i={nan:"NaN"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\u7121\u6548\u7684\u8F38\u5165\u503C\uFF1A\u9810\u671F\u70BA instanceof ${e.expected}\uFF0C\u4F46\u6536\u5230 ${s}`:`\u7121\u6548\u7684\u8F38\u5165\u503C\uFF1A\u9810\u671F\u70BA ${o}\uFF0C\u4F46\u6536\u5230 ${s}`}case"invalid_value":return e.values.length===1?`\u7121\u6548\u7684\u8F38\u5165\u503C\uFF1A\u9810\u671F\u70BA ${y(e.values[0])}`:`\u7121\u6548\u7684\u9078\u9805\uFF1A\u9810\u671F\u70BA\u4EE5\u4E0B\u5176\u4E2D\u4E4B\u4E00 ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`\u6578\u503C\u904E\u5927\uFF1A\u9810\u671F ${e.origin??"\u503C"} \u61C9\u70BA ${o}${e.maximum.toString()} ${a.unit??"\u500B\u5143\u7D20"}`:`\u6578\u503C\u904E\u5927\uFF1A\u9810\u671F ${e.origin??"\u503C"} \u61C9\u70BA ${o}${e.maximum.toString()}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`\u6578\u503C\u904E\u5C0F\uFF1A\u9810\u671F ${e.origin} \u61C9\u70BA ${o}${e.minimum.toString()} ${a.unit}`:`\u6578\u503C\u904E\u5C0F\uFF1A\u9810\u671F ${e.origin} \u61C9\u70BA ${o}${e.minimum.toString()}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u7121\u6548\u7684\u5B57\u4E32\uFF1A\u5FC5\u9808\u4EE5 "${o.prefix}" \u958B\u982D`:o.format==="ends_with"?`\u7121\u6548\u7684\u5B57\u4E32\uFF1A\u5FC5\u9808\u4EE5 "${o.suffix}" \u7D50\u5C3E`:o.format==="includes"?`\u7121\u6548\u7684\u5B57\u4E32\uFF1A\u5FC5\u9808\u5305\u542B "${o.includes}"`:o.format==="regex"?`\u7121\u6548\u7684\u5B57\u4E32\uFF1A\u5FC5\u9808\u7B26\u5408\u683C\u5F0F ${o.pattern}`:`\u7121\u6548\u7684 ${n[o.format]??e.format}`}case"not_multiple_of":return`\u7121\u6548\u7684\u6578\u5B57\uFF1A\u5FC5\u9808\u70BA ${e.divisor} \u7684\u500D\u6578`;case"unrecognized_keys":return`\u7121\u6CD5\u8B58\u5225\u7684\u9375\u503C${e.keys.length>1?"\u5011":""}\uFF1A${f(e.keys,"\u3001")}`;case"invalid_key":return`${e.origin} \u4E2D\u6709\u7121\u6548\u7684\u9375\u503C`;case"invalid_union":return"\u7121\u6548\u7684\u8F38\u5165\u503C";case"invalid_element":return`${e.origin} \u4E2D\u6709\u7121\u6548\u7684\u503C`;default:return"\u7121\u6548\u7684\u8F38\u5165\u503C"}}}});function hf(){return{localeError:iv()}}var iv,vf=x(()=>{w();iv=()=>{let t={string:{unit:"\xE0mi",verb:"n\xED"},file:{unit:"bytes",verb:"n\xED"},array:{unit:"nkan",verb:"n\xED"},set:{unit:"nkan",verb:"n\xED"}};function r(e){return t[e]??null}let n={regex:"\u1EB9\u0300r\u1ECD \xECb\xE1w\u1ECDl\xE9",email:"\xE0d\xEDr\u1EB9\u0301s\xEC \xECm\u1EB9\u0301l\xEC",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"\xE0k\xF3k\xF2 ISO",date:"\u1ECDj\u1ECD\u0301 ISO",time:"\xE0k\xF3k\xF2 ISO",duration:"\xE0k\xF3k\xF2 t\xF3 p\xE9 ISO",ipv4:"\xE0d\xEDr\u1EB9\u0301s\xEC IPv4",ipv6:"\xE0d\xEDr\u1EB9\u0301s\xEC IPv6",cidrv4:"\xE0gb\xE8gb\xE8 IPv4",cidrv6:"\xE0gb\xE8gb\xE8 IPv6",base64:"\u1ECD\u0300r\u1ECD\u0300 t\xED a k\u1ECD\u0301 n\xED base64",base64url:"\u1ECD\u0300r\u1ECD\u0300 base64url",json_string:"\u1ECD\u0300r\u1ECD\u0300 JSON",e164:"n\u1ECD\u0301mb\xE0 E.164",jwt:"JWT",template_literal:"\u1EB9\u0300r\u1ECD \xECb\xE1w\u1ECDl\xE9"},i={nan:"NaN",number:"n\u1ECD\u0301mb\xE0",array:"akop\u1ECD"};return e=>{switch(e.code){case"invalid_type":{let o=i[e.expected]??e.expected,a=b(e.input),s=i[a]??a;return/^[A-Z]/.test(e.expected)?`\xCCb\xE1w\u1ECDl\xE9 a\u1E63\xEC\u1E63e: a n\xED l\xE1ti fi instanceof ${e.expected}, \xE0m\u1ECD\u0300 a r\xED ${s}`:`\xCCb\xE1w\u1ECDl\xE9 a\u1E63\xEC\u1E63e: a n\xED l\xE1ti fi ${o}, \xE0m\u1ECD\u0300 a r\xED ${s}`}case"invalid_value":return e.values.length===1?`\xCCb\xE1w\u1ECDl\xE9 a\u1E63\xEC\u1E63e: a n\xED l\xE1ti fi ${y(e.values[0])}`:`\xC0\u1E63\xE0y\xE0n a\u1E63\xEC\u1E63e: yan \u1ECD\u0300kan l\xE1ra ${f(e.values,"|")}`;case"too_big":{let o=e.inclusive?"<=":"<",a=r(e.origin);return a?`T\xF3 p\u1ECD\u0300 j\xF9: a n\xED l\xE1ti j\u1EB9\u0301 p\xE9 ${e.origin??"iye"} ${a.verb} ${o}${e.maximum} ${a.unit}`:`T\xF3 p\u1ECD\u0300 j\xF9: a n\xED l\xE1ti j\u1EB9\u0301 ${o}${e.maximum}`}case"too_small":{let o=e.inclusive?">=":">",a=r(e.origin);return a?`K\xE9r\xE9 ju: a n\xED l\xE1ti j\u1EB9\u0301 p\xE9 ${e.origin} ${a.verb} ${o}${e.minimum} ${a.unit}`:`K\xE9r\xE9 ju: a n\xED l\xE1ti j\u1EB9\u0301 ${o}${e.minimum}`}case"invalid_format":{let o=e;return o.format==="starts_with"?`\u1ECC\u0300r\u1ECD\u0300 a\u1E63\xEC\u1E63e: gb\u1ECD\u0301d\u1ECD\u0300 b\u1EB9\u0300r\u1EB9\u0300 p\u1EB9\u0300l\xFA "${o.prefix}"`:o.format==="ends_with"?`\u1ECC\u0300r\u1ECD\u0300 a\u1E63\xEC\u1E63e: gb\u1ECD\u0301d\u1ECD\u0300 par\xED p\u1EB9\u0300l\xFA "${o.suffix}"`:o.format==="includes"?`\u1ECC\u0300r\u1ECD\u0300 a\u1E63\xEC\u1E63e: gb\u1ECD\u0301d\u1ECD\u0300 n\xED "${o.includes}"`:o.format==="regex"?`\u1ECC\u0300r\u1ECD\u0300 a\u1E63\xEC\u1E63e: gb\u1ECD\u0301d\u1ECD\u0300 b\xE1 \xE0p\u1EB9\u1EB9r\u1EB9 mu ${o.pattern}`:`A\u1E63\xEC\u1E63e: ${n[o.format]??e.format}`}case"not_multiple_of":return`N\u1ECD\u0301mb\xE0 a\u1E63\xEC\u1E63e: gb\u1ECD\u0301d\u1ECD\u0300 j\u1EB9\u0301 \xE8y\xE0 p\xEDp\xEDn ti ${e.divisor}`;case"unrecognized_keys":return`B\u1ECDt\xECn\xEC \xE0\xECm\u1ECD\u0300: ${f(e.keys,", ")}`;case"invalid_key":return`B\u1ECDt\xECn\xEC a\u1E63\xEC\u1E63e n\xEDn\xFA ${e.origin}`;case"invalid_union":return"\xCCb\xE1w\u1ECDl\xE9 a\u1E63\xEC\u1E63e";case"invalid_element":return`Iye a\u1E63\xEC\u1E63e n\xEDn\xFA ${e.origin}`;default:return"\xCCb\xE1w\u1ECDl\xE9 a\u1E63\xEC\u1E63e"}}}});var Ut={};we(Ut,{ar:()=>kp,az:()=>Sp,be:()=>Pp,bg:()=>Tp,ca:()=>Dp,cs:()=>Np,da:()=>Zp,de:()=>Ap,el:()=>Mp,en:()=>Qn,eo:()=>qp,es:()=>Jp,fa:()=>Hp,fi:()=>Wp,fr:()=>Gp,frCA:()=>Xp,he:()=>em,hr:()=>rm,hu:()=>om,hy:()=>sm,id:()=>um,is:()=>dm,it:()=>mm,ja:()=>gm,ka:()=>vm,kh:()=>bm,km:()=>Xn,ko:()=>$m,lt:()=>zm,mk:()=>wm,ms:()=>Pm,nl:()=>Tm,no:()=>Dm,ota:()=>Nm,pl:()=>Am,ps:()=>Zm,pt:()=>Mm,ro:()=>qm,ru:()=>Vm,sl:()=>Bm,sv:()=>Km,ta:()=>Qm,th:()=>Ym,tr:()=>tf,ua:()=>nf,uk:()=>Yn,ur:()=>af,uz:()=>cf,vi:()=>lf,yo:()=>hf,zhCN:()=>pf,zhTW:()=>ff});var xc=x(()=>{zp();wp();jp();Op();Up();Ep();Rp();Cp();Lp();bc();Fp();Vp();Bp();Kp();Qp();Yp();tm();nm();im();cm();lm();pm();fm();hm();ym();_m();_c();xm();Sm();Im();jm();Om();Um();Em();Rm();Cm();Lm();Fm();Hm();Wm();Gm();Xm();ef();rf();of();$c();sf();uf();df();mf();gf();vf()});function yr(){return new eo}var yf,to,ro,eo,X,br=x(()=>{to=Symbol("ZodOutput"),ro=Symbol("ZodInput"),eo=class{constructor(){this._map=new WeakMap,this._idmap=new Map}add(r,...n){let i=n[0];return this._map.set(r,i),i&&typeof i=="object"&&"id"in i&&this._idmap.set(i.id,r),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(r){let n=this._map.get(r);return n&&typeof n=="object"&&"id"in n&&this._idmap.delete(n.id),this._map.delete(r),this}get(r){let n=r._zod.parent;if(n){let i={...this.get(n)??{}};delete i.id;let e={...i,...this._map.get(r)};return Object.keys(e).length?e:void 0}return this._map.get(r)}has(r){return this._map.has(r)}};(yf=globalThis).__zod_globalRegistry??(yf.__zod_globalRegistry=yr());X=globalThis.__zod_globalRegistry});function kc(t,r){return new t({type:"string",...$(r)})}function zc(t,r){return new t({type:"string",coerce:!0,...$(r)})}function no(t,r){return new t({type:"string",format:"email",check:"string_format",abort:!1,...$(r)})}function _r(t,r){return new t({type:"string",format:"guid",check:"string_format",abort:!1,...$(r)})}function oo(t,r){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,...$(r)})}function io(t,r){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v4",...$(r)})}function ao(t,r){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v6",...$(r)})}function so(t,r){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v7",...$(r)})}function $r(t,r){return new t({type:"string",format:"url",check:"string_format",abort:!1,...$(r)})}function co(t,r){return new t({type:"string",format:"emoji",check:"string_format",abort:!1,...$(r)})}function uo(t,r){return new t({type:"string",format:"nanoid",check:"string_format",abort:!1,...$(r)})}function lo(t,r){return new t({type:"string",format:"cuid",check:"string_format",abort:!1,...$(r)})}function po(t,r){return new t({type:"string",format:"cuid2",check:"string_format",abort:!1,...$(r)})}function mo(t,r){return new t({type:"string",format:"ulid",check:"string_format",abort:!1,...$(r)})}function fo(t,r){return new t({type:"string",format:"xid",check:"string_format",abort:!1,...$(r)})}function go(t,r){return new t({type:"string",format:"ksuid",check:"string_format",abort:!1,...$(r)})}function ho(t,r){return new t({type:"string",format:"ipv4",check:"string_format",abort:!1,...$(r)})}function vo(t,r){return new t({type:"string",format:"ipv6",check:"string_format",abort:!1,...$(r)})}function Sc(t,r){return new t({type:"string",format:"mac",check:"string_format",abort:!1,...$(r)})}function yo(t,r){return new t({type:"string",format:"cidrv4",check:"string_format",abort:!1,...$(r)})}function bo(t,r){return new t({type:"string",format:"cidrv6",check:"string_format",abort:!1,...$(r)})}function _o(t,r){return new t({type:"string",format:"base64",check:"string_format",abort:!1,...$(r)})}function $o(t,r){return new t({type:"string",format:"base64url",check:"string_format",abort:!1,...$(r)})}function xo(t,r){return new t({type:"string",format:"e164",check:"string_format",abort:!1,...$(r)})}function ko(t,r){return new t({type:"string",format:"jwt",check:"string_format",abort:!1,...$(r)})}function wc(t,r){return new t({type:"string",format:"datetime",check:"string_format",offset:!1,local:!1,precision:null,...$(r)})}function Ic(t,r){return new t({type:"string",format:"date",check:"string_format",...$(r)})}function Pc(t,r){return new t({type:"string",format:"time",check:"string_format",precision:null,...$(r)})}function jc(t,r){return new t({type:"string",format:"duration",check:"string_format",...$(r)})}function Tc(t,r){return new t({type:"number",checks:[],...$(r)})}function Oc(t,r){return new t({type:"number",coerce:!0,checks:[],...$(r)})}function Dc(t,r){return new t({type:"number",check:"number_format",abort:!1,format:"safeint",...$(r)})}function Uc(t,r){return new t({type:"number",check:"number_format",abort:!1,format:"float32",...$(r)})}function Nc(t,r){return new t({type:"number",check:"number_format",abort:!1,format:"float64",...$(r)})}function Ec(t,r){return new t({type:"number",check:"number_format",abort:!1,format:"int32",...$(r)})}function Zc(t,r){return new t({type:"number",check:"number_format",abort:!1,format:"uint32",...$(r)})}function Rc(t,r){return new t({type:"boolean",...$(r)})}function Ac(t,r){return new t({type:"boolean",coerce:!0,...$(r)})}function Cc(t,r){return new t({type:"bigint",...$(r)})}function Mc(t,r){return new t({type:"bigint",coerce:!0,...$(r)})}function Lc(t,r){return new t({type:"bigint",check:"bigint_format",abort:!1,format:"int64",...$(r)})}function qc(t,r){return new t({type:"bigint",check:"bigint_format",abort:!1,format:"uint64",...$(r)})}function Fc(t,r){return new t({type:"symbol",...$(r)})}function Jc(t,r){return new t({type:"undefined",...$(r)})}function Vc(t,r){return new t({type:"null",...$(r)})}function Hc(t){return new t({type:"any"})}function Bc(t){return new t({type:"unknown"})}function Wc(t,r){return new t({type:"never",...$(r)})}function Kc(t,r){return new t({type:"void",...$(r)})}function Gc(t,r){return new t({type:"date",...$(r)})}function Qc(t,r){return new t({type:"date",coerce:!0,...$(r)})}function Xc(t,r){return new t({type:"nan",...$(r)})}function xe(t,r){return new Cn({check:"less_than",...$(r),value:t,inclusive:!1})}function fe(t,r){return new Cn({check:"less_than",...$(r),value:t,inclusive:!0})}function ke(t,r){return new Mn({check:"greater_than",...$(r),value:t,inclusive:!1})}function ae(t,r){return new Mn({check:"greater_than",...$(r),value:t,inclusive:!0})}function xr(t){return ke(0,t)}function kr(t){return xe(0,t)}function zr(t){return fe(0,t)}function Sr(t){return ae(0,t)}function Te(t,r){return new La({check:"multiple_of",...$(r),value:t})}function Oe(t,r){return new Ja({check:"max_size",...$(r),maximum:t})}function ze(t,r){return new Va({check:"min_size",...$(r),minimum:t})}function Me(t,r){return new Ha({check:"size_equals",...$(r),size:t})}function Le(t,r){return new Ba({check:"max_length",...$(r),maximum:t})}function Ie(t,r){return new Wa({check:"min_length",...$(r),minimum:t})}function qe(t,r){return new Ka({check:"length_equals",...$(r),length:t})}function tt(t,r){return new Ga({check:"string_format",format:"regex",...$(r),pattern:t})}function rt(t){return new Qa({check:"string_format",format:"lowercase",...$(t)})}function nt(t){return new Xa({check:"string_format",format:"uppercase",...$(t)})}function ot(t,r){return new Ya({check:"string_format",format:"includes",...$(r),includes:t})}function it(t,r){return new es({check:"string_format",format:"starts_with",...$(r),prefix:t})}function at(t,r){return new ts({check:"string_format",format:"ends_with",...$(r),suffix:t})}function wr(t,r,n){return new rs({check:"property",property:t,schema:r,...$(n)})}function st(t,r){return new ns({check:"mime_type",mime:t,...$(r)})}function ye(t){return new os({check:"overwrite",tx:t})}function ct(t){return ye(r=>r.normalize(t))}function ut(){return ye(t=>t.trim())}function lt(){return ye(t=>t.toLowerCase())}function dt(){return ye(t=>t.toUpperCase())}function pt(){return ye(t=>ra(t))}function Yc(t,r,n){return new t({type:"array",element:r,...$(n)})}function sv(t,r,n){return new t({type:"union",options:r,...$(n)})}function cv(t,r,n){return new t({type:"union",options:r,inclusive:!1,...$(n)})}function uv(t,r,n,i){return new t({type:"union",options:n,discriminator:r,...$(i)})}function lv(t,r,n){return new t({type:"intersection",left:r,right:n})}function dv(t,r,n,i){let e=n instanceof P,o=e?i:n,a=e?n:null;return new t({type:"tuple",items:r,rest:a,...$(o)})}function pv(t,r,n,i){return new t({type:"record",keyType:r,valueType:n,...$(i)})}function mv(t,r,n,i){return new t({type:"map",keyType:r,valueType:n,...$(i)})}function fv(t,r,n){return new t({type:"set",valueType:r,...$(n)})}function gv(t,r,n){let i=Array.isArray(r)?Object.fromEntries(r.map(e=>[e,e])):r;return new t({type:"enum",entries:i,...$(n)})}function hv(t,r,n){return new t({type:"enum",entries:r,...$(n)})}function vv(t,r,n){return new t({type:"literal",values:Array.isArray(r)?r:[r],...$(n)})}function eu(t,r){return new t({type:"file",...$(r)})}function yv(t,r){return new t({type:"transform",transform:r})}function bv(t,r){return new t({type:"optional",innerType:r})}function _v(t,r){return new t({type:"nullable",innerType:r})}function $v(t,r,n){return new t({type:"default",innerType:r,get defaultValue(){return typeof n=="function"?n():oa(n)}})}function xv(t,r,n){return new t({type:"nonoptional",innerType:r,...$(n)})}function kv(t,r){return new t({type:"success",innerType:r})}function zv(t,r,n){return new t({type:"catch",innerType:r,catchValue:typeof n=="function"?n:()=>n})}function Sv(t,r,n){return new t({type:"pipe",in:r,out:n})}function wv(t,r){return new t({type:"readonly",innerType:r})}function Iv(t,r,n){return new t({type:"template_literal",parts:r,...$(n)})}function Pv(t,r){return new t({type:"lazy",getter:r})}function jv(t,r){return new t({type:"promise",innerType:r})}function tu(t,r,n){let i=$(n);return i.abort??(i.abort=!0),new t({type:"custom",check:"custom",fn:r,...i})}function ru(t,r,n){return new t({type:"custom",check:"custom",fn:r,...$(n)})}function nu(t,r){let n=bf(i=>(i.addIssue=e=>{if(typeof e=="string")i.issues.push(kt(e,i.value,n._zod.def));else{let o=e;o.fatal&&(o.continue=!1),o.code??(o.code="custom"),o.input??(o.input=i.value),o.inst??(o.inst=n),o.continue??(o.continue=!n._zod.def.abort),i.issues.push(kt(o))}},t(i.value,i)),r);return n}function bf(t,r){let n=new J({check:"custom",...$(r)});return n._zod.check=t,n}function ou(t){let r=new J({check:"describe"});return r._zod.onattach=[n=>{let i=X.get(n)??{};X.add(n,{...i,description:t})}],r._zod.check=()=>{},r}function iu(t){let r=new J({check:"meta"});return r._zod.onattach=[n=>{let i=X.get(n)??{};X.add(n,{...i,...t})}],r._zod.check=()=>{},r}function au(t,r){let n=$(r),i=n.truthy??["true","1","yes","on","y","enabled"],e=n.falsy??["false","0","no","off","n","disabled"];n.case!=="sensitive"&&(i=i.map(v=>typeof v=="string"?v.toLowerCase():v),e=e.map(v=>typeof v=="string"?v.toLowerCase():v));let o=new Set(i),a=new Set(e),s=t.Codec??hr,c=t.Boolean??fr,u=t.String??et,d=new u({type:"string",error:n.error}),m=new c({type:"boolean",error:n.error}),h=new s({type:"pipe",in:d,out:m,transform:(v,S)=>{let G=v;return n.case!=="sensitive"&&(G=G.toLowerCase()),o.has(G)?!0:a.has(G)?!1:(S.issues.push({code:"invalid_value",expected:"stringbool",values:[...o,...a],input:S.value,inst:h,continue:!1}),{})},reverseTransform:(v,S)=>v===!0?i[0]||"true":e[0]||"false",error:n.error});return h}function Nt(t,r,n,i={}){let e=$(i),o={...$(i),check:"string_format",type:"string",format:r,fn:typeof n=="function"?n:s=>n.test(s),...e};return n instanceof RegExp&&(o.pattern=n),new t(o)}var zo,_f=x(()=>{Ln();br();yc();w();zo={Any:null,Minute:-1,Second:0,Millisecond:3,Microsecond:6}});function Fe(t){let r=t?.target??"draft-2020-12";return r==="draft-4"&&(r="draft-04"),r==="draft-7"&&(r="draft-07"),{processors:t.processors??{},metadataRegistry:t?.metadata??X,target:r,unrepresentable:t?.unrepresentable??"throw",override:t?.override??(()=>{}),io:t?.io??"output",counter:0,seen:new Map,cycles:t?.cycles??"ref",reused:t?.reused??"inline",external:t?.external??void 0}}function E(t,r,n={path:[],schemaPath:[]}){var i;let e=t._zod.def,o=r.seen.get(t);if(o)return o.count++,n.schemaPath.includes(t)&&(o.cycle=n.path),o.schema;let a={schema:{},count:1,cycle:void 0,path:n.path};r.seen.set(t,a);let s=t._zod.toJSONSchema?.();if(s)a.schema=s;else{let d={...n,schemaPath:[...n.schemaPath,t],path:n.path};if(t._zod.processJSONSchema)t._zod.processJSONSchema(r,a.schema,d);else{let h=a.schema,v=r.processors[e.type];if(!v)throw new Error(`[toJSONSchema]: Non-representable type encountered: ${e.type}`);v(t,r,h,d)}let m=t._zod.parent;m&&(a.ref||(a.ref=m),E(m,r,d),r.seen.get(m).isParent=!0)}let c=r.metadataRegistry.get(t);return c&&Object.assign(a.schema,c),r.io==="input"&&ue(t)&&(delete a.schema.examples,delete a.schema.default),r.io==="input"&&"_prefault"in a.schema&&((i=a.schema).default??(i.default=a.schema._prefault)),delete a.schema._prefault,r.seen.get(t).schema}function Je(t,r){let n=t.seen.get(r);if(!n)throw new Error("Unprocessed schema. This is a bug in Zod.");let i=new Map;for(let a of t.seen.entries()){let s=t.metadataRegistry.get(a[0])?.id;if(s){let c=i.get(s);if(c&&c!==a[0])throw new Error(`Duplicate schema id "${s}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);i.set(s,a[0])}}let e=a=>{let s=t.target==="draft-2020-12"?"$defs":"definitions";if(t.external){let m=t.external.registry.get(a[0])?.id,h=t.external.uri??(S=>S);if(m)return{ref:h(m)};let v=a[1].defId??a[1].schema.id??`schema${t.counter++}`;return a[1].defId=v,{defId:v,ref:`${h("__shared")}#/${s}/${v}`}}if(a[1]===n)return{ref:"#"};let u=`#/${s}/`,d=a[1].schema.id??`__schema${t.counter++}`;return{defId:d,ref:u+d}},o=a=>{if(a[1].schema.$ref)return;let s=a[1],{ref:c,defId:u}=e(a);s.def={...s.schema},u&&(s.defId=u);let d=s.schema;for(let m in d)delete d[m];d.$ref=c};if(t.cycles==="throw")for(let a of t.seen.entries()){let s=a[1];if(s.cycle)throw new Error(`Cycle detected: #/${s.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(let a of t.seen.entries()){let s=a[1];if(r===a[0]){o(a);continue}if(t.external){let u=t.external.registry.get(a[0])?.id;if(r!==a[0]&&u){o(a);continue}}if(t.metadataRegistry.get(a[0])?.id){o(a);continue}if(s.cycle){o(a);continue}if(s.count>1&&t.reused==="ref"){o(a);continue}}}function Ve(t,r){let n=t.seen.get(r);if(!n)throw new Error("Unprocessed schema. This is a bug in Zod.");let i=s=>{let c=t.seen.get(s);if(c.ref===null)return;let u=c.def??c.schema,d={...u},m=c.ref;if(c.ref=null,m){i(m);let v=t.seen.get(m),S=v.schema;if(S.$ref&&(t.target==="draft-07"||t.target==="draft-04"||t.target==="openapi-3.0")?(u.allOf=u.allOf??[],u.allOf.push(S)):Object.assign(u,S),Object.assign(u,d),s._zod.parent===m)for(let V in u)V==="$ref"||V==="allOf"||V in d||delete u[V];if(S.$ref&&v.def)for(let V in u)V==="$ref"||V==="allOf"||V in v.def&&JSON.stringify(u[V])===JSON.stringify(v.def[V])&&delete u[V]}let h=s._zod.parent;if(h&&h!==m){i(h);let v=t.seen.get(h);if(v?.schema.$ref&&(u.$ref=v.schema.$ref,v.def))for(let S in u)S==="$ref"||S==="allOf"||S in v.def&&JSON.stringify(u[S])===JSON.stringify(v.def[S])&&delete u[S]}t.override({zodSchema:s,jsonSchema:u,path:c.path??[]})};for(let s of[...t.seen.entries()].reverse())i(s[0]);let e={};if(t.target==="draft-2020-12"?e.$schema="https://json-schema.org/draft/2020-12/schema":t.target==="draft-07"?e.$schema="http://json-schema.org/draft-07/schema#":t.target==="draft-04"?e.$schema="http://json-schema.org/draft-04/schema#":t.target,t.external?.uri){let s=t.external.registry.get(r)?.id;if(!s)throw new Error("Schema is missing an `id` property");e.$id=t.external.uri(s)}Object.assign(e,n.def??n.schema);let o=t.metadataRegistry.get(r)?.id;o!==void 0&&e.id===o&&delete e.id;let a=t.external?.defs??{};for(let s of t.seen.entries()){let c=s[1];c.def&&c.defId&&(c.def.id===c.defId&&delete c.def.id,a[c.defId]=c.def)}t.external||Object.keys(a).length>0&&(t.target==="draft-2020-12"?e.$defs=a:e.definitions=a);try{let s=JSON.parse(JSON.stringify(e));return Object.defineProperty(s,"~standard",{value:{...r["~standard"],jsonSchema:{input:Et(r,"input",t.processors),output:Et(r,"output",t.processors)}},enumerable:!1,writable:!1}),s}catch{throw new Error("Error converting schema to JSON.")}}function ue(t,r){let n=r??{seen:new Set};if(n.seen.has(t))return!1;n.seen.add(t);let i=t._zod.def;if(i.type==="transform")return!0;if(i.type==="array")return ue(i.element,n);if(i.type==="set")return ue(i.valueType,n);if(i.type==="lazy")return ue(i.getter(),n);if(i.type==="promise"||i.type==="optional"||i.type==="nonoptional"||i.type==="nullable"||i.type==="readonly"||i.type==="default"||i.type==="prefault")return ue(i.innerType,n);if(i.type==="intersection")return ue(i.left,n)||ue(i.right,n);if(i.type==="record"||i.type==="map")return ue(i.keyType,n)||ue(i.valueType,n);if(i.type==="pipe")return t._zod.traits.has("$ZodCodec")?!0:ue(i.in,n)||ue(i.out,n);if(i.type==="object"){for(let e in i.shape)if(ue(i.shape[e],n))return!0;return!1}if(i.type==="union"){for(let e of i.options)if(ue(e,n))return!0;return!1}if(i.type==="tuple"){for(let e of i.items)if(ue(e,n))return!0;return!!(i.rest&&ue(i.rest,n))}return!1}var su,Et,Ir=x(()=>{br();su=(t,r={})=>n=>{let i=Fe({...n,processors:r});return E(t,i),Je(i,t),Ve(i,t)},Et=(t,r,n={})=>i=>{let{libraryOptions:e,target:o}=i??{},a=Fe({...e??{},target:o,io:r,processors:n});return E(t,a),Je(a,t),Ve(a,t)}});function Pr(t,r){if("_idmap"in t){let i=t,e=Fe({...r,processors:So}),o={};for(let c of i._idmap.entries()){let[u,d]=c;E(d,e)}let a={},s={registry:i,uri:r?.uri,defs:o};e.external=s;for(let c of i._idmap.entries()){let[u,d]=c;Je(e,d),a[u]=Ve(e,d)}if(Object.keys(o).length>0){let c=e.target==="draft-2020-12"?"$defs":"definitions";a.__shared={[c]:o}}return{schemas:a}}let n=Fe({...r,processors:So});return E(t,n),Je(n,t),Ve(n,t)}var Tv,cu,uu,lu,du,pu,mu,fu,gu,hu,vu,yu,bu,_u,$u,xu,ku,zu,Su,wu,Iu,Pu,ju,Tu,Ou,Du,wo,Uu,Nu,Eu,Zu,Ru,Au,Cu,Mu,Lu,qu,Fu,Io,Ju,So,jr=x(()=>{Ir();w();Tv={guid:"uuid",url:"uri",datetime:"date-time",json_string:"json-string",regex:""},cu=(t,r,n,i)=>{let e=n;e.type="string";let{minimum:o,maximum:a,format:s,patterns:c,contentEncoding:u}=t._zod.bag;if(typeof o=="number"&&(e.minLength=o),typeof a=="number"&&(e.maxLength=a),s&&(e.format=Tv[s]??s,e.format===""&&delete e.format,s==="time"&&delete e.format),u&&(e.contentEncoding=u),c&&c.size>0){let d=[...c];d.length===1?e.pattern=d[0].source:d.length>1&&(e.allOf=[...d.map(m=>({...r.target==="draft-07"||r.target==="draft-04"||r.target==="openapi-3.0"?{type:"string"}:{},pattern:m.source}))])}},uu=(t,r,n,i)=>{let e=n,{minimum:o,maximum:a,format:s,multipleOf:c,exclusiveMaximum:u,exclusiveMinimum:d}=t._zod.bag;typeof s=="string"&&s.includes("int")?e.type="integer":e.type="number";let m=typeof d=="number"&&d>=(o??Number.NEGATIVE_INFINITY),h=typeof u=="number"&&u<=(a??Number.POSITIVE_INFINITY),v=r.target==="draft-04"||r.target==="openapi-3.0";m?v?(e.minimum=d,e.exclusiveMinimum=!0):e.exclusiveMinimum=d:typeof o=="number"&&(e.minimum=o),h?v?(e.maximum=u,e.exclusiveMaximum=!0):e.exclusiveMaximum=u:typeof a=="number"&&(e.maximum=a),typeof c=="number"&&(e.multipleOf=c)},lu=(t,r,n,i)=>{n.type="boolean"},du=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("BigInt cannot be represented in JSON Schema")},pu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Symbols cannot be represented in JSON Schema")},mu=(t,r,n,i)=>{r.target==="openapi-3.0"?(n.type="string",n.nullable=!0,n.enum=[null]):n.type="null"},fu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Undefined cannot be represented in JSON Schema")},gu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Void cannot be represented in JSON Schema")},hu=(t,r,n,i)=>{n.not={}},vu=(t,r,n,i)=>{},yu=(t,r,n,i)=>{},bu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Date cannot be represented in JSON Schema")},_u=(t,r,n,i)=>{let e=t._zod.def,o=rr(e.entries);o.every(a=>typeof a=="number")&&(n.type="number"),o.every(a=>typeof a=="string")&&(n.type="string"),n.enum=o},$u=(t,r,n,i)=>{let e=t._zod.def,o=[];for(let a of e.values)if(a===void 0){if(r.unrepresentable==="throw")throw new Error("Literal `undefined` cannot be represented in JSON Schema")}else if(typeof a=="bigint"){if(r.unrepresentable==="throw")throw new Error("BigInt literals cannot be represented in JSON Schema");o.push(Number(a))}else o.push(a);if(o.length!==0)if(o.length===1){let a=o[0];n.type=a===null?"null":typeof a,r.target==="draft-04"||r.target==="openapi-3.0"?n.enum=[a]:n.const=a}else o.every(a=>typeof a=="number")&&(n.type="number"),o.every(a=>typeof a=="string")&&(n.type="string"),o.every(a=>typeof a=="boolean")&&(n.type="boolean"),o.every(a=>a===null)&&(n.type="null"),n.enum=o},xu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("NaN cannot be represented in JSON Schema")},ku=(t,r,n,i)=>{let e=n,o=t._zod.pattern;if(!o)throw new Error("Pattern not found in template literal");e.type="string",e.pattern=o.source},zu=(t,r,n,i)=>{let e=n,o={type:"string",format:"binary",contentEncoding:"binary"},{minimum:a,maximum:s,mime:c}=t._zod.bag;a!==void 0&&(o.minLength=a),s!==void 0&&(o.maxLength=s),c?c.length===1?(o.contentMediaType=c[0],Object.assign(e,o)):(Object.assign(e,o),e.anyOf=c.map(u=>({contentMediaType:u}))):Object.assign(e,o)},Su=(t,r,n,i)=>{n.type="boolean"},wu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Custom types cannot be represented in JSON Schema")},Iu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Function types cannot be represented in JSON Schema")},Pu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Transforms cannot be represented in JSON Schema")},ju=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Map cannot be represented in JSON Schema")},Tu=(t,r,n,i)=>{if(r.unrepresentable==="throw")throw new Error("Set cannot be represented in JSON Schema")},Ou=(t,r,n,i)=>{let e=n,o=t._zod.def,{minimum:a,maximum:s}=t._zod.bag;typeof a=="number"&&(e.minItems=a),typeof s=="number"&&(e.maxItems=s),e.type="array",e.items=E(o.element,r,{...i,path:[...i.path,"items"]})},Du=(t,r,n,i)=>{let e=n,o=t._zod.def;e.type="object",e.properties={};let a=o.shape;for(let u in a)e.properties[u]=E(a[u],r,{...i,path:[...i.path,"properties",u]});let s=new Set(Object.keys(a)),c=new Set([...s].filter(u=>{let d=o.shape[u]._zod;return r.io==="input"?d.optin===void 0:d.optout===void 0}));c.size>0&&(e.required=Array.from(c)),o.catchall?._zod.def.type==="never"?e.additionalProperties=!1:o.catchall?o.catchall&&(e.additionalProperties=E(o.catchall,r,{...i,path:[...i.path,"additionalProperties"]})):r.io==="output"&&(e.additionalProperties=!1)},wo=(t,r,n,i)=>{let e=t._zod.def,o=e.inclusive===!1,a=e.options.map((s,c)=>E(s,r,{...i,path:[...i.path,o?"oneOf":"anyOf",c]}));o?n.oneOf=a:n.anyOf=a},Uu=(t,r,n,i)=>{let e=t._zod.def,o=E(e.left,r,{...i,path:[...i.path,"allOf",0]}),a=E(e.right,r,{...i,path:[...i.path,"allOf",1]}),s=u=>"allOf"in u&&Object.keys(u).length===1,c=[...s(o)?o.allOf:[o],...s(a)?a.allOf:[a]];n.allOf=c},Nu=(t,r,n,i)=>{let e=n,o=t._zod.def;e.type="array";let a=r.target==="draft-2020-12"?"prefixItems":"items",s=r.target==="draft-2020-12"||r.target==="openapi-3.0"?"items":"additionalItems",c=o.items.map((h,v)=>E(h,r,{...i,path:[...i.path,a,v]})),u=o.rest?E(o.rest,r,{...i,path:[...i.path,s,...r.target==="openapi-3.0"?[o.items.length]:[]]}):null;r.target==="draft-2020-12"?(e.prefixItems=c,u&&(e.items=u)):r.target==="openapi-3.0"?(e.items={anyOf:c},u&&e.items.anyOf.push(u),e.minItems=c.length,u||(e.maxItems=c.length)):(e.items=c,u&&(e.additionalItems=u));let{minimum:d,maximum:m}=t._zod.bag;typeof d=="number"&&(e.minItems=d),typeof m=="number"&&(e.maxItems=m)},Eu=(t,r,n,i)=>{let e=n,o=t._zod.def;e.type="object";let a=o.keyType,c=a._zod.bag?.patterns;if(o.mode==="loose"&&c&&c.size>0){let d=E(o.valueType,r,{...i,path:[...i.path,"patternProperties","*"]});e.patternProperties={};for(let m of c)e.patternProperties[m.source]=d}else(r.target==="draft-07"||r.target==="draft-2020-12")&&(e.propertyNames=E(o.keyType,r,{...i,path:[...i.path,"propertyNames"]})),e.additionalProperties=E(o.valueType,r,{...i,path:[...i.path,"additionalProperties"]});let u=a._zod.values;if(u){let d=[...u].filter(m=>typeof m=="string"||typeof m=="number");d.length>0&&(e.required=d)}},Zu=(t,r,n,i)=>{let e=t._zod.def,o=E(e.innerType,r,i),a=r.seen.get(t);r.target==="openapi-3.0"?(a.ref=e.innerType,n.nullable=!0):n.anyOf=[o,{type:"null"}]},Ru=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType},Au=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType,n.default=JSON.parse(JSON.stringify(e.defaultValue))},Cu=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType,r.io==="input"&&(n._prefault=JSON.parse(JSON.stringify(e.defaultValue)))},Mu=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType;let a;try{a=e.catchValue(void 0)}catch{throw new Error("Dynamic catch values are not supported in JSON Schema")}n.default=a},Lu=(t,r,n,i)=>{let e=t._zod.def,o=e.in._zod.traits.has("$ZodTransform"),a=r.io==="input"?o?e.out:e.in:e.out;E(a,r,i);let s=r.seen.get(t);s.ref=a},qu=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType,n.readOnly=!0},Fu=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType},Io=(t,r,n,i)=>{let e=t._zod.def;E(e.innerType,r,i);let o=r.seen.get(t);o.ref=e.innerType},Ju=(t,r,n,i)=>{let e=t._zod.innerType;E(e,r,i);let o=r.seen.get(t);o.ref=e},So={string:cu,number:uu,boolean:lu,bigint:du,symbol:pu,null:mu,undefined:fu,void:gu,never:hu,any:vu,unknown:yu,date:bu,enum:_u,literal:$u,nan:xu,template_literal:ku,file:zu,success:Su,custom:wu,function:Iu,transform:Pu,map:ju,set:Tu,array:Ou,object:Du,union:wo,intersection:Uu,tuple:Nu,record:Eu,nullable:Zu,nonoptional:Ru,default:Au,prefault:Cu,catch:Mu,pipe:Lu,readonly:qu,promise:Fu,optional:Io,lazy:Ju}});var Po,$f=x(()=>{jr();Ir();Po=class{get metadataRegistry(){return this.ctx.metadataRegistry}get target(){return this.ctx.target}get unrepresentable(){return this.ctx.unrepresentable}get override(){return this.ctx.override}get io(){return this.ctx.io}get counter(){return this.ctx.counter}set counter(r){this.ctx.counter=r}get seen(){return this.ctx.seen}constructor(r){let n=r?.target??"draft-2020-12";n==="draft-4"&&(n="draft-04"),n==="draft-7"&&(n="draft-07"),this.ctx=Fe({processors:So,target:n,...r?.metadata&&{metadata:r.metadata},...r?.unrepresentable&&{unrepresentable:r.unrepresentable},...r?.override&&{override:r.override},...r?.io&&{io:r.io}})}process(r,n={path:[],schemaPath:[]}){return E(r,this.ctx,n)}emit(r,n){n&&(n.cycles&&(this.ctx.cycles=n.cycles),n.reused&&(this.ctx.reused=n.reused),n.external&&(this.ctx.external=n.external)),Je(this.ctx,r);let i=Ve(this.ctx,r),{"~standard":e,...o}=i;return o}}});var xf={};var kf=x(()=>{});var Pe={};we(Pe,{$ZodAny:()=>Ms,$ZodArray:()=>Vs,$ZodAsyncError:()=>$e,$ZodBase64:()=>Ts,$ZodBase64URL:()=>Os,$ZodBigInt:()=>Bn,$ZodBigIntFormat:()=>Zs,$ZodBoolean:()=>fr,$ZodCIDRv4:()=>Is,$ZodCIDRv6:()=>Ps,$ZodCUID:()=>gs,$ZodCUID2:()=>hs,$ZodCatch:()=>uc,$ZodCheck:()=>J,$ZodCheckBigIntFormat:()=>Fa,$ZodCheckEndsWith:()=>ts,$ZodCheckGreaterThan:()=>Mn,$ZodCheckIncludes:()=>Ya,$ZodCheckLengthEquals:()=>Ka,$ZodCheckLessThan:()=>Cn,$ZodCheckLowerCase:()=>Qa,$ZodCheckMaxLength:()=>Ba,$ZodCheckMaxSize:()=>Ja,$ZodCheckMimeType:()=>ns,$ZodCheckMinLength:()=>Wa,$ZodCheckMinSize:()=>Va,$ZodCheckMultipleOf:()=>La,$ZodCheckNumberFormat:()=>qa,$ZodCheckOverwrite:()=>os,$ZodCheckProperty:()=>rs,$ZodCheckRegex:()=>Ga,$ZodCheckSizeEquals:()=>Ha,$ZodCheckStartsWith:()=>es,$ZodCheckStringFormat:()=>Ot,$ZodCheckUpperCase:()=>Xa,$ZodCodec:()=>hr,$ZodCustom:()=>vc,$ZodCustomStringFormat:()=>Ns,$ZodDate:()=>Js,$ZodDefault:()=>ic,$ZodDiscriminatedUnion:()=>Ws,$ZodE164:()=>Ds,$ZodEmail:()=>ds,$ZodEmoji:()=>ms,$ZodEncodeError:()=>Ee,$ZodEnum:()=>Ys,$ZodError:()=>sr,$ZodExactOptional:()=>nc,$ZodFile:()=>tc,$ZodFunction:()=>fc,$ZodGUID:()=>us,$ZodIPv4:()=>zs,$ZodIPv6:()=>Ss,$ZodISODate:()=>$s,$ZodISODateTime:()=>_s,$ZodISODuration:()=>ks,$ZodISOTime:()=>xs,$ZodIntersection:()=>Ks,$ZodJWT:()=>Us,$ZodKSUID:()=>bs,$ZodLazy:()=>hc,$ZodLiteral:()=>ec,$ZodMAC:()=>ws,$ZodMap:()=>Qs,$ZodNaN:()=>lc,$ZodNanoID:()=>fs,$ZodNever:()=>qs,$ZodNonOptional:()=>sc,$ZodNull:()=>Cs,$ZodNullable:()=>oc,$ZodNumber:()=>Hn,$ZodNumberFormat:()=>Es,$ZodObject:()=>xp,$ZodObjectJIT:()=>Hs,$ZodOptional:()=>Kn,$ZodPipe:()=>Gn,$ZodPrefault:()=>ac,$ZodPreprocess:()=>dc,$ZodPromise:()=>gc,$ZodReadonly:()=>pc,$ZodRealError:()=>pe,$ZodRecord:()=>Gs,$ZodRegistry:()=>eo,$ZodSet:()=>Xs,$ZodString:()=>et,$ZodStringFormat:()=>L,$ZodSuccess:()=>cc,$ZodSymbol:()=>Rs,$ZodTemplateLiteral:()=>mc,$ZodTransform:()=>rc,$ZodTuple:()=>Wn,$ZodType:()=>P,$ZodULID:()=>vs,$ZodURL:()=>ps,$ZodUUID:()=>ls,$ZodUndefined:()=>As,$ZodUnion:()=>gr,$ZodUnknown:()=>Ls,$ZodVoid:()=>Fs,$ZodXID:()=>ys,$ZodXor:()=>Bs,$brand:()=>kn,$constructor:()=>p,$input:()=>ro,$output:()=>to,Doc:()=>mr,JSONSchema:()=>xf,JSONSchemaGenerator:()=>Po,NEVER:()=>xn,TimePrecision:()=>zo,_any:()=>Hc,_array:()=>Yc,_base64:()=>_o,_base64url:()=>$o,_bigint:()=>Cc,_boolean:()=>Rc,_catch:()=>zv,_check:()=>bf,_cidrv4:()=>yo,_cidrv6:()=>bo,_coercedBigint:()=>Mc,_coercedBoolean:()=>Ac,_coercedDate:()=>Qc,_coercedNumber:()=>Oc,_coercedString:()=>zc,_cuid:()=>lo,_cuid2:()=>po,_custom:()=>tu,_date:()=>Gc,_decode:()=>jn,_decodeAsync:()=>On,_default:()=>$v,_discriminatedUnion:()=>uv,_e164:()=>xo,_email:()=>no,_emoji:()=>co,_encode:()=>Pn,_encodeAsync:()=>Tn,_endsWith:()=>at,_enum:()=>gv,_file:()=>eu,_float32:()=>Uc,_float64:()=>Nc,_gt:()=>ke,_gte:()=>ae,_guid:()=>_r,_includes:()=>ot,_int:()=>Dc,_int32:()=>Ec,_int64:()=>Lc,_intersection:()=>lv,_ipv4:()=>ho,_ipv6:()=>vo,_isoDate:()=>Ic,_isoDateTime:()=>wc,_isoDuration:()=>jc,_isoTime:()=>Pc,_jwt:()=>ko,_ksuid:()=>go,_lazy:()=>Pv,_length:()=>qe,_literal:()=>vv,_lowercase:()=>rt,_lt:()=>xe,_lte:()=>fe,_mac:()=>Sc,_map:()=>mv,_max:()=>fe,_maxLength:()=>Le,_maxSize:()=>Oe,_mime:()=>st,_min:()=>ae,_minLength:()=>Ie,_minSize:()=>ze,_multipleOf:()=>Te,_nan:()=>Xc,_nanoid:()=>uo,_nativeEnum:()=>hv,_negative:()=>kr,_never:()=>Wc,_nonnegative:()=>Sr,_nonoptional:()=>xv,_nonpositive:()=>zr,_normalize:()=>ct,_null:()=>Vc,_nullable:()=>_v,_number:()=>Tc,_optional:()=>bv,_overwrite:()=>ye,_parse:()=>wt,_parseAsync:()=>It,_pipe:()=>Sv,_positive:()=>xr,_promise:()=>jv,_property:()=>wr,_readonly:()=>wv,_record:()=>pv,_refine:()=>ru,_regex:()=>tt,_safeDecode:()=>Un,_safeDecodeAsync:()=>En,_safeEncode:()=>Dn,_safeEncodeAsync:()=>Nn,_safeParse:()=>Pt,_safeParseAsync:()=>Tt,_set:()=>fv,_size:()=>Me,_slugify:()=>pt,_startsWith:()=>it,_string:()=>kc,_stringFormat:()=>Nt,_stringbool:()=>au,_success:()=>kv,_superRefine:()=>nu,_symbol:()=>Fc,_templateLiteral:()=>Iv,_toLowerCase:()=>lt,_toUpperCase:()=>dt,_transform:()=>yv,_trim:()=>ut,_tuple:()=>dv,_uint32:()=>Zc,_uint64:()=>qc,_ulid:()=>mo,_undefined:()=>Jc,_union:()=>sv,_unknown:()=>Bc,_uppercase:()=>nt,_url:()=>$r,_uuid:()=>oo,_uuidv4:()=>io,_uuidv6:()=>ao,_uuidv7:()=>so,_void:()=>Kc,_xid:()=>fo,_xor:()=>cv,clone:()=>ie,config:()=>H,createStandardJSONSchemaMethod:()=>Et,createToJSONSchemaMethod:()=>su,decode:()=>Vd,decodeAsync:()=>Bd,describe:()=>ou,encode:()=>Jd,encodeAsync:()=>Hd,extractDefs:()=>Je,finalize:()=>Ve,flattenError:()=>zt,formatError:()=>St,globalConfig:()=>Ge,globalRegistry:()=>X,initializeContext:()=>Fe,isValidBase64:()=>js,isValidBase64URL:()=>yp,isValidJWT:()=>bp,locales:()=>Ut,meta:()=>iu,parse:()=>cr,parseAsync:()=>ur,prettifyError:()=>In,process:()=>E,regexes:()=>me,registry:()=>yr,safeDecode:()=>Kd,safeDecodeAsync:()=>Qd,safeEncode:()=>Wd,safeEncodeAsync:()=>Gd,safeParse:()=>jt,safeParseAsync:()=>lr,toDotPath:()=>Fd,toJSONSchema:()=>Pr,treeifyError:()=>wn,util:()=>_,version:()=>as});var ge=x(()=>{Qe();da();la();yc();Ln();ss();w();An();xc();br();is();_f();Ir();jr();$f();kf()});var Oo={};we(Oo,{endsWith:()=>at,gt:()=>ke,gte:()=>ae,includes:()=>ot,length:()=>qe,lowercase:()=>rt,lt:()=>xe,lte:()=>fe,maxLength:()=>Le,maxSize:()=>Oe,mime:()=>st,minLength:()=>Ie,minSize:()=>ze,multipleOf:()=>Te,negative:()=>kr,nonnegative:()=>Sr,nonpositive:()=>zr,normalize:()=>ct,overwrite:()=>ye,positive:()=>xr,property:()=>wr,regex:()=>tt,size:()=>Me,slugify:()=>pt,startsWith:()=>it,toLowerCase:()=>lt,toUpperCase:()=>dt,trim:()=>ut,uppercase:()=>nt});var Do=x(()=>{ge()});var De={};we(De,{ZodISODate:()=>Or,ZodISODateTime:()=>Tr,ZodISODuration:()=>Ur,ZodISOTime:()=>Dr,date:()=>Hu,datetime:()=>Vu,duration:()=>Wu,time:()=>Bu});function Vu(t){return wc(Tr,t)}function Hu(t){return Ic(Or,t)}function Bu(t){return Pc(Dr,t)}function Wu(t){return jc(Ur,t)}var Tr,Or,Dr,Ur,Nr=x(()=>{ge();Zr();Tr=p("ZodISODateTime",(t,r)=>{_s.init(t,r),A.init(t,r)});Or=p("ZodISODate",(t,r)=>{$s.init(t,r),A.init(t,r)});Dr=p("ZodISOTime",(t,r)=>{xs.init(t,r),A.init(t,r)});Ur=p("ZodISODuration",(t,r)=>{ks.init(t,r),A.init(t,r)})});var wf,If,le,Ku=x(()=>{ge();ge();w();wf=(t,r)=>{sr.init(t,r),t.name="ZodError",Object.defineProperties(t,{format:{value:n=>St(t,n)},flatten:{value:n=>zt(t,n)},addIssue:{value:n=>{t.issues.push(n),t.message=JSON.stringify(t.issues,$t,2)}},addIssues:{value:n=>{t.issues.push(...n),t.message=JSON.stringify(t.issues,$t,2)}},isEmpty:{get(){return t.issues.length===0}}})},If=p("ZodError",wf),le=p("ZodError",wf,{Parent:Error})});var Uo,No,Eo,Zo,Ro,Ao,Co,Mo,Lo,qo,Fo,Jo,Gu=x(()=>{ge();Ku();Uo=wt(le),No=It(le),Eo=Pt(le),Zo=Tt(le),Ro=Pn(le),Ao=jn(le),Co=Tn(le),Mo=On(le),Lo=Dn(le),qo=Un(le),Fo=Nn(le),Jo=En(le)});var Er={};we(Er,{ZodAny:()=>Ko,ZodArray:()=>Yo,ZodBase64:()=>Yr,ZodBase64URL:()=>en,ZodBigInt:()=>bt,ZodBigIntFormat:()=>nn,ZodBoolean:()=>yt,ZodCIDRv4:()=>Qr,ZodCIDRv6:()=>Xr,ZodCUID:()=>Jr,ZodCUID2:()=>Vr,ZodCatch:()=>bi,ZodCodec:()=>Vt,ZodCustom:()=>Ht,ZodCustomStringFormat:()=>ht,ZodDate:()=>Mt,ZodDefault:()=>mi,ZodDiscriminatedUnion:()=>ti,ZodE164:()=>tn,ZodEmail:()=>Lr,ZodEmoji:()=>qr,ZodEnum:()=>ft,ZodExactOptional:()=>li,ZodFile:()=>ci,ZodFunction:()=>ji,ZodGUID:()=>Zt,ZodIPv4:()=>Kr,ZodIPv6:()=>Gr,ZodIntersection:()=>ri,ZodJWT:()=>rn,ZodKSUID:()=>Wr,ZodLazy:()=>wi,ZodLiteral:()=>si,ZodMAC:()=>Vo,ZodMap:()=>ii,ZodNaN:()=>$i,ZodNanoID:()=>Fr,ZodNever:()=>Qo,ZodNonOptional:()=>cn,ZodNull:()=>Wo,ZodNullable:()=>pi,ZodNumber:()=>vt,ZodNumberFormat:()=>He,ZodObject:()=>Lt,ZodOptional:()=>sn,ZodPipe:()=>Jt,ZodPrefault:()=>gi,ZodPreprocess:()=>xi,ZodPromise:()=>Pi,ZodReadonly:()=>ki,ZodRecord:()=>mt,ZodSet:()=>ai,ZodString:()=>gt,ZodStringFormat:()=>A,ZodSuccess:()=>yi,ZodSymbol:()=>Ho,ZodTemplateLiteral:()=>Si,ZodTransform:()=>ui,ZodTuple:()=>ni,ZodType:()=>j,ZodULID:()=>Hr,ZodURL:()=>At,ZodUUID:()=>Se,ZodUndefined:()=>Bo,ZodUnion:()=>qt,ZodUnknown:()=>Go,ZodVoid:()=>Xo,ZodXID:()=>Br,ZodXor:()=>ei,_ZodString:()=>Mr,_default:()=>fi,_function:()=>Yl,any:()=>Nl,array:()=>T,base64:()=>vl,base64url:()=>yl,bigint:()=>jl,boolean:()=>W,catch:()=>_i,check:()=>ed,cidrv4:()=>gl,cidrv6:()=>hl,codec:()=>Kl,cuid:()=>sl,cuid2:()=>cl,custom:()=>un,date:()=>Zl,describe:()=>td,discriminatedUnion:()=>Ft,e164:()=>bl,email:()=>Qu,emoji:()=>il,enum:()=>ee,exactOptional:()=>di,file:()=>Vl,float32:()=>Sl,float64:()=>wl,function:()=>Yl,guid:()=>Xu,hash:()=>zl,hex:()=>kl,hostname:()=>xl,httpUrl:()=>ol,instanceof:()=>nd,int:()=>Rr,int32:()=>Il,int64:()=>Tl,intersection:()=>_t,invertCodec:()=>Gl,ipv4:()=>pl,ipv6:()=>fl,json:()=>id,jwt:()=>_l,keyof:()=>Rl,ksuid:()=>dl,lazy:()=>Ii,literal:()=>I,looseObject:()=>Y,looseRecord:()=>Ll,mac:()=>ml,map:()=>ql,meta:()=>rd,nan:()=>Wl,nanoid:()=>al,nativeEnum:()=>Jl,never:()=>on,nonoptional:()=>vi,null:()=>Ct,nullable:()=>Rt,nullish:()=>Hl,number:()=>D,object:()=>z,optional:()=>q,partialRecord:()=>Ml,pipe:()=>Ar,prefault:()=>hi,preprocess:()=>Bt,promise:()=>Xl,readonly:()=>zi,record:()=>Z,refine:()=>Ti,set:()=>Fl,strictObject:()=>Al,string:()=>g,stringFormat:()=>$l,stringbool:()=>od,success:()=>Bl,superRefine:()=>Oi,symbol:()=>Dl,templateLiteral:()=>Ql,transform:()=>an,tuple:()=>oi,uint32:()=>Pl,uint64:()=>Ol,ulid:()=>ul,undefined:()=>Ul,union:()=>M,unknown:()=>C,url:()=>nl,uuid:()=>Yu,uuidv4:()=>el,uuidv6:()=>tl,uuidv7:()=>rl,void:()=>El,xid:()=>ll,xor:()=>Cl});function Cr(t,r,n){let i=Object.getPrototypeOf(t),e=Pf.get(i);if(e||(e=new Set,Pf.set(i,e)),!e.has(r)){e.add(r);for(let o in n){let a=n[o];Object.defineProperty(i,o,{configurable:!0,enumerable:!1,get(){let s=a.bind(this);return Object.defineProperty(this,o,{configurable:!0,writable:!0,enumerable:!0,value:s}),s},set(s){Object.defineProperty(this,o,{configurable:!0,writable:!0,enumerable:!0,value:s})}})}}}function g(t){return kc(gt,t)}function Qu(t){return no(Lr,t)}function Xu(t){return _r(Zt,t)}function Yu(t){return oo(Se,t)}function el(t){return io(Se,t)}function tl(t){return ao(Se,t)}function rl(t){return so(Se,t)}function nl(t){return $r(At,t)}function ol(t){return $r(At,{protocol:me.httpProtocol,hostname:me.domain,..._.normalizeParams(t)})}function il(t){return co(qr,t)}function al(t){return uo(Fr,t)}function sl(t){return lo(Jr,t)}function cl(t){return po(Vr,t)}function ul(t){return mo(Hr,t)}function ll(t){return fo(Br,t)}function dl(t){return go(Wr,t)}function pl(t){return ho(Kr,t)}function ml(t){return Sc(Vo,t)}function fl(t){return vo(Gr,t)}function gl(t){return yo(Qr,t)}function hl(t){return bo(Xr,t)}function vl(t){return _o(Yr,t)}function yl(t){return $o(en,t)}function bl(t){return xo(tn,t)}function _l(t){return ko(rn,t)}function $l(t,r,n={}){return Nt(ht,t,r,n)}function xl(t){return Nt(ht,"hostname",me.hostname,t)}function kl(t){return Nt(ht,"hex",me.hex,t)}function zl(t,r){let n=r?.enc??"hex",i=`${t}_${n}`,e=me[i];if(!e)throw new Error(`Unrecognized hash format: ${i}`);return Nt(ht,i,e,r)}function D(t){return Tc(vt,t)}function Rr(t){return Dc(He,t)}function Sl(t){return Uc(He,t)}function wl(t){return Nc(He,t)}function Il(t){return Ec(He,t)}function Pl(t){return Zc(He,t)}function W(t){return Rc(yt,t)}function jl(t){return Cc(bt,t)}function Tl(t){return Lc(nn,t)}function Ol(t){return qc(nn,t)}function Dl(t){return Fc(Ho,t)}function Ul(t){return Jc(Bo,t)}function Ct(t){return Vc(Wo,t)}function Nl(){return Hc(Ko)}function C(){return Bc(Go)}function on(t){return Wc(Qo,t)}function El(t){return Kc(Xo,t)}function Zl(t){return Gc(Mt,t)}function T(t,r){return Yc(Yo,t,r)}function Rl(t){let r=t._zod.def.shape;return ee(Object.keys(r))}function z(t,r){let n={type:"object",shape:t??{},..._.normalizeParams(r)};return new Lt(n)}function Al(t,r){return new Lt({type:"object",shape:t,catchall:on(),..._.normalizeParams(r)})}function Y(t,r){return new Lt({type:"object",shape:t,catchall:C(),..._.normalizeParams(r)})}function M(t,r){return new qt({type:"union",options:t,..._.normalizeParams(r)})}function Cl(t,r){return new ei({type:"union",options:t,inclusive:!1,..._.normalizeParams(r)})}function Ft(t,r,n){return new ti({type:"union",options:r,discriminator:t,..._.normalizeParams(n)})}function _t(t,r){return new ri({type:"intersection",left:t,right:r})}function oi(t,r,n){let i=r instanceof P,e=i?n:r,o=i?r:null;return new ni({type:"tuple",items:t,rest:o,..._.normalizeParams(e)})}function Z(t,r,n){return!r||!r._zod?new mt({type:"record",keyType:g(),valueType:t,..._.normalizeParams(r)}):new mt({type:"record",keyType:t,valueType:r,..._.normalizeParams(n)})}function Ml(t,r,n){let i=ie(t);return i._zod.values=void 0,new mt({type:"record",keyType:i,valueType:r,..._.normalizeParams(n)})}function Ll(t,r,n){return new mt({type:"record",keyType:t,valueType:r,mode:"loose",..._.normalizeParams(n)})}function ql(t,r,n){return new ii({type:"map",keyType:t,valueType:r,..._.normalizeParams(n)})}function Fl(t,r){return new ai({type:"set",valueType:t,..._.normalizeParams(r)})}function ee(t,r){let n=Array.isArray(t)?Object.fromEntries(t.map(i=>[i,i])):t;return new ft({type:"enum",entries:n,..._.normalizeParams(r)})}function Jl(t,r){return new ft({type:"enum",entries:t,..._.normalizeParams(r)})}function I(t,r){return new si({type:"literal",values:Array.isArray(t)?t:[t],..._.normalizeParams(r)})}function Vl(t){return eu(ci,t)}function an(t){return new ui({type:"transform",transform:t})}function q(t){return new sn({type:"optional",innerType:t})}function di(t){return new li({type:"optional",innerType:t})}function Rt(t){return new pi({type:"nullable",innerType:t})}function Hl(t){return q(Rt(t))}function fi(t,r){return new mi({type:"default",innerType:t,get defaultValue(){return typeof r=="function"?r():_.shallowClone(r)}})}function hi(t,r){return new gi({type:"prefault",innerType:t,get defaultValue(){return typeof r=="function"?r():_.shallowClone(r)}})}function vi(t,r){return new cn({type:"nonoptional",innerType:t,..._.normalizeParams(r)})}function Bl(t){return new yi({type:"success",innerType:t})}function _i(t,r){return new bi({type:"catch",innerType:t,catchValue:typeof r=="function"?r:()=>r})}function Wl(t){return Xc($i,t)}function Ar(t,r){return new Jt({type:"pipe",in:t,out:r})}function Kl(t,r,n){return new Vt({type:"pipe",in:t,out:r,transform:n.decode,reverseTransform:n.encode})}function Gl(t){let r=t._zod.def;return new Vt({type:"pipe",in:r.out,out:r.in,transform:r.reverseTransform,reverseTransform:r.transform})}function zi(t){return new ki({type:"readonly",innerType:t})}function Ql(t,r){return new Si({type:"template_literal",parts:t,..._.normalizeParams(r)})}function Ii(t){return new wi({type:"lazy",getter:t})}function Xl(t){return new Pi({type:"promise",innerType:t})}function Yl(t){return new ji({type:"function",input:Array.isArray(t?.input)?oi(t?.input):t?.input??T(C()),output:t?.output??C()})}function ed(t){let r=new J({check:"custom"});return r._zod.check=t,r}function un(t,r){return tu(Ht,t??(()=>!0),r)}function Ti(t,r={}){return ru(Ht,t,r)}function Oi(t,r){return nu(t,r)}function nd(t,r={}){let n=new Ht({type:"custom",check:"custom",fn:i=>i instanceof t,abort:!0,..._.normalizeParams(r)});return n._zod.bag.Class=t,n._zod.check=i=>{i.value instanceof t||i.issues.push({code:"invalid_type",expected:t.name,input:i.value,inst:n,path:[...n._zod.def.path??[]]})},n}function id(t){let r=Ii(()=>M([g(t),D(),W(),Ct(),T(r),Z(g(),r)]));return r}function Bt(t,r){return new xi({type:"pipe",in:an(t),out:r})}var Pf,j,Mr,gt,A,Lr,Zt,Se,At,qr,Fr,Jr,Vr,Hr,Br,Wr,Kr,Vo,Gr,Qr,Xr,Yr,en,tn,rn,ht,vt,He,yt,bt,nn,Ho,Bo,Wo,Ko,Go,Qo,Xo,Mt,Yo,Lt,qt,ei,ti,ri,ni,mt,ii,ai,ft,si,ci,ui,sn,li,pi,mi,gi,cn,yi,bi,$i,Jt,Vt,xi,ki,Si,wi,Pi,ji,Ht,td,rd,od,Zr=x(()=>{ge();ge();jr();Ir();Do();Nr();Gu();Pf=new WeakMap;j=p("ZodType",(t,r)=>(P.init(t,r),Object.assign(t["~standard"],{jsonSchema:{input:Et(t,"input"),output:Et(t,"output")}}),t.toJSONSchema=su(t,{}),t.def=r,t.type=r.type,Object.defineProperty(t,"_def",{value:r}),t.parse=(n,i)=>Uo(t,n,i,{callee:t.parse}),t.safeParse=(n,i)=>Eo(t,n,i),t.parseAsync=async(n,i)=>No(t,n,i,{callee:t.parseAsync}),t.safeParseAsync=async(n,i)=>Zo(t,n,i),t.spa=t.safeParseAsync,t.encode=(n,i)=>Ro(t,n,i),t.decode=(n,i)=>Ao(t,n,i),t.encodeAsync=async(n,i)=>Co(t,n,i),t.decodeAsync=async(n,i)=>Mo(t,n,i),t.safeEncode=(n,i)=>Lo(t,n,i),t.safeDecode=(n,i)=>qo(t,n,i),t.safeEncodeAsync=async(n,i)=>Fo(t,n,i),t.safeDecodeAsync=async(n,i)=>Jo(t,n,i),Cr(t,"ZodType",{check(...n){let i=this.def;return this.clone(_.mergeDefs(i,{checks:[...i.checks??[],...n.map(e=>typeof e=="function"?{_zod:{check:e,def:{check:"custom"},onattach:[]}}:e)]}),{parent:!0})},with(...n){return this.check(...n)},clone(n,i){return ie(this,n,i)},brand(){return this},register(n,i){return n.add(this,i),this},refine(n,i){return this.check(Ti(n,i))},superRefine(n,i){return this.check(Oi(n,i))},overwrite(n){return this.check(ye(n))},optional(){return q(this)},exactOptional(){return di(this)},nullable(){return Rt(this)},nullish(){return q(Rt(this))},nonoptional(n){return vi(this,n)},array(){return T(this)},or(n){return M([this,n])},and(n){return _t(this,n)},transform(n){return Ar(this,an(n))},default(n){return fi(this,n)},prefault(n){return hi(this,n)},catch(n){return _i(this,n)},pipe(n){return Ar(this,n)},readonly(){return zi(this)},describe(n){let i=this.clone();return X.add(i,{description:n}),i},meta(...n){if(n.length===0)return X.get(this);let i=this.clone();return X.add(i,n[0]),i},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(n){return n(this)}}),Object.defineProperty(t,"description",{get(){return X.get(t)?.description},configurable:!0}),t)),Mr=p("_ZodString",(t,r)=>{et.init(t,r),j.init(t,r),t._zod.processJSONSchema=(i,e,o)=>cu(t,i,e,o);let n=t._zod.bag;t.format=n.format??null,t.minLength=n.minimum??null,t.maxLength=n.maximum??null,Cr(t,"_ZodString",{regex(...i){return this.check(tt(...i))},includes(...i){return this.check(ot(...i))},startsWith(...i){return this.check(it(...i))},endsWith(...i){return this.check(at(...i))},min(...i){return this.check(Ie(...i))},max(...i){return this.check(Le(...i))},length(...i){return this.check(qe(...i))},nonempty(...i){return this.check(Ie(1,...i))},lowercase(i){return this.check(rt(i))},uppercase(i){return this.check(nt(i))},trim(){return this.check(ut())},normalize(...i){return this.check(ct(...i))},toLowerCase(){return this.check(lt())},toUpperCase(){return this.check(dt())},slugify(){return this.check(pt())}})}),gt=p("ZodString",(t,r)=>{et.init(t,r),Mr.init(t,r),t.email=n=>t.check(no(Lr,n)),t.url=n=>t.check($r(At,n)),t.jwt=n=>t.check(ko(rn,n)),t.emoji=n=>t.check(co(qr,n)),t.guid=n=>t.check(_r(Zt,n)),t.uuid=n=>t.check(oo(Se,n)),t.uuidv4=n=>t.check(io(Se,n)),t.uuidv6=n=>t.check(ao(Se,n)),t.uuidv7=n=>t.check(so(Se,n)),t.nanoid=n=>t.check(uo(Fr,n)),t.guid=n=>t.check(_r(Zt,n)),t.cuid=n=>t.check(lo(Jr,n)),t.cuid2=n=>t.check(po(Vr,n)),t.ulid=n=>t.check(mo(Hr,n)),t.base64=n=>t.check(_o(Yr,n)),t.base64url=n=>t.check($o(en,n)),t.xid=n=>t.check(fo(Br,n)),t.ksuid=n=>t.check(go(Wr,n)),t.ipv4=n=>t.check(ho(Kr,n)),t.ipv6=n=>t.check(vo(Gr,n)),t.cidrv4=n=>t.check(yo(Qr,n)),t.cidrv6=n=>t.check(bo(Xr,n)),t.e164=n=>t.check(xo(tn,n)),t.datetime=n=>t.check(Vu(n)),t.date=n=>t.check(Hu(n)),t.time=n=>t.check(Bu(n)),t.duration=n=>t.check(Wu(n))});A=p("ZodStringFormat",(t,r)=>{L.init(t,r),Mr.init(t,r)}),Lr=p("ZodEmail",(t,r)=>{ds.init(t,r),A.init(t,r)});Zt=p("ZodGUID",(t,r)=>{us.init(t,r),A.init(t,r)});Se=p("ZodUUID",(t,r)=>{ls.init(t,r),A.init(t,r)});At=p("ZodURL",(t,r)=>{ps.init(t,r),A.init(t,r)});qr=p("ZodEmoji",(t,r)=>{ms.init(t,r),A.init(t,r)});Fr=p("ZodNanoID",(t,r)=>{fs.init(t,r),A.init(t,r)});Jr=p("ZodCUID",(t,r)=>{gs.init(t,r),A.init(t,r)});Vr=p("ZodCUID2",(t,r)=>{hs.init(t,r),A.init(t,r)});Hr=p("ZodULID",(t,r)=>{vs.init(t,r),A.init(t,r)});Br=p("ZodXID",(t,r)=>{ys.init(t,r),A.init(t,r)});Wr=p("ZodKSUID",(t,r)=>{bs.init(t,r),A.init(t,r)});Kr=p("ZodIPv4",(t,r)=>{zs.init(t,r),A.init(t,r)});Vo=p("ZodMAC",(t,r)=>{ws.init(t,r),A.init(t,r)});Gr=p("ZodIPv6",(t,r)=>{Ss.init(t,r),A.init(t,r)});Qr=p("ZodCIDRv4",(t,r)=>{Is.init(t,r),A.init(t,r)});Xr=p("ZodCIDRv6",(t,r)=>{Ps.init(t,r),A.init(t,r)});Yr=p("ZodBase64",(t,r)=>{Ts.init(t,r),A.init(t,r)});en=p("ZodBase64URL",(t,r)=>{Os.init(t,r),A.init(t,r)});tn=p("ZodE164",(t,r)=>{Ds.init(t,r),A.init(t,r)});rn=p("ZodJWT",(t,r)=>{Us.init(t,r),A.init(t,r)});ht=p("ZodCustomStringFormat",(t,r)=>{Ns.init(t,r),A.init(t,r)});vt=p("ZodNumber",(t,r)=>{Hn.init(t,r),j.init(t,r),t._zod.processJSONSchema=(i,e,o)=>uu(t,i,e,o),Cr(t,"ZodNumber",{gt(i,e){return this.check(ke(i,e))},gte(i,e){return this.check(ae(i,e))},min(i,e){return this.check(ae(i,e))},lt(i,e){return this.check(xe(i,e))},lte(i,e){return this.check(fe(i,e))},max(i,e){return this.check(fe(i,e))},int(i){return this.check(Rr(i))},safe(i){return this.check(Rr(i))},positive(i){return this.check(ke(0,i))},nonnegative(i){return this.check(ae(0,i))},negative(i){return this.check(xe(0,i))},nonpositive(i){return this.check(fe(0,i))},multipleOf(i,e){return this.check(Te(i,e))},step(i,e){return this.check(Te(i,e))},finite(){return this}});let n=t._zod.bag;t.minValue=Math.max(n.minimum??Number.NEGATIVE_INFINITY,n.exclusiveMinimum??Number.NEGATIVE_INFINITY)??null,t.maxValue=Math.min(n.maximum??Number.POSITIVE_INFINITY,n.exclusiveMaximum??Number.POSITIVE_INFINITY)??null,t.isInt=(n.format??"").includes("int")||Number.isSafeInteger(n.multipleOf??.5),t.isFinite=!0,t.format=n.format??null});He=p("ZodNumberFormat",(t,r)=>{Es.init(t,r),vt.init(t,r)});yt=p("ZodBoolean",(t,r)=>{fr.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>lu(t,n,i,e)});bt=p("ZodBigInt",(t,r)=>{Bn.init(t,r),j.init(t,r),t._zod.processJSONSchema=(i,e,o)=>du(t,i,e,o),t.gte=(i,e)=>t.check(ae(i,e)),t.min=(i,e)=>t.check(ae(i,e)),t.gt=(i,e)=>t.check(ke(i,e)),t.gte=(i,e)=>t.check(ae(i,e)),t.min=(i,e)=>t.check(ae(i,e)),t.lt=(i,e)=>t.check(xe(i,e)),t.lte=(i,e)=>t.check(fe(i,e)),t.max=(i,e)=>t.check(fe(i,e)),t.positive=i=>t.check(ke(BigInt(0),i)),t.negative=i=>t.check(xe(BigInt(0),i)),t.nonpositive=i=>t.check(fe(BigInt(0),i)),t.nonnegative=i=>t.check(ae(BigInt(0),i)),t.multipleOf=(i,e)=>t.check(Te(i,e));let n=t._zod.bag;t.minValue=n.minimum??null,t.maxValue=n.maximum??null,t.format=n.format??null});nn=p("ZodBigIntFormat",(t,r)=>{Zs.init(t,r),bt.init(t,r)});Ho=p("ZodSymbol",(t,r)=>{Rs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>pu(t,n,i,e)});Bo=p("ZodUndefined",(t,r)=>{As.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>fu(t,n,i,e)});Wo=p("ZodNull",(t,r)=>{Cs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>mu(t,n,i,e)});Ko=p("ZodAny",(t,r)=>{Ms.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>vu(t,n,i,e)});Go=p("ZodUnknown",(t,r)=>{Ls.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>yu(t,n,i,e)});Qo=p("ZodNever",(t,r)=>{qs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>hu(t,n,i,e)});Xo=p("ZodVoid",(t,r)=>{Fs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>gu(t,n,i,e)});Mt=p("ZodDate",(t,r)=>{Js.init(t,r),j.init(t,r),t._zod.processJSONSchema=(i,e,o)=>bu(t,i,e,o),t.min=(i,e)=>t.check(ae(i,e)),t.max=(i,e)=>t.check(fe(i,e));let n=t._zod.bag;t.minDate=n.minimum?new Date(n.minimum):null,t.maxDate=n.maximum?new Date(n.maximum):null});Yo=p("ZodArray",(t,r)=>{Vs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Ou(t,n,i,e),t.element=r.element,Cr(t,"ZodArray",{min(n,i){return this.check(Ie(n,i))},nonempty(n){return this.check(Ie(1,n))},max(n,i){return this.check(Le(n,i))},length(n,i){return this.check(qe(n,i))},unwrap(){return this.element}})});Lt=p("ZodObject",(t,r)=>{Hs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Du(t,n,i,e),_.defineLazy(t,"shape",()=>r.shape),Cr(t,"ZodObject",{keyof(){return ee(Object.keys(this._zod.def.shape))},catchall(n){return this.clone({...this._zod.def,catchall:n})},passthrough(){return this.clone({...this._zod.def,catchall:C()})},loose(){return this.clone({...this._zod.def,catchall:C()})},strict(){return this.clone({...this._zod.def,catchall:on()})},strip(){return this.clone({...this._zod.def,catchall:void 0})},extend(n){return _.extend(this,n)},safeExtend(n){return _.safeExtend(this,n)},merge(n){return _.merge(this,n)},pick(n){return _.pick(this,n)},omit(n){return _.omit(this,n)},partial(...n){return _.partial(sn,this,n[0])},required(...n){return _.required(cn,this,n[0])}})});qt=p("ZodUnion",(t,r)=>{gr.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>wo(t,n,i,e),t.options=r.options});ei=p("ZodXor",(t,r)=>{qt.init(t,r),Bs.init(t,r),t._zod.processJSONSchema=(n,i,e)=>wo(t,n,i,e),t.options=r.options});ti=p("ZodDiscriminatedUnion",(t,r)=>{qt.init(t,r),Ws.init(t,r)});ri=p("ZodIntersection",(t,r)=>{Ks.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Uu(t,n,i,e)});ni=p("ZodTuple",(t,r)=>{Wn.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Nu(t,n,i,e),t.rest=n=>t.clone({...t._zod.def,rest:n})});mt=p("ZodRecord",(t,r)=>{Gs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Eu(t,n,i,e),t.keyType=r.keyType,t.valueType=r.valueType});ii=p("ZodMap",(t,r)=>{Qs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>ju(t,n,i,e),t.keyType=r.keyType,t.valueType=r.valueType,t.min=(...n)=>t.check(ze(...n)),t.nonempty=n=>t.check(ze(1,n)),t.max=(...n)=>t.check(Oe(...n)),t.size=(...n)=>t.check(Me(...n))});ai=p("ZodSet",(t,r)=>{Xs.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Tu(t,n,i,e),t.min=(...n)=>t.check(ze(...n)),t.nonempty=n=>t.check(ze(1,n)),t.max=(...n)=>t.check(Oe(...n)),t.size=(...n)=>t.check(Me(...n))});ft=p("ZodEnum",(t,r)=>{Ys.init(t,r),j.init(t,r),t._zod.processJSONSchema=(i,e,o)=>_u(t,i,e,o),t.enum=r.entries,t.options=Object.values(r.entries);let n=new Set(Object.keys(r.entries));t.extract=(i,e)=>{let o={};for(let a of i)if(n.has(a))o[a]=r.entries[a];else throw new Error(`Key ${a} not found in enum`);return new ft({...r,checks:[],..._.normalizeParams(e),entries:o})},t.exclude=(i,e)=>{let o={...r.entries};for(let a of i)if(n.has(a))delete o[a];else throw new Error(`Key ${a} not found in enum`);return new ft({...r,checks:[],..._.normalizeParams(e),entries:o})}});si=p("ZodLiteral",(t,r)=>{ec.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>$u(t,n,i,e),t.values=new Set(r.values),Object.defineProperty(t,"value",{get(){if(r.values.length>1)throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");return r.values[0]}})});ci=p("ZodFile",(t,r)=>{tc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>zu(t,n,i,e),t.min=(n,i)=>t.check(ze(n,i)),t.max=(n,i)=>t.check(Oe(n,i)),t.mime=(n,i)=>t.check(st(Array.isArray(n)?n:[n],i))});ui=p("ZodTransform",(t,r)=>{rc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Pu(t,n,i,e),t._zod.parse=(n,i)=>{if(i.direction==="backward")throw new Ee(t.constructor.name);n.addIssue=o=>{if(typeof o=="string")n.issues.push(_.issue(o,n.value,r));else{let a=o;a.fatal&&(a.continue=!1),a.code??(a.code="custom"),a.input??(a.input=n.value),a.inst??(a.inst=t),n.issues.push(_.issue(a))}};let e=r.transform(n.value,n);return e instanceof Promise?e.then(o=>(n.value=o,n.fallback=!0,n)):(n.value=e,n.fallback=!0,n)}});sn=p("ZodOptional",(t,r)=>{Kn.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Io(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});li=p("ZodExactOptional",(t,r)=>{nc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Io(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});pi=p("ZodNullable",(t,r)=>{oc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Zu(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});mi=p("ZodDefault",(t,r)=>{ic.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Au(t,n,i,e),t.unwrap=()=>t._zod.def.innerType,t.removeDefault=t.unwrap});gi=p("ZodPrefault",(t,r)=>{ac.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Cu(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});cn=p("ZodNonOptional",(t,r)=>{sc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Ru(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});yi=p("ZodSuccess",(t,r)=>{cc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Su(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});bi=p("ZodCatch",(t,r)=>{uc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Mu(t,n,i,e),t.unwrap=()=>t._zod.def.innerType,t.removeCatch=t.unwrap});$i=p("ZodNaN",(t,r)=>{lc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>xu(t,n,i,e)});Jt=p("ZodPipe",(t,r)=>{Gn.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Lu(t,n,i,e),t.in=r.in,t.out=r.out});Vt=p("ZodCodec",(t,r)=>{Jt.init(t,r),hr.init(t,r)});xi=p("ZodPreprocess",(t,r)=>{Jt.init(t,r),dc.init(t,r)}),ki=p("ZodReadonly",(t,r)=>{pc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>qu(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});Si=p("ZodTemplateLiteral",(t,r)=>{mc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>ku(t,n,i,e)});wi=p("ZodLazy",(t,r)=>{hc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Ju(t,n,i,e),t.unwrap=()=>t._zod.def.getter()});Pi=p("ZodPromise",(t,r)=>{gc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Fu(t,n,i,e),t.unwrap=()=>t._zod.def.innerType});ji=p("ZodFunction",(t,r)=>{fc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>Iu(t,n,i,e)});Ht=p("ZodCustom",(t,r)=>{vc.init(t,r),j.init(t,r),t._zod.processJSONSchema=(n,i,e)=>wu(t,n,i,e)});td=ou,rd=iu;od=(...t)=>au({Codec:Vt,Boolean:yt,String:gt},...t)});function Tf(t){H({customError:t})}function Of(){return H().customError}var jf,Di,Df=x(()=>{ge();jf={invalid_type:"invalid_type",too_big:"too_big",too_small:"too_small",invalid_format:"invalid_format",not_multiple_of:"not_multiple_of",unrecognized_keys:"unrecognized_keys",invalid_union:"invalid_union",invalid_key:"invalid_key",invalid_element:"invalid_element",invalid_value:"invalid_value",custom:"custom"};Di||(Di={})});function Nv(t,r){let n=t.$schema;return n==="https://json-schema.org/draft/2020-12/schema"?"draft-2020-12":n==="http://json-schema.org/draft-07/schema#"?"draft-7":n==="http://json-schema.org/draft-04/schema#"?"draft-4":r??"draft-2020-12"}function Ev(t,r){if(!t.startsWith("#"))throw new Error("External $ref is not supported, only local refs (#/...) are allowed");let n=t.slice(1).split("/").filter(Boolean);if(n.length===0)return r.rootSchema;let i=r.version==="draft-2020-12"?"$defs":"definitions";if(n[0]===i){let e=n[1];if(!e||!r.defs[e])throw new Error(`Reference not found: ${t}`);return r.defs[e]}throw new Error(`Reference not found: ${t}`)}function Uf(t,r){if(t.not!==void 0){if(typeof t.not=="object"&&Object.keys(t.not).length===0)return k.never();throw new Error("not is not supported in Zod (except { not: {} } for never)")}if(t.unevaluatedItems!==void 0)throw new Error("unevaluatedItems is not supported");if(t.unevaluatedProperties!==void 0)throw new Error("unevaluatedProperties is not supported");if(t.if!==void 0||t.then!==void 0||t.else!==void 0)throw new Error("Conditional schemas (if/then/else) are not supported");if(t.dependentSchemas!==void 0||t.dependentRequired!==void 0)throw new Error("dependentSchemas and dependentRequired are not supported");if(t.$ref){let e=t.$ref;if(r.refs.has(e))return r.refs.get(e);if(r.processing.has(e))return k.lazy(()=>{if(!r.refs.has(e))throw new Error(`Circular reference not resolved: ${e}`);return r.refs.get(e)});r.processing.add(e);let o=Ev(e,r),a=se(o,r);return r.refs.set(e,a),r.processing.delete(e),a}if(t.enum!==void 0){let e=t.enum;if(r.version==="openapi-3.0"&&t.nullable===!0&&e.length===1&&e[0]===null)return k.null();if(e.length===0)return k.never();if(e.length===1)return k.literal(e[0]);if(e.every(a=>typeof a=="string"))return k.enum(e);let o=e.map(a=>k.literal(a));return o.length<2?o[0]:k.union([o[0],o[1],...o.slice(2)])}if(t.const!==void 0)return k.literal(t.const);let n=t.type;if(Array.isArray(n)){let e=n.map(o=>{let a={...t,type:o};return Uf(a,r)});return e.length===0?k.never():e.length===1?e[0]:k.union(e)}if(!n)return k.any();let i;switch(n){case"string":{let e=k.string();if(t.format){let o=t.format;o==="email"?e=e.check(k.email()):o==="uri"||o==="uri-reference"?e=e.check(k.url()):o==="uuid"||o==="guid"?e=e.check(k.uuid()):o==="date-time"?e=e.check(k.iso.datetime()):o==="date"?e=e.check(k.iso.date()):o==="time"?e=e.check(k.iso.time()):o==="duration"?e=e.check(k.iso.duration()):o==="ipv4"?e=e.check(k.ipv4()):o==="ipv6"?e=e.check(k.ipv6()):o==="mac"?e=e.check(k.mac()):o==="cidr"?e=e.check(k.cidrv4()):o==="cidr-v6"?e=e.check(k.cidrv6()):o==="base64"?e=e.check(k.base64()):o==="base64url"?e=e.check(k.base64url()):o==="e164"?e=e.check(k.e164()):o==="jwt"?e=e.check(k.jwt()):o==="emoji"?e=e.check(k.emoji()):o==="nanoid"?e=e.check(k.nanoid()):o==="cuid"?e=e.check(k.cuid()):o==="cuid2"?e=e.check(k.cuid2()):o==="ulid"?e=e.check(k.ulid()):o==="xid"?e=e.check(k.xid()):o==="ksuid"&&(e=e.check(k.ksuid()))}typeof t.minLength=="number"&&(e=e.min(t.minLength)),typeof t.maxLength=="number"&&(e=e.max(t.maxLength)),t.pattern&&(e=e.regex(new RegExp(t.pattern))),i=e;break}case"number":case"integer":{let e=n==="integer"?k.number().int():k.number();typeof t.minimum=="number"&&(e=e.min(t.minimum)),typeof t.maximum=="number"&&(e=e.max(t.maximum)),typeof t.exclusiveMinimum=="number"?e=e.gt(t.exclusiveMinimum):t.exclusiveMinimum===!0&&typeof t.minimum=="number"&&(e=e.gt(t.minimum)),typeof t.exclusiveMaximum=="number"?e=e.lt(t.exclusiveMaximum):t.exclusiveMaximum===!0&&typeof t.maximum=="number"&&(e=e.lt(t.maximum)),typeof t.multipleOf=="number"&&(e=e.multipleOf(t.multipleOf)),i=e;break}case"boolean":{i=k.boolean();break}case"null":{i=k.null();break}case"object":{let e={},o=t.properties||{},a=new Set(t.required||[]);for(let[c,u]of Object.entries(o)){let d=se(u,r);e[c]=a.has(c)?d:d.optional()}if(t.propertyNames){let c=se(t.propertyNames,r),u=t.additionalProperties&&typeof t.additionalProperties=="object"?se(t.additionalProperties,r):k.any();if(Object.keys(e).length===0){i=k.record(c,u);break}let d=k.object(e).passthrough(),m=k.looseRecord(c,u);i=k.intersection(d,m);break}if(t.patternProperties){let c=t.patternProperties,u=Object.keys(c),d=[];for(let h of u){let v=se(c[h],r),S=k.string().regex(new RegExp(h));d.push(k.looseRecord(S,v))}let m=[];if(Object.keys(e).length>0&&m.push(k.object(e).passthrough()),m.push(...d),m.length===0)i=k.object({}).passthrough();else if(m.length===1)i=m[0];else{let h=k.intersection(m[0],m[1]);for(let v=2;vse(c,r)),s=o&&typeof o=="object"&&!Array.isArray(o)?se(o,r):void 0;s?i=k.tuple(a).rest(s):i=k.tuple(a),typeof t.minItems=="number"&&(i=i.check(k.minLength(t.minItems))),typeof t.maxItems=="number"&&(i=i.check(k.maxLength(t.maxItems)))}else if(Array.isArray(o)){let a=o.map(c=>se(c,r)),s=t.additionalItems&&typeof t.additionalItems=="object"?se(t.additionalItems,r):void 0;s?i=k.tuple(a).rest(s):i=k.tuple(a),typeof t.minItems=="number"&&(i=i.check(k.minLength(t.minItems))),typeof t.maxItems=="number"&&(i=i.check(k.maxLength(t.maxItems)))}else if(o!==void 0){let a=se(o,r),s=k.array(a);typeof t.minItems=="number"&&(s=s.min(t.minItems)),typeof t.maxItems=="number"&&(s=s.max(t.maxItems)),i=s}else i=k.array(k.any());break}default:throw new Error(`Unsupported type: ${n}`)}return i}function se(t,r){if(typeof t=="boolean")return t?k.any():k.never();let n=Uf(t,r),i=t.type||t.enum!==void 0||t.const!==void 0;if(t.anyOf&&Array.isArray(t.anyOf)){let s=t.anyOf.map(u=>se(u,r)),c=k.union(s);n=i?k.intersection(n,c):c}if(t.oneOf&&Array.isArray(t.oneOf)){let s=t.oneOf.map(u=>se(u,r)),c=k.xor(s);n=i?k.intersection(n,c):c}if(t.allOf&&Array.isArray(t.allOf))if(t.allOf.length===0)n=i?n:k.any();else{let s=i?n:se(t.allOf[0],r),c=i?0:1;for(let u=c;u0&&r.registry.add(n,e),t.description&&(n=n.describe(t.description)),n}function ad(t,r){if(typeof t=="boolean")return t?k.any():k.never();let n;try{n=JSON.parse(JSON.stringify(t))}catch{throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas")}let i=Nv(n,r?.defaultTarget),e=n.$defs||n.definitions||{},o={version:i,defs:e,refs:new Map,processing:new Set,rootSchema:n,registry:r?.registry??X};return se(n,o)}var k,Uv,Nf=x(()=>{br();Do();Nr();Zr();k={...Er,...Oo,iso:De},Uv=new Set(["$schema","$ref","$defs","definitions","$id","id","$comment","$anchor","$vocabulary","$dynamicRef","$dynamicAnchor","type","enum","const","anyOf","oneOf","allOf","not","properties","required","additionalProperties","patternProperties","propertyNames","minProperties","maxProperties","items","prefixItems","additionalItems","minItems","maxItems","uniqueItems","contains","minContains","maxContains","minLength","maxLength","pattern","format","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","description","default","contentEncoding","contentMediaType","contentSchema","unevaluatedItems","unevaluatedProperties","if","then","else","dependentSchemas","dependentRequired","nullable","readOnly"])});var Ui={};we(Ui,{bigint:()=>Cv,boolean:()=>Av,date:()=>Mv,number:()=>Rv,string:()=>Zv});function Zv(t){return zc(gt,t)}function Rv(t){return Oc(vt,t)}function Av(t){return Ac(yt,t)}function Cv(t){return Mc(bt,t)}function Mv(t){return Qc(Mt,t)}var Ef=x(()=>{ge();Zr()});var l={};we(l,{$brand:()=>kn,$input:()=>ro,$output:()=>to,NEVER:()=>xn,TimePrecision:()=>zo,ZodAny:()=>Ko,ZodArray:()=>Yo,ZodBase64:()=>Yr,ZodBase64URL:()=>en,ZodBigInt:()=>bt,ZodBigIntFormat:()=>nn,ZodBoolean:()=>yt,ZodCIDRv4:()=>Qr,ZodCIDRv6:()=>Xr,ZodCUID:()=>Jr,ZodCUID2:()=>Vr,ZodCatch:()=>bi,ZodCodec:()=>Vt,ZodCustom:()=>Ht,ZodCustomStringFormat:()=>ht,ZodDate:()=>Mt,ZodDefault:()=>mi,ZodDiscriminatedUnion:()=>ti,ZodE164:()=>tn,ZodEmail:()=>Lr,ZodEmoji:()=>qr,ZodEnum:()=>ft,ZodError:()=>If,ZodExactOptional:()=>li,ZodFile:()=>ci,ZodFirstPartyTypeKind:()=>Di,ZodFunction:()=>ji,ZodGUID:()=>Zt,ZodIPv4:()=>Kr,ZodIPv6:()=>Gr,ZodISODate:()=>Or,ZodISODateTime:()=>Tr,ZodISODuration:()=>Ur,ZodISOTime:()=>Dr,ZodIntersection:()=>ri,ZodIssueCode:()=>jf,ZodJWT:()=>rn,ZodKSUID:()=>Wr,ZodLazy:()=>wi,ZodLiteral:()=>si,ZodMAC:()=>Vo,ZodMap:()=>ii,ZodNaN:()=>$i,ZodNanoID:()=>Fr,ZodNever:()=>Qo,ZodNonOptional:()=>cn,ZodNull:()=>Wo,ZodNullable:()=>pi,ZodNumber:()=>vt,ZodNumberFormat:()=>He,ZodObject:()=>Lt,ZodOptional:()=>sn,ZodPipe:()=>Jt,ZodPrefault:()=>gi,ZodPreprocess:()=>xi,ZodPromise:()=>Pi,ZodReadonly:()=>ki,ZodRealError:()=>le,ZodRecord:()=>mt,ZodSet:()=>ai,ZodString:()=>gt,ZodStringFormat:()=>A,ZodSuccess:()=>yi,ZodSymbol:()=>Ho,ZodTemplateLiteral:()=>Si,ZodTransform:()=>ui,ZodTuple:()=>ni,ZodType:()=>j,ZodULID:()=>Hr,ZodURL:()=>At,ZodUUID:()=>Se,ZodUndefined:()=>Bo,ZodUnion:()=>qt,ZodUnknown:()=>Go,ZodVoid:()=>Xo,ZodXID:()=>Br,ZodXor:()=>ei,_ZodString:()=>Mr,_default:()=>fi,_function:()=>Yl,any:()=>Nl,array:()=>T,base64:()=>vl,base64url:()=>yl,bigint:()=>jl,boolean:()=>W,catch:()=>_i,check:()=>ed,cidrv4:()=>gl,cidrv6:()=>hl,clone:()=>ie,codec:()=>Kl,coerce:()=>Ui,config:()=>H,core:()=>Pe,cuid:()=>sl,cuid2:()=>cl,custom:()=>un,date:()=>Zl,decode:()=>Ao,decodeAsync:()=>Mo,describe:()=>td,discriminatedUnion:()=>Ft,e164:()=>bl,email:()=>Qu,emoji:()=>il,encode:()=>Ro,encodeAsync:()=>Co,endsWith:()=>at,enum:()=>ee,exactOptional:()=>di,file:()=>Vl,flattenError:()=>zt,float32:()=>Sl,float64:()=>wl,formatError:()=>St,fromJSONSchema:()=>ad,function:()=>Yl,getErrorMap:()=>Of,globalRegistry:()=>X,gt:()=>ke,gte:()=>ae,guid:()=>Xu,hash:()=>zl,hex:()=>kl,hostname:()=>xl,httpUrl:()=>ol,includes:()=>ot,instanceof:()=>nd,int:()=>Rr,int32:()=>Il,int64:()=>Tl,intersection:()=>_t,invertCodec:()=>Gl,ipv4:()=>pl,ipv6:()=>fl,iso:()=>De,json:()=>id,jwt:()=>_l,keyof:()=>Rl,ksuid:()=>dl,lazy:()=>Ii,length:()=>qe,literal:()=>I,locales:()=>Ut,looseObject:()=>Y,looseRecord:()=>Ll,lowercase:()=>rt,lt:()=>xe,lte:()=>fe,mac:()=>ml,map:()=>ql,maxLength:()=>Le,maxSize:()=>Oe,meta:()=>rd,mime:()=>st,minLength:()=>Ie,minSize:()=>ze,multipleOf:()=>Te,nan:()=>Wl,nanoid:()=>al,nativeEnum:()=>Jl,negative:()=>kr,never:()=>on,nonnegative:()=>Sr,nonoptional:()=>vi,nonpositive:()=>zr,normalize:()=>ct,null:()=>Ct,nullable:()=>Rt,nullish:()=>Hl,number:()=>D,object:()=>z,optional:()=>q,overwrite:()=>ye,parse:()=>Uo,parseAsync:()=>No,partialRecord:()=>Ml,pipe:()=>Ar,positive:()=>xr,prefault:()=>hi,preprocess:()=>Bt,prettifyError:()=>In,promise:()=>Xl,property:()=>wr,readonly:()=>zi,record:()=>Z,refine:()=>Ti,regex:()=>tt,regexes:()=>me,registry:()=>yr,safeDecode:()=>qo,safeDecodeAsync:()=>Jo,safeEncode:()=>Lo,safeEncodeAsync:()=>Fo,safeParse:()=>Eo,safeParseAsync:()=>Zo,set:()=>Fl,setErrorMap:()=>Tf,size:()=>Me,slugify:()=>pt,startsWith:()=>it,strictObject:()=>Al,string:()=>g,stringFormat:()=>$l,stringbool:()=>od,success:()=>Bl,superRefine:()=>Oi,symbol:()=>Dl,templateLiteral:()=>Ql,toJSONSchema:()=>Pr,toLowerCase:()=>lt,toUpperCase:()=>dt,transform:()=>an,treeifyError:()=>wn,trim:()=>ut,tuple:()=>oi,uint32:()=>Pl,uint64:()=>Ol,ulid:()=>ul,undefined:()=>Ul,union:()=>M,unknown:()=>C,uppercase:()=>nt,url:()=>nl,util:()=>_,uuid:()=>Yu,uuidv4:()=>el,uuidv6:()=>tl,uuidv7:()=>rl,void:()=>El,xid:()=>ll,xor:()=>Cl});var sd=x(()=>{ge();Zr();Do();Ku();Gu();Df();ge();bc();ge();jr();Nf();xc();Nr();Nr();Ef();H(Qn())});var Zf,cd=x(()=>{sd();sd();Zf=l});var ud={};we(ud,{$brand:()=>kn,$input:()=>ro,$output:()=>to,NEVER:()=>xn,TimePrecision:()=>zo,ZodAny:()=>Ko,ZodArray:()=>Yo,ZodBase64:()=>Yr,ZodBase64URL:()=>en,ZodBigInt:()=>bt,ZodBigIntFormat:()=>nn,ZodBoolean:()=>yt,ZodCIDRv4:()=>Qr,ZodCIDRv6:()=>Xr,ZodCUID:()=>Jr,ZodCUID2:()=>Vr,ZodCatch:()=>bi,ZodCodec:()=>Vt,ZodCustom:()=>Ht,ZodCustomStringFormat:()=>ht,ZodDate:()=>Mt,ZodDefault:()=>mi,ZodDiscriminatedUnion:()=>ti,ZodE164:()=>tn,ZodEmail:()=>Lr,ZodEmoji:()=>qr,ZodEnum:()=>ft,ZodError:()=>If,ZodExactOptional:()=>li,ZodFile:()=>ci,ZodFirstPartyTypeKind:()=>Di,ZodFunction:()=>ji,ZodGUID:()=>Zt,ZodIPv4:()=>Kr,ZodIPv6:()=>Gr,ZodISODate:()=>Or,ZodISODateTime:()=>Tr,ZodISODuration:()=>Ur,ZodISOTime:()=>Dr,ZodIntersection:()=>ri,ZodIssueCode:()=>jf,ZodJWT:()=>rn,ZodKSUID:()=>Wr,ZodLazy:()=>wi,ZodLiteral:()=>si,ZodMAC:()=>Vo,ZodMap:()=>ii,ZodNaN:()=>$i,ZodNanoID:()=>Fr,ZodNever:()=>Qo,ZodNonOptional:()=>cn,ZodNull:()=>Wo,ZodNullable:()=>pi,ZodNumber:()=>vt,ZodNumberFormat:()=>He,ZodObject:()=>Lt,ZodOptional:()=>sn,ZodPipe:()=>Jt,ZodPrefault:()=>gi,ZodPreprocess:()=>xi,ZodPromise:()=>Pi,ZodReadonly:()=>ki,ZodRealError:()=>le,ZodRecord:()=>mt,ZodSet:()=>ai,ZodString:()=>gt,ZodStringFormat:()=>A,ZodSuccess:()=>yi,ZodSymbol:()=>Ho,ZodTemplateLiteral:()=>Si,ZodTransform:()=>ui,ZodTuple:()=>ni,ZodType:()=>j,ZodULID:()=>Hr,ZodURL:()=>At,ZodUUID:()=>Se,ZodUndefined:()=>Bo,ZodUnion:()=>qt,ZodUnknown:()=>Go,ZodVoid:()=>Xo,ZodXID:()=>Br,ZodXor:()=>ei,_ZodString:()=>Mr,_default:()=>fi,_function:()=>Yl,any:()=>Nl,array:()=>T,base64:()=>vl,base64url:()=>yl,bigint:()=>jl,boolean:()=>W,catch:()=>_i,check:()=>ed,cidrv4:()=>gl,cidrv6:()=>hl,clone:()=>ie,codec:()=>Kl,coerce:()=>Ui,config:()=>H,core:()=>Pe,cuid:()=>sl,cuid2:()=>cl,custom:()=>un,date:()=>Zl,decode:()=>Ao,decodeAsync:()=>Mo,default:()=>Lv,describe:()=>td,discriminatedUnion:()=>Ft,e164:()=>bl,email:()=>Qu,emoji:()=>il,encode:()=>Ro,encodeAsync:()=>Co,endsWith:()=>at,enum:()=>ee,exactOptional:()=>di,file:()=>Vl,flattenError:()=>zt,float32:()=>Sl,float64:()=>wl,formatError:()=>St,fromJSONSchema:()=>ad,function:()=>Yl,getErrorMap:()=>Of,globalRegistry:()=>X,gt:()=>ke,gte:()=>ae,guid:()=>Xu,hash:()=>zl,hex:()=>kl,hostname:()=>xl,httpUrl:()=>ol,includes:()=>ot,instanceof:()=>nd,int:()=>Rr,int32:()=>Il,int64:()=>Tl,intersection:()=>_t,invertCodec:()=>Gl,ipv4:()=>pl,ipv6:()=>fl,iso:()=>De,json:()=>id,jwt:()=>_l,keyof:()=>Rl,ksuid:()=>dl,lazy:()=>Ii,length:()=>qe,literal:()=>I,locales:()=>Ut,looseObject:()=>Y,looseRecord:()=>Ll,lowercase:()=>rt,lt:()=>xe,lte:()=>fe,mac:()=>ml,map:()=>ql,maxLength:()=>Le,maxSize:()=>Oe,meta:()=>rd,mime:()=>st,minLength:()=>Ie,minSize:()=>ze,multipleOf:()=>Te,nan:()=>Wl,nanoid:()=>al,nativeEnum:()=>Jl,negative:()=>kr,never:()=>on,nonnegative:()=>Sr,nonoptional:()=>vi,nonpositive:()=>zr,normalize:()=>ct,null:()=>Ct,nullable:()=>Rt,nullish:()=>Hl,number:()=>D,object:()=>z,optional:()=>q,overwrite:()=>ye,parse:()=>Uo,parseAsync:()=>No,partialRecord:()=>Ml,pipe:()=>Ar,positive:()=>xr,prefault:()=>hi,preprocess:()=>Bt,prettifyError:()=>In,promise:()=>Xl,property:()=>wr,readonly:()=>zi,record:()=>Z,refine:()=>Ti,regex:()=>tt,regexes:()=>me,registry:()=>yr,safeDecode:()=>qo,safeDecodeAsync:()=>Jo,safeEncode:()=>Lo,safeEncodeAsync:()=>Fo,safeParse:()=>Eo,safeParseAsync:()=>Zo,set:()=>Fl,setErrorMap:()=>Tf,size:()=>Me,slugify:()=>pt,startsWith:()=>it,strictObject:()=>Al,string:()=>g,stringFormat:()=>$l,stringbool:()=>od,success:()=>Bl,superRefine:()=>Oi,symbol:()=>Dl,templateLiteral:()=>Ql,toJSONSchema:()=>Pr,toLowerCase:()=>lt,toUpperCase:()=>dt,transform:()=>an,treeifyError:()=>wn,trim:()=>ut,tuple:()=>oi,uint32:()=>Pl,uint64:()=>Ol,ulid:()=>ul,undefined:()=>Ul,union:()=>M,unknown:()=>C,uppercase:()=>nt,url:()=>nl,util:()=>_,uuid:()=>Yu,uuidv4:()=>el,uuidv6:()=>tl,uuidv7:()=>rl,void:()=>El,xid:()=>ll,xor:()=>Cl,z:()=>l});var Lv,ln=x(()=>{cd();cd();Lv=Zf});ge();function jo(t){return!!t._zod}function To(t,r){return jo(t)?jt(t,r):t.safeParse(r)}function zf(t){if(!t)return;let r;if(jo(t)?r=t._zod?.def?.shape:r=t.shape,!!r){if(typeof r=="function")try{return r()}catch{return}return r}}function Sf(t){if(jo(t)){let o=t._zod?.def;if(o){if(o.value!==void 0)return o.value;if(Array.isArray(o.values)&&o.values.length>0)return o.values[0]}}let n=t._def;if(n){if(n.value!==void 0)return n.value;if(Array.isArray(n.values)&&n.values.length>0)return n.values[0]}let i=t.value;if(i!==void 0)return i}ln();var Be="io.modelcontextprotocol/related-task",Ei="2.0",K=un(t=>t!==null&&(typeof t=="object"||typeof t=="function")),Rf=M([g(),D().int()]),Af=g(),ck=Y({ttl:D().optional(),pollInterval:D().optional()}),qv=z({ttl:D().optional()}),Fv=z({taskId:g()}),dd=Y({progressToken:Rf.optional(),[Be]:Fv.optional()}),he=z({_meta:dd.optional()}),dn=he.extend({task:qv.optional()}),Cf=t=>dn.safeParse(t).success,re=z({method:g(),params:he.loose().optional()}),be=z({_meta:dd.optional()}),_e=z({method:g(),params:be.loose().optional()}),ne=Y({_meta:dd.optional()}),Kt=M([g(),D().int()]),Mf=z({jsonrpc:I(Ei),id:Kt,...re.shape}).strict(),pd=t=>Mf.safeParse(t).success,Lf=z({jsonrpc:I(Ei),..._e.shape}).strict(),qf=t=>Lf.safeParse(t).success,md=z({jsonrpc:I(Ei),id:Kt,result:ne}).strict(),pn=t=>md.safeParse(t).success;var R;(function(t){t[t.ConnectionClosed=-32e3]="ConnectionClosed",t[t.RequestTimeout=-32001]="RequestTimeout",t[t.ParseError=-32700]="ParseError",t[t.InvalidRequest=-32600]="InvalidRequest",t[t.MethodNotFound=-32601]="MethodNotFound",t[t.InvalidParams=-32602]="InvalidParams",t[t.InternalError=-32603]="InternalError",t[t.UrlElicitationRequired=-32042]="UrlElicitationRequired"})(R||(R={}));var fd=z({jsonrpc:I(Ei),id:Kt.optional(),error:z({code:D().int(),message:g(),data:C().optional()})}).strict();var Ff=t=>fd.safeParse(t).success;var Jf=M([Mf,Lf,md,fd]),uk=M([md,fd]),Zi=ne.strict(),Jv=be.extend({requestId:Kt.optional(),reason:g().optional()}),Ri=_e.extend({method:I("notifications/cancelled"),params:Jv}),Vv=z({src:g(),mimeType:g().optional(),sizes:T(g()).optional(),theme:ee(["light","dark"]).optional()}),mn=z({icons:T(Vv).optional()}),Wt=z({name:g(),title:g().optional()}),fn=Wt.extend({...Wt.shape,...mn.shape,version:g(),websiteUrl:g().optional(),description:g().optional()}),Hv=_t(z({applyDefaults:W().optional()}),Z(g(),C())),Bv=Bt(t=>t&&typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length===0?{form:{}}:t,_t(z({form:Hv.optional(),url:K.optional()}),Z(g(),C()).optional())),Wv=Y({list:K.optional(),cancel:K.optional(),requests:Y({sampling:Y({createMessage:K.optional()}).optional(),elicitation:Y({create:K.optional()}).optional()}).optional()}),Kv=Y({list:K.optional(),cancel:K.optional(),requests:Y({tools:Y({call:K.optional()}).optional()}).optional()}),Gv=z({experimental:Z(g(),K).optional(),sampling:z({context:K.optional(),tools:K.optional()}).optional(),elicitation:Bv.optional(),roots:z({listChanged:W().optional()}).optional(),tasks:Wv.optional(),extensions:Z(g(),K).optional()}),Qv=he.extend({protocolVersion:g(),capabilities:Gv,clientInfo:fn}),Xv=re.extend({method:I("initialize"),params:Qv});var Yv=z({experimental:Z(g(),K).optional(),logging:K.optional(),completions:K.optional(),prompts:z({listChanged:W().optional()}).optional(),resources:z({subscribe:W().optional(),listChanged:W().optional()}).optional(),tools:z({listChanged:W().optional()}).optional(),tasks:Kv.optional(),extensions:Z(g(),K).optional()}),ey=ne.extend({protocolVersion:g(),capabilities:Yv,serverInfo:fn,instructions:g().optional()}),ty=_e.extend({method:I("notifications/initialized"),params:be.optional()});var Gt=re.extend({method:I("ping"),params:he.optional()}),ry=z({progress:D(),total:q(D()),message:q(g())}),ny=z({...be.shape,...ry.shape,progressToken:Rf}),Ai=_e.extend({method:I("notifications/progress"),params:ny}),oy=he.extend({cursor:Af.optional()}),gn=re.extend({params:oy.optional()}),hn=ne.extend({nextCursor:Af.optional()}),iy=ee(["working","input_required","completed","failed","cancelled"]),vn=z({taskId:g(),status:iy,ttl:M([D(),Ct()]),createdAt:g(),lastUpdatedAt:g(),pollInterval:q(D()),statusMessage:q(g())}),Ci=ne.extend({task:vn}),ay=be.merge(vn),yn=_e.extend({method:I("notifications/tasks/status"),params:ay}),Mi=re.extend({method:I("tasks/get"),params:he.extend({taskId:g()})}),Li=ne.merge(vn),qi=re.extend({method:I("tasks/result"),params:he.extend({taskId:g()})}),lk=ne.loose(),Fi=gn.extend({method:I("tasks/list")}),Ji=hn.extend({tasks:T(vn)}),Vi=re.extend({method:I("tasks/cancel"),params:he.extend({taskId:g()})}),Vf=ne.merge(vn),Hf=z({uri:g(),mimeType:q(g()),_meta:Z(g(),C()).optional()}),Bf=Hf.extend({text:g()}),gd=g().refine(t=>{try{return atob(t),!0}catch{return!1}},{message:"Invalid Base64 string"}),Wf=Hf.extend({blob:gd}),bn=ee(["user","assistant"]),Qt=z({audience:T(bn).optional(),priority:D().min(0).max(1).optional(),lastModified:De.datetime({offset:!0}).optional()}),Kf=z({...Wt.shape,...mn.shape,uri:g(),description:q(g()),mimeType:q(g()),size:q(D()),annotations:Qt.optional(),_meta:q(Y({}))}),sy=z({...Wt.shape,...mn.shape,uriTemplate:g(),description:q(g()),mimeType:q(g()),annotations:Qt.optional(),_meta:q(Y({}))}),cy=gn.extend({method:I("resources/list")}),hd=hn.extend({resources:T(Kf)}),uy=gn.extend({method:I("resources/templates/list")}),ly=hn.extend({resourceTemplates:T(sy)}),vd=he.extend({uri:g()}),dy=vd,py=re.extend({method:I("resources/read"),params:dy}),yd=ne.extend({contents:T(M([Bf,Wf]))}),my=_e.extend({method:I("notifications/resources/list_changed"),params:be.optional()}),fy=vd,gy=re.extend({method:I("resources/subscribe"),params:fy}),hy=vd,vy=re.extend({method:I("resources/unsubscribe"),params:hy}),yy=be.extend({uri:g()}),by=_e.extend({method:I("notifications/resources/updated"),params:yy}),_y=z({name:g(),description:q(g()),required:q(W())}),$y=z({...Wt.shape,...mn.shape,description:q(g()),arguments:q(T(_y)),_meta:q(Y({}))}),xy=gn.extend({method:I("prompts/list")}),ky=hn.extend({prompts:T($y)}),zy=he.extend({name:g(),arguments:Z(g(),g()).optional()}),Sy=re.extend({method:I("prompts/get"),params:zy}),bd=z({type:I("text"),text:g(),annotations:Qt.optional(),_meta:Z(g(),C()).optional()}),_d=z({type:I("image"),data:gd,mimeType:g(),annotations:Qt.optional(),_meta:Z(g(),C()).optional()}),$d=z({type:I("audio"),data:gd,mimeType:g(),annotations:Qt.optional(),_meta:Z(g(),C()).optional()}),wy=z({type:I("tool_use"),name:g(),id:g(),input:Z(g(),C()),_meta:Z(g(),C()).optional()}),xd=z({type:I("resource"),resource:M([Bf,Wf]),annotations:Qt.optional(),_meta:Z(g(),C()).optional()}),kd=Kf.extend({type:I("resource_link")}),Xt=M([bd,_d,$d,kd,xd]),Iy=z({role:bn,content:Xt}),Py=ne.extend({description:g().optional(),messages:T(Iy)}),jy=_e.extend({method:I("notifications/prompts/list_changed"),params:be.optional()}),Ty=z({title:g().optional(),readOnlyHint:W().optional(),destructiveHint:W().optional(),idempotentHint:W().optional(),openWorldHint:W().optional()}),Oy=z({taskSupport:ee(["required","optional","forbidden"]).optional()}),Hi=z({...Wt.shape,...mn.shape,description:g().optional(),inputSchema:z({type:I("object"),properties:Z(g(),K).optional(),required:T(g()).optional()}).catchall(C()),outputSchema:z({type:I("object"),properties:Z(g(),K).optional(),required:T(g()).optional()}).catchall(C()).optional(),annotations:Ty.optional(),execution:Oy.optional(),_meta:Z(g(),C()).optional()}),zd=gn.extend({method:I("tools/list")}),Dy=hn.extend({tools:T(Hi)}),Yt=ne.extend({content:T(Xt).default([]),structuredContent:Z(g(),C()).optional(),isError:W().optional()}),dk=Yt.or(ne.extend({toolResult:C()})),Uy=dn.extend({name:g(),arguments:Z(g(),C()).optional()}),Sd=re.extend({method:I("tools/call"),params:Uy}),Ny=_e.extend({method:I("notifications/tools/list_changed"),params:be.optional()}),pk=z({autoRefresh:W().default(!0),debounceMs:D().int().nonnegative().default(300)}),Gf=ee(["debug","info","notice","warning","error","critical","alert","emergency"]),Ey=he.extend({level:Gf}),Zy=re.extend({method:I("logging/setLevel"),params:Ey}),Ry=be.extend({level:Gf,logger:g().optional(),data:C()}),Ay=_e.extend({method:I("notifications/message"),params:Ry}),Cy=z({name:g().optional()}),My=z({hints:T(Cy).optional(),costPriority:D().min(0).max(1).optional(),speedPriority:D().min(0).max(1).optional(),intelligencePriority:D().min(0).max(1).optional()}),Ly=z({mode:ee(["auto","required","none"]).optional()}),qy=z({type:I("tool_result"),toolUseId:g().describe("The unique identifier for the corresponding tool call."),content:T(Xt).default([]),structuredContent:z({}).loose().optional(),isError:W().optional(),_meta:Z(g(),C()).optional()}),Fy=Ft("type",[bd,_d,$d]),Ni=Ft("type",[bd,_d,$d,wy,qy]),Jy=z({role:bn,content:M([Ni,T(Ni)]),_meta:Z(g(),C()).optional()}),Vy=dn.extend({messages:T(Jy),modelPreferences:My.optional(),systemPrompt:g().optional(),includeContext:ee(["none","thisServer","allServers"]).optional(),temperature:D().optional(),maxTokens:D().int(),stopSequences:T(g()).optional(),metadata:K.optional(),tools:T(Hi).optional(),toolChoice:Ly.optional()}),Hy=re.extend({method:I("sampling/createMessage"),params:Vy}),wd=ne.extend({model:g(),stopReason:q(ee(["endTurn","stopSequence","maxTokens"]).or(g())),role:bn,content:Fy}),Id=ne.extend({model:g(),stopReason:q(ee(["endTurn","stopSequence","maxTokens","toolUse"]).or(g())),role:bn,content:M([Ni,T(Ni)])}),By=z({type:I("boolean"),title:g().optional(),description:g().optional(),default:W().optional()}),Wy=z({type:I("string"),title:g().optional(),description:g().optional(),minLength:D().optional(),maxLength:D().optional(),format:ee(["email","uri","date","date-time"]).optional(),default:g().optional()}),Ky=z({type:ee(["number","integer"]),title:g().optional(),description:g().optional(),minimum:D().optional(),maximum:D().optional(),default:D().optional()}),Gy=z({type:I("string"),title:g().optional(),description:g().optional(),enum:T(g()),default:g().optional()}),Qy=z({type:I("string"),title:g().optional(),description:g().optional(),oneOf:T(z({const:g(),title:g()})),default:g().optional()}),Xy=z({type:I("string"),title:g().optional(),description:g().optional(),enum:T(g()),enumNames:T(g()).optional(),default:g().optional()}),Yy=M([Gy,Qy]),eb=z({type:I("array"),title:g().optional(),description:g().optional(),minItems:D().optional(),maxItems:D().optional(),items:z({type:I("string"),enum:T(g())}),default:T(g()).optional()}),tb=z({type:I("array"),title:g().optional(),description:g().optional(),minItems:D().optional(),maxItems:D().optional(),items:z({anyOf:T(z({const:g(),title:g()}))}),default:T(g()).optional()}),rb=M([eb,tb]),nb=M([Xy,Yy,rb]),ob=M([nb,By,Wy,Ky]),ib=dn.extend({mode:I("form").optional(),message:g(),requestedSchema:z({type:I("object"),properties:Z(g(),ob),required:T(g()).optional()})}),ab=dn.extend({mode:I("url"),message:g(),elicitationId:g(),url:g().url()}),sb=M([ib,ab]),cb=re.extend({method:I("elicitation/create"),params:sb}),ub=be.extend({elicitationId:g()}),lb=_e.extend({method:I("notifications/elicitation/complete"),params:ub}),db=ne.extend({action:ee(["accept","decline","cancel"]),content:Bt(t=>t===null?void 0:t,Z(g(),M([g(),D(),W(),T(g())])).optional())}),pb=z({type:I("ref/resource"),uri:g()});var mb=z({type:I("ref/prompt"),name:g()}),fb=he.extend({ref:M([mb,pb]),argument:z({name:g(),value:g()}),context:z({arguments:Z(g(),g()).optional()}).optional()}),gb=re.extend({method:I("completion/complete"),params:fb});var hb=ne.extend({completion:Y({values:T(g()).max(100),total:q(D().int()),hasMore:q(W())})}),vb=z({uri:g().startsWith("file://"),name:g().optional(),_meta:Z(g(),C()).optional()}),yb=re.extend({method:I("roots/list"),params:he.optional()}),bb=ne.extend({roots:T(vb)}),_b=_e.extend({method:I("notifications/roots/list_changed"),params:be.optional()}),mk=M([Gt,Xv,gb,Zy,Sy,xy,cy,uy,py,gy,vy,Sd,zd,Mi,qi,Fi,Vi]),fk=M([Ri,Ai,ty,_b,yn]),gk=M([Zi,wd,Id,db,bb,Li,Ji,Ci]),hk=M([Gt,Hy,cb,yb,Mi,qi,Fi,Vi]),vk=M([Ri,Ai,Ay,by,my,Ny,jy,yn,lb]),yk=M([Zi,ey,hb,Py,ky,hd,ly,yd,Yt,Dy,Li,Ji,Ci]),U=class t extends Error{constructor(r,n,i){super(`MCP error ${r}: ${n}`),this.code=r,this.data=i,this.name="McpError"}static fromError(r,n,i){if(r===R.UrlElicitationRequired&&i){let e=i;if(e.elicitations)return new ld(e.elicitations,n)}return new t(r,n,i)}},ld=class extends U{constructor(r,n=`URL elicitation${r.length>1?"s":""} required`){super(R.UrlElicitationRequired,n,{elicitations:r})}get elicitations(){return this.data?.elicitations??[]}};function We(t){return t==="completed"||t==="failed"||t==="cancelled"}var $b=Symbol("Let zodToJsonSchema decide on which parser to use");var Qk=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");function Pd(t){let n=zf(t)?.method;if(!n)throw new Error("Schema is missing a method literal");let i=Sf(n);if(typeof i!="string")throw new Error("Schema method literal must be a string");return i}function jd(t,r){let n=To(t,r);if(!n.success)throw n.error;return n.data}var Ib=6e4,Bi=class{constructor(r){this._options=r,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this._pendingDebouncedNotifications=new Set,this._taskProgressTokens=new Map,this._requestResolvers=new Map,this.setNotificationHandler(Ri,n=>{this._oncancel(n)}),this.setNotificationHandler(Ai,n=>{this._onprogress(n)}),this.setRequestHandler(Gt,n=>({})),this._taskStore=r?.taskStore,this._taskMessageQueue=r?.taskMessageQueue,this._taskStore&&(this.setRequestHandler(Mi,async(n,i)=>{let e=await this._taskStore.getTask(n.params.taskId,i.sessionId);if(!e)throw new U(R.InvalidParams,"Failed to retrieve task: Task not found");return{...e}}),this.setRequestHandler(qi,async(n,i)=>{let e=async()=>{let o=n.params.taskId;if(this._taskMessageQueue){let s;for(;s=await this._taskMessageQueue.dequeue(o,i.sessionId);){if(s.type==="response"||s.type==="error"){let c=s.message,u=c.id,d=this._requestResolvers.get(u);if(d)if(this._requestResolvers.delete(u),s.type==="response")d(c);else{let m=c,h=new U(m.error.code,m.error.message,m.error.data);d(h)}else{let m=s.type==="response"?"Response":"Error";this._onerror(new Error(`${m} handler missing for request ${u}`))}continue}await this._transport?.send(s.message,{relatedRequestId:i.requestId})}}let a=await this._taskStore.getTask(o,i.sessionId);if(!a)throw new U(R.InvalidParams,`Task not found: ${o}`);if(!We(a.status))return await this._waitForTaskUpdate(o,i.signal),await e();if(We(a.status)){let s=await this._taskStore.getTaskResult(o,i.sessionId);return this._clearTaskQueue(o),{...s,_meta:{...s._meta,[Be]:{taskId:o}}}}return await e()};return await e()}),this.setRequestHandler(Fi,async(n,i)=>{try{let{tasks:e,nextCursor:o}=await this._taskStore.listTasks(n.params?.cursor,i.sessionId);return{tasks:e,nextCursor:o,_meta:{}}}catch(e){throw new U(R.InvalidParams,`Failed to list tasks: ${e instanceof Error?e.message:String(e)}`)}}),this.setRequestHandler(Vi,async(n,i)=>{try{let e=await this._taskStore.getTask(n.params.taskId,i.sessionId);if(!e)throw new U(R.InvalidParams,`Task not found: ${n.params.taskId}`);if(We(e.status))throw new U(R.InvalidParams,`Cannot cancel task in terminal status: ${e.status}`);await this._taskStore.updateTaskStatus(n.params.taskId,"cancelled","Client cancelled task execution.",i.sessionId),this._clearTaskQueue(n.params.taskId);let o=await this._taskStore.getTask(n.params.taskId,i.sessionId);if(!o)throw new U(R.InvalidParams,`Task not found after cancellation: ${n.params.taskId}`);return{_meta:{},...o}}catch(e){throw e instanceof U?e:new U(R.InvalidRequest,`Failed to cancel task: ${e instanceof Error?e.message:String(e)}`)}}))}async _oncancel(r){if(!r.params.requestId)return;this._requestHandlerAbortControllers.get(r.params.requestId)?.abort(r.params.reason)}_setupTimeout(r,n,i,e,o=!1){this._timeoutInfo.set(r,{timeoutId:setTimeout(e,n),startTime:Date.now(),timeout:n,maxTotalTimeout:i,resetTimeoutOnProgress:o,onTimeout:e})}_resetTimeout(r){let n=this._timeoutInfo.get(r);if(!n)return!1;let i=Date.now()-n.startTime;if(n.maxTotalTimeout&&i>=n.maxTotalTimeout)throw this._timeoutInfo.delete(r),U.fromError(R.RequestTimeout,"Maximum total timeout exceeded",{maxTotalTimeout:n.maxTotalTimeout,totalElapsed:i});return clearTimeout(n.timeoutId),n.timeoutId=setTimeout(n.onTimeout,n.timeout),!0}_cleanupTimeout(r){let n=this._timeoutInfo.get(r);n&&(clearTimeout(n.timeoutId),this._timeoutInfo.delete(r))}async connect(r){if(this._transport)throw new Error("Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.");this._transport=r;let n=this.transport?.onclose;this._transport.onclose=()=>{n?.(),this._onclose()};let i=this.transport?.onerror;this._transport.onerror=o=>{i?.(o),this._onerror(o)};let e=this._transport?.onmessage;this._transport.onmessage=(o,a)=>{e?.(o,a),pn(o)||Ff(o)?this._onresponse(o):pd(o)?this._onrequest(o,a):qf(o)?this._onnotification(o):this._onerror(new Error(`Unknown message type: ${JSON.stringify(o)}`))},await this._transport.start()}_onclose(){let r=this._responseHandlers;this._responseHandlers=new Map,this._progressHandlers.clear(),this._taskProgressTokens.clear(),this._pendingDebouncedNotifications.clear();for(let i of this._timeoutInfo.values())clearTimeout(i.timeoutId);this._timeoutInfo.clear();for(let i of this._requestHandlerAbortControllers.values())i.abort();this._requestHandlerAbortControllers.clear();let n=U.fromError(R.ConnectionClosed,"Connection closed");this._transport=void 0,this.onclose?.();for(let i of r.values())i(n)}_onerror(r){this.onerror?.(r)}_onnotification(r){let n=this._notificationHandlers.get(r.method)??this.fallbackNotificationHandler;n!==void 0&&Promise.resolve().then(()=>n(r)).catch(i=>this._onerror(new Error(`Uncaught error in notification handler: ${i}`)))}_onrequest(r,n){let i=this._requestHandlers.get(r.method)??this.fallbackRequestHandler,e=this._transport,o=r.params?._meta?.[Be]?.taskId;if(i===void 0){let d={jsonrpc:"2.0",id:r.id,error:{code:R.MethodNotFound,message:"Method not found"}};o&&this._taskMessageQueue?this._enqueueTaskMessage(o,{type:"error",message:d,timestamp:Date.now()},e?.sessionId).catch(m=>this._onerror(new Error(`Failed to enqueue error response: ${m}`))):e?.send(d).catch(m=>this._onerror(new Error(`Failed to send an error response: ${m}`)));return}let a=new AbortController;this._requestHandlerAbortControllers.set(r.id,a);let s=Cf(r.params)?r.params.task:void 0,c=this._taskStore?this.requestTaskStore(r,e?.sessionId):void 0,u={signal:a.signal,sessionId:e?.sessionId,_meta:r.params?._meta,sendNotification:async d=>{if(a.signal.aborted)return;let m={relatedRequestId:r.id};o&&(m.relatedTask={taskId:o}),await this.notification(d,m)},sendRequest:async(d,m,h)=>{if(a.signal.aborted)throw new U(R.ConnectionClosed,"Request was cancelled");let v={...h,relatedRequestId:r.id};o&&!v.relatedTask&&(v.relatedTask={taskId:o});let S=v.relatedTask?.taskId??o;return S&&c&&await c.updateTaskStatus(S,"input_required"),await this.request(d,m,v)},authInfo:n?.authInfo,requestId:r.id,requestInfo:n?.requestInfo,taskId:o,taskStore:c,taskRequestedTtl:s?.ttl,closeSSEStream:n?.closeSSEStream,closeStandaloneSSEStream:n?.closeStandaloneSSEStream};Promise.resolve().then(()=>{s&&this.assertTaskHandlerCapability(r.method)}).then(()=>i(r,u)).then(async d=>{if(a.signal.aborted)return;let m={result:d,jsonrpc:"2.0",id:r.id};o&&this._taskMessageQueue?await this._enqueueTaskMessage(o,{type:"response",message:m,timestamp:Date.now()},e?.sessionId):await e?.send(m)},async d=>{if(a.signal.aborted)return;let m={jsonrpc:"2.0",id:r.id,error:{code:Number.isSafeInteger(d.code)?d.code:R.InternalError,message:d.message??"Internal error",...d.data!==void 0&&{data:d.data}}};o&&this._taskMessageQueue?await this._enqueueTaskMessage(o,{type:"error",message:m,timestamp:Date.now()},e?.sessionId):await e?.send(m)}).catch(d=>this._onerror(new Error(`Failed to send response: ${d}`))).finally(()=>{this._requestHandlerAbortControllers.get(r.id)===a&&this._requestHandlerAbortControllers.delete(r.id)})}_onprogress(r){let{progressToken:n,...i}=r.params,e=Number(n),o=this._progressHandlers.get(e);if(!o){this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(r)}`));return}let a=this._responseHandlers.get(e),s=this._timeoutInfo.get(e);if(s&&a&&s.resetTimeoutOnProgress)try{this._resetTimeout(e)}catch(c){this._responseHandlers.delete(e),this._progressHandlers.delete(e),this._cleanupTimeout(e),a(c);return}o(i)}_onresponse(r){let n=Number(r.id),i=this._requestResolvers.get(n);if(i){if(this._requestResolvers.delete(n),pn(r))i(r);else{let a=new U(r.error.code,r.error.message,r.error.data);i(a)}return}let e=this._responseHandlers.get(n);if(e===void 0){this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(r)}`));return}this._responseHandlers.delete(n),this._cleanupTimeout(n);let o=!1;if(pn(r)&&r.result&&typeof r.result=="object"){let a=r.result;if(a.task&&typeof a.task=="object"){let s=a.task;typeof s.taskId=="string"&&(o=!0,this._taskProgressTokens.set(s.taskId,n))}}if(o||this._progressHandlers.delete(n),pn(r))e(r);else{let a=U.fromError(r.error.code,r.error.message,r.error.data);e(a)}}get transport(){return this._transport}async close(){await this._transport?.close()}async*requestStream(r,n,i){let{task:e}=i??{};if(!e){try{yield{type:"result",result:await this.request(r,n,i)}}catch(a){yield{type:"error",error:a instanceof U?a:new U(R.InternalError,String(a))}}return}let o;try{let a=await this.request(r,Ci,i);if(a.task)o=a.task.taskId,yield{type:"taskCreated",task:a.task};else throw new U(R.InternalError,"Task creation did not return a task");for(;;){let s=await this.getTask({taskId:o},i);if(yield{type:"taskStatus",task:s},We(s.status)){s.status==="completed"?yield{type:"result",result:await this.getTaskResult({taskId:o},n,i)}:s.status==="failed"?yield{type:"error",error:new U(R.InternalError,`Task ${o} failed`)}:s.status==="cancelled"&&(yield{type:"error",error:new U(R.InternalError,`Task ${o} was cancelled`)});return}if(s.status==="input_required"){yield{type:"result",result:await this.getTaskResult({taskId:o},n,i)};return}let c=s.pollInterval??this._options?.defaultTaskPollInterval??1e3;await new Promise(u=>setTimeout(u,c)),i?.signal?.throwIfAborted()}}catch(a){yield{type:"error",error:a instanceof U?a:new U(R.InternalError,String(a))}}}request(r,n,i){let{relatedRequestId:e,resumptionToken:o,onresumptiontoken:a,task:s,relatedTask:c}=i??{};return new Promise((u,d)=>{let m=Q=>{d(Q)};if(!this._transport){m(new Error("Not connected"));return}if(this._options?.enforceStrictCapabilities===!0)try{this.assertCapabilityForMethod(r.method),s&&this.assertTaskCapability(r.method)}catch(Q){m(Q);return}i?.signal?.throwIfAborted();let h=this._requestMessageId++,v={...r,jsonrpc:"2.0",id:h};i?.onprogress&&(this._progressHandlers.set(h,i.onprogress),v.params={...r.params,_meta:{...r.params?._meta||{},progressToken:h}}),s&&(v.params={...v.params,task:s}),c&&(v.params={...v.params,_meta:{...v.params?._meta||{},[Be]:c}});let S=Q=>{this._responseHandlers.delete(h),this._progressHandlers.delete(h),this._cleanupTimeout(h),this._transport?.send({jsonrpc:"2.0",method:"notifications/cancelled",params:{requestId:h,reason:String(Q)}},{relatedRequestId:e,resumptionToken:o,onresumptiontoken:a}).catch(F=>this._onerror(new Error(`Failed to send cancellation: ${F}`)));let B=Q instanceof U?Q:new U(R.RequestTimeout,String(Q));d(B)};this._responseHandlers.set(h,Q=>{if(!i?.signal?.aborted){if(Q instanceof Error)return d(Q);try{let B=To(n,Q.result);B.success?u(B.data):d(B.error)}catch(B){d(B)}}}),i?.signal?.addEventListener("abort",()=>{S(i?.signal?.reason)});let G=i?.timeout??Ib,V=()=>S(U.fromError(R.RequestTimeout,"Request timed out",{timeout:G}));this._setupTimeout(h,G,i?.maxTotalTimeout,V,i?.resetTimeoutOnProgress??!1);let Ne=c?.taskId;if(Ne){let Q=B=>{let F=this._responseHandlers.get(h);F?F(B):this._onerror(new Error(`Response handler missing for side-channeled request ${h}`))};this._requestResolvers.set(h,Q),this._enqueueTaskMessage(Ne,{type:"request",message:v,timestamp:Date.now()}).catch(B=>{this._cleanupTimeout(h),d(B)})}else this._transport.send(v,{relatedRequestId:e,resumptionToken:o,onresumptiontoken:a}).catch(Q=>{this._cleanupTimeout(h),d(Q)})})}async getTask(r,n){return this.request({method:"tasks/get",params:r},Li,n)}async getTaskResult(r,n,i){return this.request({method:"tasks/result",params:r},n,i)}async listTasks(r,n){return this.request({method:"tasks/list",params:r},Ji,n)}async cancelTask(r,n){return this.request({method:"tasks/cancel",params:r},Vf,n)}async notification(r,n){if(!this._transport)throw new Error("Not connected");this.assertNotificationCapability(r.method);let i=n?.relatedTask?.taskId;if(i){let s={...r,jsonrpc:"2.0",params:{...r.params,_meta:{...r.params?._meta||{},[Be]:n.relatedTask}}};await this._enqueueTaskMessage(i,{type:"notification",message:s,timestamp:Date.now()});return}if((this._options?.debouncedNotificationMethods??[]).includes(r.method)&&!r.params&&!n?.relatedRequestId&&!n?.relatedTask){if(this._pendingDebouncedNotifications.has(r.method))return;this._pendingDebouncedNotifications.add(r.method),Promise.resolve().then(()=>{if(this._pendingDebouncedNotifications.delete(r.method),!this._transport)return;let s={...r,jsonrpc:"2.0"};n?.relatedTask&&(s={...s,params:{...s.params,_meta:{...s.params?._meta||{},[Be]:n.relatedTask}}}),this._transport?.send(s,n).catch(c=>this._onerror(c))});return}let a={...r,jsonrpc:"2.0"};n?.relatedTask&&(a={...a,params:{...a.params,_meta:{...a.params?._meta||{},[Be]:n.relatedTask}}}),await this._transport.send(a,n)}setRequestHandler(r,n){let i=Pd(r);this.assertRequestHandlerCapability(i),this._requestHandlers.set(i,(e,o)=>{let a=jd(r,e);return Promise.resolve(n(a,o))})}removeRequestHandler(r){this._requestHandlers.delete(r)}assertCanSetRequestHandler(r){if(this._requestHandlers.has(r))throw new Error(`A request handler for ${r} already exists, which would be overridden`)}setNotificationHandler(r,n){let i=Pd(r);this._notificationHandlers.set(i,e=>{let o=jd(r,e);return Promise.resolve(n(o))})}removeNotificationHandler(r){this._notificationHandlers.delete(r)}_cleanupTaskProgressHandler(r){let n=this._taskProgressTokens.get(r);n!==void 0&&(this._progressHandlers.delete(n),this._taskProgressTokens.delete(r))}async _enqueueTaskMessage(r,n,i){if(!this._taskStore||!this._taskMessageQueue)throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");let e=this._options?.maxTaskQueueSize;await this._taskMessageQueue.enqueue(r,n,i,e)}async _clearTaskQueue(r,n){if(this._taskMessageQueue){let i=await this._taskMessageQueue.dequeueAll(r,n);for(let e of i)if(e.type==="request"&&pd(e.message)){let o=e.message.id,a=this._requestResolvers.get(o);a?(a(new U(R.InternalError,"Task cancelled or completed")),this._requestResolvers.delete(o)):this._onerror(new Error(`Resolver missing for request ${o} during task ${r} cleanup`))}}}async _waitForTaskUpdate(r,n){let i=this._options?.defaultTaskPollInterval??1e3;try{let e=await this._taskStore?.getTask(r);e?.pollInterval&&(i=e.pollInterval)}catch{}return new Promise((e,o)=>{if(n.aborted){o(new U(R.InvalidRequest,"Request cancelled"));return}let a=setTimeout(e,i);n.addEventListener("abort",()=>{clearTimeout(a),o(new U(R.InvalidRequest,"Request cancelled"))},{once:!0})})}requestTaskStore(r,n){let i=this._taskStore;if(!i)throw new Error("No task store configured");return{createTask:async e=>{if(!r)throw new Error("No request provided");return await i.createTask(e,r.id,{method:r.method,params:r.params},n)},getTask:async e=>{let o=await i.getTask(e,n);if(!o)throw new U(R.InvalidParams,"Failed to retrieve task: Task not found");return o},storeTaskResult:async(e,o,a)=>{await i.storeTaskResult(e,o,a,n);let s=await i.getTask(e,n);if(s){let c=yn.parse({method:"notifications/tasks/status",params:s});await this.notification(c),We(s.status)&&this._cleanupTaskProgressHandler(e)}},getTaskResult:e=>i.getTaskResult(e,n),updateTaskStatus:async(e,o,a)=>{let s=await i.getTask(e,n);if(!s)throw new U(R.InvalidParams,`Task "${e}" not found - it may have been cleaned up`);if(We(s.status))throw new U(R.InvalidParams,`Cannot update task "${e}" from terminal status "${s.status}" to "${o}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);await i.updateTaskStatus(e,o,a,n);let c=await i.getTask(e,n);if(c){let u=yn.parse({method:"notifications/tasks/status",params:c});await this.notification(u),We(c.status)&&this._cleanupTaskProgressHandler(e)}},listTasks:e=>i.listTasks(e,n)}}};function Qf(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function Xf(t,r){let n={...t};for(let i in r){let e=i,o=r[e];if(o===void 0)continue;let a=n[e];Qf(a)&&Qf(o)?n[e]={...a,...o}:n[e]=o}return n}ln();ln();var Kw=(t=>typeof Ke<"u"?Ke:typeof Proxy<"u"?new Proxy(t,{get:(r,n)=>(typeof Ke<"u"?Ke:r)[n]}):t)(function(t){if(typeof Ke<"u")return Ke.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')}),Td=class extends Bi{constructor(){super(...arguments);N(this,"_registeredMethods",new Set);N(this,"_eventSlots",new Map);N(this,"setRequestHandler",(n,i)=>{this._assertMethodNotRegistered(n,"setRequestHandler"),super.setRequestHandler(n,i)});N(this,"setNotificationHandler",(n,i)=>{this._assertMethodNotRegistered(n,"setNotificationHandler"),super.setNotificationHandler(n,i)});N(this,"replaceRequestHandler",(n,i)=>{let e=n.shape.method.value;this._registeredMethods.add(e),super.setRequestHandler(n,i)})}onEventDispatch(n,i){}_ensureEventSlot(n){let i=this._eventSlots.get(n);if(!i){let e=this.eventSchemas[n];if(!e)throw Error(`Unknown event: ${String(n)}`);i={listeners:[]},this._eventSlots.set(n,i);let o=e.shape.method.value;this._registeredMethods.add(o);let a=i;super.setNotificationHandler(e,s=>{let c=s.params;this.onEventDispatch(n,c),a.onHandler?.(c);for(let u of[...a.listeners])u(c)})}return i}setEventHandler(n,i){let e=this._ensureEventSlot(n);e.onHandler&&i&&console.warn(`[MCP Apps] on${String(n)} handler replaced. Use addEventListener("${String(n)}", \u2026) to add multiple listeners without replacing.`),e.onHandler=i}getEventHandler(n){return this._eventSlots.get(n)?.onHandler}addEventListener(n,i){this._ensureEventSlot(n).listeners.push(i)}removeEventListener(n,i){let e=this._eventSlots.get(n);if(!e)return;let o=e.listeners.indexOf(i);o!==-1&&e.listeners.splice(o,1)}warnIfRequestHandlerReplaced(n,i,e){i&&e&&console.warn(`[MCP Apps] ${n} handler replaced. Previous handler will no longer be called.`)}_assertMethodNotRegistered(n,i){let e=n.shape.method.value;if(this._registeredMethods.has(e))throw Error(`Handler for "${e}" already registered (via ${i}). Use addEventListener() to attach multiple listeners, or the on* setter for replace semantics.`);this._registeredMethods.add(e)}},Pb="2026-01-26";var jb="ui/notifications/tool-input-partial";var Od=class{constructor(r=window.parent,n){N(this,"eventTarget");N(this,"eventSource");N(this,"messageListener");N(this,"onclose");N(this,"onerror");N(this,"onmessage");N(this,"sessionId");N(this,"setProtocolVersion");this.eventTarget=r,this.eventSource=n,this.messageListener=i=>{if(n&&i.source!==this.eventSource){console.debug("Ignoring message from unknown source",i);return}let e=Jf.safeParse(i.data);e.success?(console.debug("Parsed message",e.data),this.onmessage?.(e.data)):i.data?.jsonrpc!=="2.0"?console.debug("Ignoring non-JSON-RPC message",e.error.message,i):(console.error("Failed to parse message",e.error.message,i),this.onerror?.(Error("Invalid JSON-RPC message received: "+e.error.message)))}}async start(){window.addEventListener("message",this.messageListener)}async send(r,n){r.method!==jb&&console.debug("Sending message",r),this.eventTarget.postMessage(r,"*")}async close(){window.removeEventListener("message",this.messageListener),this.onclose?.()}},Tb=l.union([l.literal("light"),l.literal("dark")]).describe("Color theme preference for the host environment."),$n=l.union([l.literal("inline"),l.literal("fullscreen"),l.literal("pip")]).describe("Display mode for UI presentation."),Ob=l.union([l.literal("--color-background-primary"),l.literal("--color-background-secondary"),l.literal("--color-background-tertiary"),l.literal("--color-background-inverse"),l.literal("--color-background-ghost"),l.literal("--color-background-info"),l.literal("--color-background-danger"),l.literal("--color-background-success"),l.literal("--color-background-warning"),l.literal("--color-background-disabled"),l.literal("--color-text-primary"),l.literal("--color-text-secondary"),l.literal("--color-text-tertiary"),l.literal("--color-text-inverse"),l.literal("--color-text-ghost"),l.literal("--color-text-info"),l.literal("--color-text-danger"),l.literal("--color-text-success"),l.literal("--color-text-warning"),l.literal("--color-text-disabled"),l.literal("--color-border-primary"),l.literal("--color-border-secondary"),l.literal("--color-border-tertiary"),l.literal("--color-border-inverse"),l.literal("--color-border-ghost"),l.literal("--color-border-info"),l.literal("--color-border-danger"),l.literal("--color-border-success"),l.literal("--color-border-warning"),l.literal("--color-border-disabled"),l.literal("--color-ring-primary"),l.literal("--color-ring-secondary"),l.literal("--color-ring-inverse"),l.literal("--color-ring-info"),l.literal("--color-ring-danger"),l.literal("--color-ring-success"),l.literal("--color-ring-warning"),l.literal("--font-sans"),l.literal("--font-mono"),l.literal("--font-weight-normal"),l.literal("--font-weight-medium"),l.literal("--font-weight-semibold"),l.literal("--font-weight-bold"),l.literal("--font-text-xs-size"),l.literal("--font-text-sm-size"),l.literal("--font-text-md-size"),l.literal("--font-text-lg-size"),l.literal("--font-heading-xs-size"),l.literal("--font-heading-sm-size"),l.literal("--font-heading-md-size"),l.literal("--font-heading-lg-size"),l.literal("--font-heading-xl-size"),l.literal("--font-heading-2xl-size"),l.literal("--font-heading-3xl-size"),l.literal("--font-text-xs-line-height"),l.literal("--font-text-sm-line-height"),l.literal("--font-text-md-line-height"),l.literal("--font-text-lg-line-height"),l.literal("--font-heading-xs-line-height"),l.literal("--font-heading-sm-line-height"),l.literal("--font-heading-md-line-height"),l.literal("--font-heading-lg-line-height"),l.literal("--font-heading-xl-line-height"),l.literal("--font-heading-2xl-line-height"),l.literal("--font-heading-3xl-line-height"),l.literal("--border-radius-xs"),l.literal("--border-radius-sm"),l.literal("--border-radius-md"),l.literal("--border-radius-lg"),l.literal("--border-radius-xl"),l.literal("--border-radius-full"),l.literal("--border-width-regular"),l.literal("--shadow-hairline"),l.literal("--shadow-sm"),l.literal("--shadow-md"),l.literal("--shadow-lg")]).describe("CSS variable keys available to MCP apps for theming."),Db=l.record(Ob.describe(`Style variables for theming MCP apps. + +Individual style keys are optional - hosts may provide any subset of these values. +Values are strings containing CSS values (colors, sizes, font stacks, etc.). + +Note: This type uses \`Record\` rather than \`Partial>\` +for compatibility with Zod schema generation. Both are functionally equivalent for validation.`),l.union([l.string(),l.undefined()]).describe(`Style variables for theming MCP apps. + +Individual style keys are optional - hosts may provide any subset of these values. +Values are strings containing CSS values (colors, sizes, font stacks, etc.). + +Note: This type uses \`Record\` rather than \`Partial>\` +for compatibility with Zod schema generation. Both are functionally equivalent for validation.`)).describe(`Style variables for theming MCP apps. + +Individual style keys are optional - hosts may provide any subset of these values. +Values are strings containing CSS values (colors, sizes, font stacks, etc.). + +Note: This type uses \`Record\` rather than \`Partial>\` +for compatibility with Zod schema generation. Both are functionally equivalent for validation.`),rI=l.object({method:l.literal("ui/open-link"),params:l.object({url:l.string().describe("URL to open in the host's browser")})}),Ub=l.object({isError:l.boolean().optional().describe("True if the host failed to open the URL (e.g., due to security policy).")}).passthrough(),Nb=l.object({isError:l.boolean().optional().describe("True if the download failed (e.g., user cancelled or host denied).")}).passthrough(),Eb=l.object({isError:l.boolean().optional().describe("True if the host rejected or failed to deliver the message.")}).passthrough(),nI=l.object({method:l.literal("ui/notifications/sandbox-proxy-ready"),params:l.object({})}),Dd=l.object({connectDomains:l.array(l.string()).optional().describe(`Origins for network requests (fetch/XHR/WebSocket). + +- Maps to CSP \`connect-src\` directive +- Empty or omitted \u2192 no network connections (secure default)`),resourceDomains:l.array(l.string()).optional().describe("Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted \u2192 no network resources (secure default)"),frameDomains:l.array(l.string()).optional().describe("Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted \u2192 no nested iframes allowed (`frame-src 'none'`)"),baseUriDomains:l.array(l.string()).optional().describe("Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted \u2192 only same origin allowed (`base-uri 'self'`)")}),Ud=l.object({camera:l.object({}).optional().describe("Request camera access.\n\nMaps to Permission Policy `camera` feature."),microphone:l.object({}).optional().describe("Request microphone access.\n\nMaps to Permission Policy `microphone` feature."),geolocation:l.object({}).optional().describe("Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature."),clipboardWrite:l.object({}).optional().describe("Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.")}),oI=l.object({method:l.literal("ui/notifications/size-changed"),params:l.object({width:l.number().optional().describe("New width in pixels."),height:l.number().optional().describe("New height in pixels.")})}),Zb=l.object({method:l.literal("ui/notifications/tool-input"),params:l.object({arguments:l.record(l.string(),l.unknown().describe("Complete tool call arguments as key-value pairs.")).optional().describe("Complete tool call arguments as key-value pairs.")})}),Rb=l.object({method:l.literal("ui/notifications/tool-input-partial"),params:l.object({arguments:l.record(l.string(),l.unknown().describe("Partial tool call arguments (incomplete, may change).")).optional().describe("Partial tool call arguments (incomplete, may change).")})}),Ab=l.object({method:l.literal("ui/notifications/tool-cancelled"),params:l.object({reason:l.string().optional().describe('Optional reason for the cancellation (e.g., "user action", "timeout").')})}),Cb=l.object({fonts:l.string().optional()}),Mb=l.object({variables:Db.optional().describe("CSS variables for theming the app."),css:Cb.optional().describe("CSS blocks that apps can inject.")}),Lb=l.object({method:l.literal("ui/resource-teardown"),params:l.object({})}),iI=l.record(l.string(),l.unknown()),Yf=l.object({text:l.object({}).optional().describe("Host supports text content blocks."),image:l.object({}).optional().describe("Host supports image content blocks."),audio:l.object({}).optional().describe("Host supports audio content blocks."),resource:l.object({}).optional().describe("Host supports resource content blocks."),resourceLink:l.object({}).optional().describe("Host supports resource link content blocks."),structuredContent:l.object({}).optional().describe("Host supports structured content.")}),aI=l.object({method:l.literal("ui/notifications/request-teardown"),params:l.object({}).optional()}),qb=l.object({experimental:l.object({}).optional().describe("Experimental features (structure TBD)."),openLinks:l.object({}).optional().describe("Host supports opening external URLs."),downloadFile:l.object({}).optional().describe("Host supports file downloads via ui/download-file."),serverTools:l.object({listChanged:l.boolean().optional().describe("Host supports tools/list_changed notifications.")}).optional().describe("Host can proxy tool calls to the MCP server."),serverResources:l.object({listChanged:l.boolean().optional().describe("Host supports resources/list_changed notifications.")}).optional().describe("Host can proxy resource reads to the MCP server."),logging:l.object({}).optional().describe("Host accepts log messages."),sandbox:l.object({permissions:Ud.optional().describe("Permissions granted by the host (camera, microphone, geolocation)."),csp:Dd.optional().describe("CSP domains approved by the host.")}).optional().describe("Sandbox configuration applied by the host."),updateModelContext:Yf.optional().describe("Host accepts context updates (ui/update-model-context) to be included in the model's context for future turns."),message:Yf.optional().describe("Host supports receiving content messages (ui/message) from the view."),sampling:l.object({tools:l.object({}).optional().describe("Host supports tool use via `tools` and `toolChoice` parameters.")}).optional().describe("Host supports LLM sampling (sampling/createMessage) from the view.\nMirrors the MCP `ClientCapabilities.sampling` shape so hosts can pass it through.")}),Fb=l.object({experimental:l.object({}).optional().describe("Experimental features (structure TBD)."),tools:l.object({listChanged:l.boolean().optional().describe("App supports tools/list_changed notifications.")}).optional().describe("App exposes MCP-style tools that the host can call."),availableDisplayModes:l.array($n).optional().describe("Display modes the app supports.")}),sI=l.object({method:l.literal("ui/notifications/initialized"),params:l.object({}).optional()}),cI=l.object({csp:Dd.optional().describe("Content Security Policy configuration for UI resources."),permissions:Ud.optional().describe("Sandbox permissions requested by the UI resource."),domain:l.string().optional().describe(`Dedicated origin for view sandbox. + +Useful when views need stable, dedicated origins for OAuth callbacks, CORS policies, or API key allowlists. + +**Host-dependent:** The format and validation rules for this field are determined by each host. Servers MUST consult host-specific documentation for the expected domain format. Common patterns include: +- Hash-based subdomains (e.g., \`{hash}.claudemcpcontent.com\`) +- URL-derived subdomains (e.g., \`www-example-com.oaiusercontent.com\`) + +If omitted, host uses default sandbox origin (typically per-conversation).`),prefersBorder:l.boolean().optional().describe(`Visual boundary preference - true if view prefers a visible border. + +Boolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary. + +- \`true\`: request visible border + background +- \`false\`: request no visible border + background +- omitted: host decides border`)}),uI=l.object({method:l.literal("ui/request-display-mode"),params:l.object({mode:$n.describe("The display mode being requested.")})}),Jb=l.object({mode:$n.describe("The display mode that was actually set. May differ from requested if not supported.")}).passthrough(),Vb=l.union([l.literal("model"),l.literal("app")]).describe("Tool visibility scope - who can access the tool."),lI=l.object({resourceUri:l.string().optional(),visibility:l.array(Vb).optional().describe(`Who can access this tool. Default: ["model", "app"] +- "model": Tool visible to and callable by the agent +- "app": Tool callable by the app from this server only`),csp:l.never().optional(),permissions:l.never().optional()}),dI=l.object({mimeTypes:l.array(l.string()).optional().describe('Array of supported MIME types for UI resources.\nMust include `"text/html;profile=mcp-app"` for MCP Apps support.')}),pI=l.object({method:l.literal("ui/download-file"),params:l.object({contents:l.array(l.union([xd,kd])).describe("Resource contents to download \u2014 embedded (inline data) or linked (host fetches). Uses standard MCP resource types.")})}),mI=l.object({method:l.literal("ui/message"),params:l.object({role:l.literal("user").describe('Message role, currently only "user" is supported.'),content:l.array(Xt).describe("Message content blocks (text, image, etc.).")})}),fI=l.object({method:l.literal("ui/notifications/sandbox-resource-ready"),params:l.object({html:l.string().describe("HTML content to load into the inner iframe."),sandbox:l.string().optional().describe("Optional override for the inner iframe's sandbox attribute."),csp:Dd.optional().describe("CSP configuration from resource metadata."),permissions:Ud.optional().describe("Sandbox permissions from resource metadata.")})}),Hb=l.object({method:l.literal("ui/notifications/tool-result"),params:Yt.describe("Standard MCP tool execution result.")}),rg=l.object({toolInfo:l.object({id:Kt.optional().describe("JSON-RPC id of the tools/call request."),tool:Hi.describe("Tool definition including name, inputSchema, etc.")}).optional().describe("Metadata of the tool call that instantiated this App."),theme:Tb.optional().describe("Current color theme preference."),styles:Mb.optional().describe("Style configuration for theming the app."),displayMode:$n.optional().describe("How the UI is currently displayed."),availableDisplayModes:l.array($n).optional().describe("Display modes the host supports."),containerDimensions:l.union([l.object({height:l.number().describe("Fixed container height in pixels.")}),l.object({maxHeight:l.union([l.number(),l.undefined()]).optional().describe("Maximum container height in pixels.")})]).and(l.union([l.object({width:l.number().describe("Fixed container width in pixels.")}),l.object({maxWidth:l.union([l.number(),l.undefined()]).optional().describe("Maximum container width in pixels.")})])).optional().describe(`Container dimensions. Represents the dimensions of the iframe or other +container holding the app. Specify either width or maxWidth, and either height or maxHeight.`),locale:l.string().optional().describe("User's language and region preference in BCP 47 format."),timeZone:l.string().optional().describe("User's timezone in IANA format."),userAgent:l.string().optional().describe("Host application identifier."),platform:l.union([l.literal("web"),l.literal("desktop"),l.literal("mobile")]).optional().describe("Platform type for responsive design decisions."),deviceCapabilities:l.object({touch:l.boolean().optional().describe("Whether the device supports touch input."),hover:l.boolean().optional().describe("Whether the device supports hover interactions.")}).optional().describe("Device input capabilities."),safeAreaInsets:l.object({top:l.number().describe("Top safe area inset in pixels."),right:l.number().describe("Right safe area inset in pixels."),bottom:l.number().describe("Bottom safe area inset in pixels."),left:l.number().describe("Left safe area inset in pixels.")}).optional().describe("Mobile safe area boundaries in pixels.")}).passthrough(),Bb=l.object({method:l.literal("ui/notifications/host-context-changed"),params:rg.describe("Partial context update containing only changed fields.")}),gI=l.object({method:l.literal("ui/update-model-context"),params:l.object({content:l.array(Xt).optional().describe("Context content blocks (text, image, etc.)."),structuredContent:l.record(l.string(),l.unknown().describe("Structured content for machine-readable context data.")).optional().describe("Structured content for machine-readable context data.")})}),hI=l.object({method:l.literal("ui/initialize"),params:l.object({appInfo:fn.describe("App identification (name and version)."),appCapabilities:Fb.describe("Features and capabilities this app provides."),protocolVersion:l.string().describe("Protocol version this app supports.")})}),Wb=l.object({protocolVersion:l.string().describe('Negotiated protocol version string (e.g., "2025-11-21").'),hostInfo:fn.describe("Host application identification and version."),hostCapabilities:qb.describe("Features and capabilities provided by the host."),hostContext:rg.describe("Rich context about the host environment.")}).passthrough(),Kb={target:"draft-2020-12"};async function eg(t,r){let n=t["~standard"];if(n.jsonSchema)return n.jsonSchema[r](Kb);if(n.vendor==="zod"){let{z:i}=await Promise.resolve().then(()=>(ln(),ud));return i.toJSONSchema(t,{io:r})}throw Error(`Schema (vendor: ${n.vendor}) does not implement Standard JSON Schema (~standard.jsonSchema). Use a library that does (zod v4, ArkType, Valibot) or wrap your schema accordingly.`)}async function tg(t,r,n=""){let i=await t["~standard"].validate(r);if(i.issues){let e=i.issues.map(o=>{let a=o.path?.map(s=>typeof s=="object"?s.key:s).join(".");return a?`${a}: ${o.message}`:o.message}).join("; ");throw Error(n+e)}return i.value}function ng(t){let r=document.documentElement;r.setAttribute("data-theme",t),r.style.colorScheme=t}function og(t,r=document.documentElement){for(let[n,i]of Object.entries(t))i!==void 0&&r.style.setProperty(n,i)}function ig(t){if(document.getElementById("__mcp-host-fonts"))return;let r=document.createElement("style");r.id="__mcp-host-fonts",r.textContent=t,document.head.appendChild(r)}var Ki=class Ki extends Td{constructor(n,i={},e={autoResize:!0}){super(e);N(this,"_appInfo");N(this,"_capabilities");N(this,"options");N(this,"_hostCapabilities");N(this,"_hostInfo");N(this,"_hostContext");N(this,"_registeredTools",{});N(this,"_initializedSent",!1);N(this,"eventSchemas",{toolinput:Zb,toolinputpartial:Rb,toolresult:Hb,toolcancelled:Ab,hostcontextchanged:Bb});N(this,"_everHadListener",new Set);N(this,"_toolHandlersInitialized",!1);N(this,"_onteardown");N(this,"_oncalltool");N(this,"_onlisttools");N(this,"sendOpenLink",this.openLink);this._appInfo=n,this._capabilities=i,this.options=e,e.allowUnsafeEval||l.config({jitless:!0}),this.setRequestHandler(Gt,o=>(console.log("Received ping:",o.params),{})),this.setEventHandler("hostcontextchanged",void 0)}_assertInitialized(n){if(this._initializedSent)return;let i=`[ext-apps] App.${n}() called before connect() completed the ui/initialize handshake. Await app.connect() before calling this method, or move data loading to an ontoolresult handler.`;if(this.options?.strict)throw Error(i);console.warn(`${i}. This will throw in a future release.`)}_assertHandlerTiming(n){if(!Ki.ONE_SHOT_EVENTS.has(n)||this._everHadListener.has(n)||(this._everHadListener.add(n),!this._initializedSent))return;let i=`[ext-apps] "${String(n)}" handler registered after connect() completed the ui/initialize handshake. The host may have already sent this notification. Register handlers before calling app.connect().`;if(this.options?.strict)throw Error(i);console.warn(i)}setEventHandler(n,i){i&&this._assertHandlerTiming(n),super.setEventHandler(n,i)}addEventListener(n,i){this._assertHandlerTiming(n),super.addEventListener(n,i)}onEventDispatch(n,i){n==="hostcontextchanged"&&(this._hostContext={...this._hostContext,...i})}registerCapabilities(n){if(this.transport)throw Error("Cannot register capabilities after transport is established");this._capabilities=Xf(this._capabilities,n)}registerTool(n,i,e){if(this._registeredTools[n])throw Error(`Tool ${n} is already registered`);let o=this,a=()=>{o._initializedSent&&o._capabilities.tools?.listChanged&&o.sendToolListChanged()},s=i.inputSchema!==void 0,c={title:i.title,description:i.description,inputSchema:i.inputSchema,outputSchema:i.outputSchema,annotations:i.annotations,_meta:i._meta,enabled:!0,enable(){this.enabled=!0,a()},disable(){this.enabled=!1,a()},update(u){Object.assign(this,u),a()},remove(){o._registeredTools[n]===c&&(delete o._registeredTools[n],a())},handler:async(u,d)=>{if(!c.enabled)throw Error(`Tool ${n} is disabled`);let m;if(s){let h=c.inputSchema,v=h?await tg(h,u??{},`Invalid input for tool ${n}: `):u??{};m=await e(v,d)}else m=await e(d);return c.outputSchema&&!m.isError&&(m.structuredContent=await tg(c.outputSchema,m.structuredContent,`Invalid output for tool ${n}: `)),m}};return this._registeredTools[n]=c,!this._capabilities.tools&&!this.transport&&this.registerCapabilities({tools:{listChanged:!0}}),this.ensureToolHandlersInitialized(),a(),c}ensureToolHandlersInitialized(){this._toolHandlersInitialized||(this._toolHandlersInitialized=!0,this.oncalltool=async(n,i)=>{let e=this._registeredTools[n.name];if(!e)throw Error(`Tool ${n.name} not found`);return e.handler(n.arguments,i)},this.onlisttools=async(n,i)=>({tools:await Promise.all(Object.entries(this._registeredTools).filter(([e,o])=>o.enabled).map(async([e,o])=>{let a={name:e,title:o.title,description:o.description,inputSchema:o.inputSchema?await eg(o.inputSchema,"input"):{type:"object",properties:{}}};return o.outputSchema&&(a.outputSchema=await eg(o.outputSchema,"output")),o.annotations&&(a.annotations=o.annotations),o._meta&&(a._meta=o._meta),a}))}))}async sendToolListChanged(n={}){this._assertInitialized("sendToolListChanged"),await this.notification({method:"notifications/tools/list_changed",params:n})}getHostCapabilities(){return this._hostCapabilities}getHostVersion(){return this._hostInfo}getHostContext(){return this._hostContext}get ontoolinput(){return this.getEventHandler("toolinput")}set ontoolinput(n){this.setEventHandler("toolinput",n)}get ontoolinputpartial(){return this.getEventHandler("toolinputpartial")}set ontoolinputpartial(n){this.setEventHandler("toolinputpartial",n)}get ontoolresult(){return this.getEventHandler("toolresult")}set ontoolresult(n){this.setEventHandler("toolresult",n)}get ontoolcancelled(){return this.getEventHandler("toolcancelled")}set ontoolcancelled(n){this.setEventHandler("toolcancelled",n)}get onhostcontextchanged(){return this.getEventHandler("hostcontextchanged")}set onhostcontextchanged(n){this.setEventHandler("hostcontextchanged",n)}get onteardown(){return this._onteardown}set onteardown(n){this.warnIfRequestHandlerReplaced("onteardown",this._onteardown,n),this._onteardown=n,this.replaceRequestHandler(Lb,(i,e)=>{if(!this._onteardown)throw Error("No onteardown handler set");return this._onteardown(i.params,e)})}get oncalltool(){return this._oncalltool}set oncalltool(n){this.warnIfRequestHandlerReplaced("oncalltool",this._oncalltool,n),this._oncalltool=n,this.replaceRequestHandler(Sd,(i,e)=>{if(!this._oncalltool)throw Error("No oncalltool handler set");return this._oncalltool(i.params,e)})}get onlisttools(){return this._onlisttools}set onlisttools(n){this.warnIfRequestHandlerReplaced("onlisttools",this._onlisttools,n),this._onlisttools=n,this.replaceRequestHandler(zd,(i,e)=>{if(!this._onlisttools)throw Error("No onlisttools handler set");return this._onlisttools(i.params,e)})}assertCapabilityForMethod(n){switch(n){case"sampling/createMessage":if(!this._hostCapabilities?.sampling)throw Error(`Host does not support sampling (required for ${n})`);break}}assertRequestHandlerCapability(n){switch(n){case"tools/call":case"tools/list":if(!this._capabilities.tools)throw Error(`Client does not support tool capability (required for ${n})`);return;case"ping":case"ui/resource-teardown":return;default:throw Error(`No handler for method ${n} registered`)}}assertNotificationCapability(n){}assertTaskCapability(n){throw Error("Tasks are not supported in MCP Apps")}assertTaskHandlerCapability(n){throw Error("Task handlers are not supported in MCP Apps")}async callServerTool(n,i){if(this._assertInitialized("callServerTool"),typeof n=="string")throw Error(`callServerTool() expects an object as its first argument, but received a string ("${n}"). Did you mean: callServerTool({ name: "${n}", arguments: { ... } })?`);return await this.request({method:"tools/call",params:n},Yt,{onprogress:()=>{},resetTimeoutOnProgress:!0,...i})}async readServerResource(n,i){return this._assertInitialized("readServerResource"),await this.request({method:"resources/read",params:n},yd,i)}async listServerResources(n,i){return this._assertInitialized("listServerResources"),await this.request({method:"resources/list",params:n},hd,i)}async createSamplingMessage(n,i){this._assertInitialized("createSamplingMessage");let e=n.tools?Id:wd;return await this.request({method:"sampling/createMessage",params:n},e,i)}sendMessage(n,i){return this._assertInitialized("sendMessage"),this.request({method:"ui/message",params:n},Eb,i)}sendLog(n){return this.notification({method:"notifications/message",params:n})}updateModelContext(n,i){return this._assertInitialized("updateModelContext"),this.request({method:"ui/update-model-context",params:n},Zi,i)}openLink(n,i){return this._assertInitialized("openLink"),this.request({method:"ui/open-link",params:n},Ub,i)}downloadFile(n,i){return this._assertInitialized("downloadFile"),this.request({method:"ui/download-file",params:n},Nb,i)}requestTeardown(n={}){return this.notification({method:"ui/notifications/request-teardown",params:n})}requestDisplayMode(n,i){return this._assertInitialized("requestDisplayMode"),this.request({method:"ui/request-display-mode",params:n},Jb,i)}sendSizeChanged(n){return this.notification({method:"ui/notifications/size-changed",params:n})}setupSizeChangedNotifications(){let n=!1,i=0,e=0,o=()=>{n||(n=!0,requestAnimationFrame(()=>{n=!1;let s=document.documentElement,c=s.style.height;s.style.height="max-content";let u=Math.ceil(s.getBoundingClientRect().height);s.style.height=c;let d=Math.ceil(window.innerWidth);(d!==i||u!==e)&&(i=d,e=u,this.sendSizeChanged({width:d,height:u}))}))};o();let a=new ResizeObserver(o);return a.observe(document.documentElement),a.observe(document.body),()=>a.disconnect()}async connect(n=new Od(window.parent,window.parent),i){if(this.transport)throw Error("App is already connected. Call close() before connecting again.");this._initializedSent=!1,await super.connect(n);try{let e=await this.request({method:"ui/initialize",params:{appCapabilities:this._capabilities,appInfo:this._appInfo,protocolVersion:Pb}},Wb,i);if(e===void 0)throw Error(`Server sent invalid initialize result: ${e}`);this._hostCapabilities=e.hostCapabilities,this._hostInfo=e.hostInfo,this._hostContext=e.hostContext,await this.notification({method:"ui/notifications/initialized"}),this._initializedSent=!0,this.options?.autoResize&&this.setupSizeChangedNotifications()}catch(e){throw this.close(),e}}};N(Ki,"ONE_SHOT_EVENTS",new Set(["toolinput","toolinputpartial","toolresult","toolcancelled"]));var Wi=Ki;var Gi=class{constructor(r){this.opts=r;this.readyState=0;this.binaryType="arraybuffer";this.allowReconnect=!1;this.transportKind="pending";this.onopen=null;this.onmessage=null;this.onclose=null;this.onerror=null;this.transport=null;this.closedEarly=!1}async start(){let r=this.opts.directWsUrl?await this._tryDirect(this.opts.directWsUrl):null;if(this.closedEarly){r?.close();return}if(r)this._adopt(r,"direct"),this.readyState=1,this.onopen?.();else{let n=this.opts.makeTunnel();this._adopt(n,"tunnel"),n.onopen=()=>{this.readyState=1,this.onopen?.()},n.start()}}send(r){this.readyState!==1||!this.transport||this.transport.send(r)}close(r=1e3){if(!(this.readyState>=2)){if(!this.transport){this.closedEarly=!0,this.readyState=3,this.onclose?.({code:r});return}this.readyState=2,this.transport.close(r)}}_adopt(r,n){this.transport=r,this.transportKind=n,this.opts.onTransport?.(n),r.onmessage=i=>{this.onmessage?.({data:i.data})},r.onclose=i=>{this.readyState=3,this.onclose?.({code:i.code})},r.onerror=i=>{this.onerror?.(i)}}_tryDirect(r){let n=this.opts.wsConstructor??(typeof WebSocket<"u"?WebSocket:void 0);return n?new Promise(i=>{let e=!1,o=c=>{e||(e=!0,clearTimeout(s),i(c))},a;try{a=new n(r)}catch{i(null);return}a.binaryType="arraybuffer";let s=setTimeout(()=>{try{a.close()}catch{}o(null)},this.opts.timeoutMs??2500);a.onopen=()=>o(a),a.onerror=()=>o(null),a.onclose=()=>o(null)}):Promise.resolve(null)}};function Gb(t){let r=atob(t),n=new Uint8Array(r.length);for(let i=0;i{this.resolveConnected=r})}async start(){try{let r=await this.callTool("_shiny_connect",{});this.connectionId=String(r.connectionId),this.readyState=1,this.resolveConnected(this.connectionId),this.onopen?.(),this._pollLoop()}catch(r){this._fail(r)}}send(r){if(this.readyState!==1||this.connectionId===null)return;let n=typeof r=="string"?{data:r,binary:!1}:{data:Qb(r),binary:!0};this.callTool("_shiny_send",{connectionId:this.connectionId,frames:[n]}).catch(i=>this._fail(i))}close(r=1e3){if(this.readyState>=2)return;this.readyState=2;let n=this.connectionId;this.connectionId=null,n!==null&&this.callTool("_shiny_close",{connectionId:n}).catch(()=>{}),this._finishClose(r)}async _pollLoop(){for(;this.readyState===1&&this.connectionId!==null;){let r;try{r=await this.callTool("_shiny_receive",{connectionId:this.connectionId})}catch(n){this._fail(n);return}for(let n of r.frames??[]){if(this.readyState!==1)break;let i=n.binary?Gb(n.data):n.data;this.onmessage?.({data:i})}if(r.closed){this._finishClose(1e3);return}}}_fail(r){this.onerror?.(r),this._finishClose(1006)}_finishClose(r){this.readyState!==3&&(this.readyState=3,this.onclose?.({code:r}))}};function Xb(t){let r=atob(t),n=new Uint8Array(r.length);for(let i=0;i`${o}: ${a}\r +`).join("")}abort(){this.aborted=!0,this.nativeReq?.abort(),this.readyState!==4&&(this.readyState=4,this.onabort?.())}send(o){if(this.tunnelPath===null){this._delegateToNative(o);return}this._sendTunneled(o)}_classify(o){let a;try{a=new URL(o,"http://tunnel.invalid")}catch{return null}if(a.origin==="http://tunnel.invalid"){let s=a.pathname+a.search;return s.startsWith("/")?s:"/"+s}return a.origin===r?a.pathname+a.search:null}async _sendTunneled(o){try{let a=await Yb(o);if(a.error)throw new Error(a.error);let s=await t.getConnectionId(),c={method:this.reqMethod,path:this.tunnelPath,headers:this.reqHeaders};s&&(c.connectionId=s),a.b64!==null&&(c.body=a.b64);let u=await t.callTool("_shiny_http",c);if(this.aborted)return;this.status=u.status??0,this.statusText=e_(this.status),this.respHeaders={};for(let[m,h]of Object.entries(u.headers??{}))this.respHeaders[m.toLowerCase()]=String(h);let d=u.body?Xb(u.body):new Uint8Array(0);this._setResponse(d),this.readyState=4,this.onreadystatechange?.(),this.onload?.()}catch(a){if(this.aborted)return;this.status=0,this.readyState=4,this.onreadystatechange?.(),this.onerror?.(),console.warn("shiny-mcp-bridge: tunneled XHR failed:",a)}}_setResponse(o){let a=this.respHeaders["content-type"]??"";switch(this.responseType){case"arraybuffer":this.response=o.buffer.slice(o.byteOffset,o.byteOffset+o.byteLength);break;case"blob":this.response=new Blob([o],{type:a});break;case"json":{let s=new TextDecoder().decode(o);try{this.response=JSON.parse(s)}catch{this.response=null}break}default:{let s=new TextDecoder().decode(o);this.responseText=s,this.response=s}}}_delegateToNative(o){if(!n){this.status=0,this.readyState=4,this.onerror?.();return}let a=new n;this.nativeReq=a,a.open(this.reqMethod,this.reqUrl,!0);for(let[s,c]of Object.entries(this.reqHeaders))a.setRequestHeader(s,c);this.responseType&&(a.responseType=this.responseType),a.onreadystatechange=()=>{if(this.readyState=a.readyState,a.readyState===4){this.status=a.status,this.statusText=a.statusText,this.response=a.response,(!this.responseType||this.responseType==="text")&&(this.responseText=a.responseText),this.respHeaders={};for(let s of a.getAllResponseHeaders().split(`\r +`)){let c=s.indexOf(": ");c>0&&(this.respHeaders[s.slice(0,c).toLowerCase()]=s.slice(c+2))}}this.onreadystatechange?.()},a.onload=()=>this.onload?.(),a.onerror=()=>this.onerror?.(),a.onabort=()=>this.onabort?.(),a.ontimeout=()=>this.ontimeout?.(),a.send(o)}}return i}function Nd(){return window.Shiny}function er(t,r,n=100){let i=Nd();if(i?.setInputValue){i.setInputValue(t,r);return}n>0&&setTimeout(()=>er(t,r,n-1),100)}function sg(t){t&&(t.theme&&ng(t.theme),t.styles&&(t.styles.variables&&og(t.styles.variables),t.styles.css?.fonts&&ig(t.styles.css.fonts)))}function t_(t){if(!t)return"download";let r=/filename="?([^";]+)"?/.exec(t);return r?r[1]:"download"}function r_(t){document.addEventListener("click",r=>{let i=r.target?.closest?.("a.shiny-download-link");if(!i)return;let e=i.getAttribute("href");if(!e||i.classList.contains("disabled"))return;r.preventDefault(),r.stopPropagation();let o=new t;o.open("GET",e),o.responseType="blob",o.onload=()=>{if(o.status!==200){console.warn("shiny-mcp-bridge: download failed:",o.status);return}let a=t_(o.getResponseHeader("content-disposition")),s=URL.createObjectURL(o.response),c=document.createElement("a");c.href=s,c.download=a,document.body.appendChild(c),c.click(),c.remove(),setTimeout(()=>URL.revokeObjectURL(s),6e4)},o.send()},!0)}function n_(){return window.__shinyMcpConfig__??{}}function o_(){let t=Nd();if(!t){console.error("shiny-mcp-bridge: window.Shiny not found; load shiny.js first.");return}let r=n_(),n=new Wi({name:"shiny",version:"1.14.0.9000"},{availableDisplayModes:r.displayModes??["inline","fullscreen","pip"]}),i=n.connect().then(()=>{sg(n.getHostContext()),er(".clientdata_mcp_host_context",JSON.stringify(n.getHostContext()??{}))}).catch(m=>{throw console.error("shiny-mcp-bridge: failed to connect to MCP host:",m),m}),e=async(m,h)=>{await i;let v=r.appId&&m.startsWith("_shiny_")?r.appId+m:m,S=await n.callServerTool({name:v,arguments:h});if(S.isError){let V=S.content?.find(Ne=>Ne.type==="text")?.text;throw new Error(V??"MCP tool call failed: "+m)}return S.structuredContent??{}},o=r.directBase?r.directBase.replace(/^http/,"ws")+"/websocket/?mcp=1":null,a=null,s,c=new Promise(m=>{s=m});t.createSocket=()=>{let m=null;a=new Gi({directWsUrl:o,makeTunnel:()=>(m=new Qi(e),m),onTransport:v=>{window.__shinyMcpTransport__=v,console.log("shiny-mcp-bridge: connected via",v),v==="direct"?s(""):m?.whenConnected.then(s)}});let h=a;return setTimeout(()=>void h.start(),0),a};let u=ag({callTool:e,getConnectionId:()=>c,nativeXhr:window.XMLHttpRequest});window.XMLHttpRequest=u,r_(u),n.onhostcontextchanged=m=>{sg(m),er(".clientdata_mcp_host_context",JSON.stringify(n.getHostContext()??{}))},n.ontoolinput=m=>{er(".clientdata_mcp_tool_input",JSON.stringify(m.arguments??{}))},n.ontoolresult=m=>{er(".clientdata_mcp_tool_result",JSON.stringify(m))},n.onteardown=()=>(a?.close(),{});let d=(m=100)=>{let h=Nd();if(!h?.addCustomMessageHandler){m>0&&setTimeout(()=>d(m-1),100);return}h.addCustomMessageHandler("shiny.mcp.updateModelContext",v=>{i.then(()=>n.updateModelContext(v).catch(S=>console.warn("shiny-mcp-bridge: updateModelContext failed:",S)))}),h.addCustomMessageHandler("shiny.mcp.sendMessage",v=>{i.then(()=>n.sendMessage(v).catch(S=>console.warn("shiny-mcp-bridge: sendMessage failed:",S)))}),h.addCustomMessageHandler("shiny.mcp.requestDisplayMode",v=>{i.then(()=>n.requestDisplayMode(v).then(S=>{er(".clientdata_mcp_host_context",JSON.stringify({...n.getHostContext()??{},displayMode:S.mode}))}).catch(S=>console.warn("shiny-mcp-bridge: requestDisplayMode failed:",S)))})};d()}o_();})(); diff --git a/man/mcp-session.Rd b/man/mcp-session.Rd new file mode 100644 index 0000000000..0601ee306e --- /dev/null +++ b/man/mcp-session.Rd @@ -0,0 +1,173 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mcp-session.R +\name{mcp-session} +\alias{mcp-session} +\alias{isMcpSession} +\alias{mcpToolInput} +\alias{mcpHostContext} +\alias{mcpUpdateModelContext} +\alias{mcpSendMessage} +\alias{mcpRequestDisplayMode} +\title{Interact with the MCP host from a Shiny app} +\usage{ +isMcpSession(session = getDefaultReactiveDomain()) + +mcpToolInput(session = getDefaultReactiveDomain()) + +mcpHostContext(session = getDefaultReactiveDomain()) + +mcpUpdateModelContext( + text = NULL, + data = NULL, + session = getDefaultReactiveDomain() +) + +mcpSendMessage(text, session = getDefaultReactiveDomain()) + +mcpRequestDisplayMode( + mode = c("inline", "fullscreen", "pip"), + session = getDefaultReactiveDomain() +) +} +\arguments{ +\item{session}{The Shiny session object.} + +\item{text}{A character string. For \code{mcpUpdateModelContext()}, the +human/model-readable context text; for \code{mcpSendMessage()}, the message +to send to the chat.} + +\item{data}{An optional named list of structured, machine-readable +context data (serialized as JSON).} + +\item{mode}{The display mode to request: \code{"inline"}, \code{"fullscreen"}, or +\code{"pip"}. The host may decline; observe \code{mcpHostContext()$displayMode} +for the mode actually in effect. Declare the modes the app supports +with \code{options(shiny.mcp.displayModes = c("inline", "fullscreen"))} +(default: all three).} +} +\value{ +\code{isMcpSession()} returns \code{TRUE} or \code{FALSE}. \code{mcpToolInput()} and +\code{mcpHostContext()} return a named list, or \code{NULL} when nothing has been +received (they must be called within a reactive context). +\code{mcpUpdateModelContext()} and \code{mcpSendMessage()} invisibly return \code{TRUE} +if the message was sent to the host and \code{FALSE} otherwise. +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} + +When a Shiny app is served as an MCP App (by setting +\code{options(shiny.mcp = TRUE)} before the app starts), it renders inside an +MCP host's conversation (e.g. Claude, Claude Desktop, VS Code Copilot) +and can exchange information with the host: +\itemize{ +\item \code{isMcpSession()} reports whether the current session is connected +through an MCP host (as opposed to a regular browser). +\item \code{mcpToolInput()} returns the arguments the model supplied when it +called the app's tool, as a named list (reactive read). Declare the +expected arguments with +\code{options(shiny.mcp.tool = list(inputSchema = ...))}. +\item \code{mcpHostContext()} returns the host's context (theme, locale, display +mode, ...) as a named list (reactive read). +\item \code{mcpUpdateModelContext()} updates the model's context for future +conversation turns. Each call overwrites the previous update; the host +typically delivers it with the user's next message. +\item \code{mcpSendMessage()} sends a user-role message to the host's chat +interface, which may trigger a model response. +} + +Outside of an MCP session, \code{mcpUpdateModelContext()} and +\code{mcpSendMessage()} do nothing and return \code{FALSE}, so apps can call them +unconditionally. +} +\section{Deployment and the direct-connect fast path}{ + +On hosts that honor the declared content security policy, the app's +iframe connects over a real WebSocket for native-latency reactivity, +falling back to the tools/call tunnel automatically. The websocket URL +is derived, in order, from: \code{options(shiny.mcp.origin = )} (a full base +URL, which may include a path); Posit Connect's +\code{RStudio-Connect-App-Base-Url} (or \code{X-RSC-Request}) header; +shinyapps.io's \code{X-Redx-Frontend-Name} header; +a deployment record next to the app whose URL matches the serving host +(rsconnect's \verb{rsconnect/**/*.dcf} or Posit Publisher's +\verb{.posit/publish/deployments/*.toml}) — so apps deployed +under a sub-path such as \verb{/content/} work without configuration; +or the origin of the MCP request itself. Set +\code{options(shiny.mcp.direct = FALSE)} to always use the tunnel. +} + +\section{Multiple apps behind one server}{ + +A gateway can merge several Shiny MCP endpoints into a single MCP +server, so one connector exposes many apps. For that to work each app +must set a unique \code{options(shiny.mcp.appId = "")} (letters, digits, +\verb{_}, \code{-}): the app's internal tunnel tools are then prefixed with the +id and its UI resource is published as \verb{ui://shiny/}, so tools and +resources from different apps do not collide when merged. App-facing +tool names must also be unique across the merged apps. +} + +\section{Additional tools}{ + +Beyond the tool that opens the app, authors can expose plain R functions +as MCP tools the model may call directly, via +\code{options(shiny.mcp.tools = list(...))}. Each tool is a list with a +\code{name}, a \code{description}, an optional \code{inputSchema} (JSON Schema as a +nested list), and a \code{handler} function that receives the parsed +arguments as a named list. Handlers run in the server R process outside +of any Shiny session and may return a character vector (sent as text), a +list (sent as JSON \code{structuredContent}), or a promise. Errors are +reported to the model as tool errors. + +\if{html}{\out{
}}\preformatted{options(shiny.mcp.tools = list( + list( + name = "get_sample_stats", + description = "Summary statistics for a normal sample of size n.", + inputSchema = list( + type = "object", + properties = list(n = list(type = "integer")), + required = list("n") + ), + handler = function(args) \{ + x <- rnorm(args$n) + list(n = args$n, mean = mean(x), sd = stats::sd(x)) + \} + ) +)) +}\if{html}{\out{
}} +} + +\examples{ +\dontrun{ +options(shiny.mcp = TRUE) +options(shiny.mcp.tool = list( + name = "open_sales_dashboard", + description = "Show the interactive sales dashboard.", + inputSchema = list( + type = "object", + properties = list( + region = list(type = "string", description = "Region to focus on") + ) + ) +)) + +server <- function(input, output, session) { + # React to arguments the model passed to the tool + observe({ + region <- mcpToolInput()$region + if (!is.null(region)) { + updateSelectInput(session, "region", selected = region) + } + }) + + # Keep the model informed about what the user is looking at + observe({ + mcpUpdateModelContext( + text = paste("The user is viewing region", input$region), + data = list(region = input$region) + ) + }) +} +} + +} diff --git a/mcp/QUESTIONS.md b/mcp/QUESTIONS.md new file mode 100644 index 0000000000..851a529a14 --- /dev/null +++ b/mcp/QUESTIONS.md @@ -0,0 +1,93 @@ +# Open questions — answered 2026-07-13 + +Barret's decisions, with follow-up state. Original context preserved below +each item. + +## 1. Naming (`mcp*` functions, `shiny.mcp.*` options) — ✅ leave as is + +No renames. Surface: options `shiny.mcp`, `shiny.mcp.stdio`, +`shiny.mcp.direct`, `shiny.mcp.tool`, `shiny.mcp.tools`, +`shiny.mcp.displayModes`; exports `isMcpSession()`, `mcpToolInput()`, +`mcpHostContext()`, `mcpUpdateModelContext()`, `mcpSendMessage()`, +`mcpRequestDisplayMode()`. + +## 2. `shiny.mcp.direct = TRUE` default — ℹ️ explanation requested (below); default unchanged pending review + +**What it does.** When the host reads `ui://shiny/app`, shiny declares the +app's origin in the resource's `_meta.ui.csp.connectDomains` (both `http(s)` +and `ws(s)` forms). Spec-compliant hosts compile that into the sandbox +iframe's Content-Security-Policy, which permits the iframe to open network +connections to that one origin. The bridge then attempts a real WebSocket to +`/websocket/?mcp=1` (2.5 s cap) before falling back to the +postMessage tunnel. + +**Why it matters.** Transport latency differs by an order of magnitude. Over +the tunnel, every server→client reactive flush waits for the in-flight +`_shiny_receive` long-poll to resolve and re-arm, and each hop traverses +iframe → sandbox proxy → host page → HTTP POST → R. That's typically +50-300 ms per interaction (worse on remote connectors). The direct WebSocket +is ordinary Shiny: millisecond-scale, no host mediation, no tool-call +traffic. Side channels (uploads etc.) stay on the tunnel either way — going +direct for XHR would require CORS on the app (see Q3). + +**How the origin is derived.** From the HTTP request the host itself made to +`/mcp`: `Host` header + `X-Forwarded-Proto`. So it's automatically right for +localhost (`ws://127.0.0.1:7788`) and for https tunnels/proxies +(`wss://x.trycloudflare.com`). The stdio transport has no request, so it +falls back to the local httpuv origin — correct for desktop hosts, whose +iframe runs on the same machine. + +**Cost when it can't work (why default TRUE is safe).** +- Host ignores declared CSP (claude.ai today): the browser blocks the + attempt *immediately* (synchronous SecurityError or instant error event). + Fallback cost ≈ 0; one CSP-violation line in the console. +- Origin unreachable from the user's browser (e.g. app on a private network + the user isn't on): connection-refused fails fast; a silently-dropped + (filtered) route pays the full 2.5 s cap once, then the tunnel takes over. +- Reachability is user's-browser → app, not host-server → app. For + cloudflared/Connect-style https deployments users can reach, direct works. + +**Security delta of default-on: none.** The WebSocket endpoint accepts +browser connections regardless of this feature (that's just Shiny; browsers +don't apply CORS to WebSockets). Declaring the origin in CSP metadata only +tells the *sandbox* it may connect; it doesn't open anything new on the app. +The `?mcp=1` marker only switches session behavior (dependency inlining, +custom-message bridges). + +**The sub-path caveat — ✅ resolved 2026-07-13.** Implemented per Barret's +request: the direct-connect base is now path-aware, derived from (in order) +`options(shiny.mcp.origin=)`, Posit Connect's `RStudio-Connect-App-Base-Url` +header (verified 2026-07-13 on a real connect.posit.it deployment — Connect +does *not* send `X-RSC-Request` to Shiny content, though that header is +still honored), a +host-matched rsconnect deployment record (`rsconnect/**/*.dcf` `url` — the +deployment output files), then the request origin. CSP still declares +origins only (host sanitizers reject paths); the full base feeds the ws +URL. Records require a Host match so local runs of deployed app dirs can't +split-brain against production. + +**When to set FALSE:** deterministic tunnel-only transport for debugging, or +sub-path/unreachable deployments where the probe is known-futile. + +## 3. Direct-mode side channels stay tunneled (no CORS) — ⏸ deferred + +Revisit later. Current behavior stands: `_shiny_http` works without a +`connectionId`; no CORS headers are added to the app. + +## 4. mcptools upstreaming — ✅ filed 2026-07-13 + +Parent tracking issue posit-dev/mcptools#115 with one issue per part: +#116 (resources), #117 (tool `_meta`), #118 (async tool handlers), +#119 (embeddable dispatch), #120 (non-blocking stdio). Note: true GitHub +sub-issue linking was permission-blocked for `schloerke` via API, so the +parent uses a task-list; convert in the UI if desired. + +## 5. Draft PR — ✅ opened 2026-07-13 + +rstudio/shiny#4407 (draft). NEWS placeholder corrected to `(#4407)`. + +## 6. Smaller judgment calls — ✅ fine as-is + +Long-poll 15 s / GC 60 s; legacy font formats not inlined; tool result text; +Windows stdio unsupported; display modes declared all-three (basic-host +can't E2E them); `shiny.sharedSecret` unsupported over the tunnel. diff --git a/mcp/README-mcp-host.md b/mcp/README-mcp-host.md new file mode 100644 index 0000000000..8f66611f74 --- /dev/null +++ b/mcp/README-mcp-host.md @@ -0,0 +1,110 @@ +# MCP Apps test host for Shiny + +How to see a Shiny app render as an MCP App using the reference `basic-host` +from `modelcontextprotocol/ext-apps`. + +## One-time setup: prepare the ext-apps clone + +```sh +git clone https://github.com/modelcontextprotocol/ext-apps .context/ext-apps +cd .context/ext-apps +npm install --ignore-scripts # root install; NOT inside examples/basic-host +npm run build -w examples/basic-host # build just this workspace +``` + +If the clone lives under a dot-directory (like `.context/`), patch +`examples/basic-host/serve.ts` (~line 127): + +```ts +// before (fails: express/send dotfiles policy rejects absolute paths +// containing a dot-directory segment): +res.sendFile(join(DIRECTORY, "sandbox.html")); +// after: +res.sendFile("sandbox.html", { root: DIRECTORY }); +``` + +An already-prepared clone may exist at `.context/ext-apps` (gitignored; +re-create it with the steps above if missing). + +## Run it + +Terminal 1 — the demo Shiny app (from the repo root): + +```sh +Rscript -e 'devtools::load_all(); shiny::runApp("mcp/demo-app", port = 7788)' +``` + +Terminal 2 — the host: + +```sh +mcp/run-mcp-host.sh # defaults to :7788/mcp +# or: mcp/run-mcp-host.sh http://127.0.0.1:9999/mcp +``` + +Then open +(or plain and click Call Tool). + +## Showing the app in a real Claude session + +Claude Code (terminal) does **not** render MCP Apps iframes — use Claude +Desktop (local) or claude.ai (deployed). + +### Claude Desktop (local, stdio) + +Add the app as a local stdio server in +`~/Library/Application Support/Claude/claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "shiny-demo": { + "command": "Rscript", + "args": [ + "-e", + "setwd('/ABSOLUTE/PATH/TO/shiny-repo'); pkgload::load_all(quiet = TRUE); options(shiny.mcp = TRUE, shiny.mcp.stdio = TRUE); shiny::runApp('mcp/demo-app', launch.browser = FALSE)" + ] + } + } +} +``` + +Then fully restart Claude Desktop (Cmd-Q, not just close the window) and ask +it to *"open the shiny app"* — it calls the `open_shiny_app` tool and the app +renders inline in the conversation. + +Notes: + +- `pkgload::load_all()` is needed until this branch is installed as + {shiny}; once installed, replace it with `library(shiny)`. +- Claude Desktop spawns servers without your login-shell `PATH` — if + `Rscript` isn't found, use its absolute path (`which Rscript`). +- BOTH options are required: `shiny.mcp` enables the endpoint, + `shiny.mcp.stdio` speaks the protocol on stdin/stdout. +- Never `cat()`/`print()` to stdout in the app at top level — stdout is the + protocol channel (`message()` is fine). +- R startup can exceed host connect timeouts; for the `claude` CLI use + `MCP_TIMEOUT=120000`. Pre-warm `pkgload::load_all()` once so compilation + isn't paid at connect time. + +### claude.ai (web, deployed) + +Deploy the app (with `options(shiny.mcp = TRUE)` set in app.R / .Rprofile) +somewhere with a public HTTPS URL — e.g. Posit Connect — then in claude.ai: +Settings → Connectors → *Add custom connector* → URL +`https:///mcp`. The direct-connect fast path may be blocked +there (claude.ai currently hardcodes the iframe CSP, +anthropics/claude-ai-mcp#40); the postMessage tunnel still works. + +## Gotchas + +- `SANDBOX_PORT` must stay 8081 — the sandbox URL is hardcoded in the built + client (`examples/basic-host/src/implementation.ts`). `HOST_PORT` is + flexible (default here 8090; :8080 tends to be occupied locally). +- Don't `npm install` inside `examples/basic-host` (monorepo prepare script + needs husky/bun); install at the ext-apps root with `--ignore-scripts`. +- `npm start` in basic-host needs bun; `run-mcp-host.sh` uses `npx tsx serve.ts`. +- Zero-setup alternative: `npx @mcpjam/inspector` and paste the /mcp URL. +- Claude Code (terminal) can register the server + (`claude mcp add --transport http my-shiny-app http://127.0.0.1:7788/mcp`) + and call tools, but does not render MCP Apps iframes. Rendering hosts: + Claude / Claude Desktop, VS Code Copilot, MCPJam, basic-host. diff --git a/mcp/README.md b/mcp/README.md new file mode 100644 index 0000000000..7c02ce5e9d --- /dev/null +++ b/mcp/README.md @@ -0,0 +1,142 @@ +# Shiny × MCP Apps (SEP-1865) — working docs + +Planning documents, research notes, and demo material for Shiny's experimental +MCP Apps support. Collected here for discoverability; the location may move. +Keep these in sync with the sources listed below. + +## Status (2026-07-10) + +Phases 1 and 2 are implemented and E2E-verified. With `options(shiny.mcp = +TRUE)`, a Shiny app serves an MCP endpoint at `/mcp` on its own port, and MCP +Apps hosts render the live, reactive app in a sandboxed iframe (websocket +traffic tunneled over postMessage → `tools/call`). + +- **Phase 1:** endpoint, session tunnel, single-file `ui://shiny/app` + resource, `Shiny.createSocket` bridge. Inputs/outputs/plots/dynamic UI. +- **Phase 2:** HTTP side channels tunneled via `_shiny_http` (file + upload/download, server-side DataTables/selectize, dynamically inserted + htmlDependencies inlined for the sandbox), plus host theme/style variables, + tool-input/result delivered to `session$clientData`, and + `session$sendCustomMessage("shiny.mcp.updateModelContext" | "…sendMessage")` + bridges. Verified in basic-host: upload, dynamic panel, server-side + selectize, theme toggle (`screenshot-e2e-phase2.png`). + +- **CSS assets:** relative `url()` refs inside inlined stylesheets (webfonts, + background images) are rewritten to `data:` URIs, so icon fonts like + FontAwesome render in the sandbox (`screenshot-e2e-css-fonts.png`). Legacy + font fallback formats (ttf/otf/eot) are intentionally left un-inlined — + browsers never fetch them once the inlined woff2 loads — keeping the + resource ~2.3 MB instead of ~5 MB. +- **Stdio transport:** `options(shiny.mcp.stdio = TRUE)` additionally speaks + newline-delimited JSON-RPC over stdin/stdout (non-blocking stdin polled + from the `later` loop, coexisting with httpuv), so local hosts can launch + the app process directly: + + ```sh + claude mcp add shiny-demo -- Rscript -e \ + "options(shiny.mcp=TRUE, shiny.mcp.stdio=TRUE); shiny::runApp('path/to/app', launch.browser=FALSE)" + ``` + + Verified E2E: `claude --print` launched the demo app over stdio and called + `get_sample_stats` successfully. Caveats: stdout is reserved for the + protocol (don't `cat()` to it; `message()` is fine), no Windows support + (non-blocking stdin), and terminal Claude Code still doesn't render the + iframe UI — tools/resources only. +- **Direct-connect fast path:** the resource declares the app's origin in + `_meta.ui.csp.connectDomains`, and the bridge tries a real WebSocket + (`/websocket/?mcp=1`, 2.5 s timeout) before falling back to the + tunnel. The base URL is **path-aware** so sub-path deployments (Posit + Connect `/content/`) connect directly: priority is + `options(shiny.mcp.origin=)` → Connect's `RStudio-Connect-App-Base-Url` + header (what Connect actually sends to Shiny content, verified on a real + deployment; `X-RSC-Request` also honored for API content) → + shinyapps.io's `X-Redx-Frontend-Name` header (schemeless host + path, + verified on a real deployment) → a + host-matched deployment record written at deploy time (rsconnect's + `rsconnect/**/*.dcf` `url` or Posit Publisher's + `.posit/publish/deployments/*.toml` `direct_url`; Quarto's `_publish.yml` + was considered and dropped) → request + `Host` + `X-Forwarded-Proto` → local httpuv origin (stdio). Deployment + records are only trusted when their host matches the serving request, so + local runs of deployed app dirs never point the iframe at production — + note rsconnect does **not** include its `rsconnect/` records in the + uploaded bundle, so on the server the header is the working signal. Verified in + basic-host (`__shinyMcpTransport__ === "direct"`) and against a real + connect.posit.it deployment. HTTP side channels stay tunneled (no + CORS exposure) via connectionId-less `_shiny_http`. Disable with + `options(shiny.mcp.direct = FALSE)`. +- **Display modes:** the app declares + `options(shiny.mcp.displayModes = ...)` (default: inline, fullscreen, + pip) and can call `mcpRequestDisplayMode("fullscreen")`; the resulting + mode arrives via `mcpHostContext()$displayMode`. Unit-tested; basic-host + doesn't implement display modes, so not yet E2E-verified on a real host. +- **Author-declared tools:** `options(shiny.mcp.tools = list(list(name=, + description=, inputSchema=, handler=)))` exposes plain R functions as + model-callable MCP tools alongside the app tool. Handlers run in the + server R process (no session), may return character/list/promise, and + errors surface as MCP tool errors. Invalid or name-colliding specs are + skipped with a warning. Verified E2E in basic-host (`get_sample_stats` + in the demo app). +- **Multi-app gateway (one connector, many apps):** each app sets a unique + `options(shiny.mcp.appId = "")`, which namespaces its internal + `_shiny_*` tools (`demo_shiny_connect`, ...) and publishes its resource + as `ui://shiny/`; `gateway/shiny-mcp-gateway.mjs` (zero-dep Node, + stdio or `--port` HTTP) then merges several app endpoints into a single + MCP server. E2E verified in basic-host with `demo-app` + `demo-app2` + behind one gateway, including full tunnel reactivity + (`screenshot-e2e-gateway.png`); see `gateway/README.md`. +- **Session API (exported, experimental):** `isMcpSession()`, + `mcpToolInput()` (parsed tool arguments, reactive), `mcpHostContext()` + (theme/locale/display mode, reactive), `mcpUpdateModelContext(text=, data=)` + (updates the model's context; no-op outside MCP), and `mcpSendMessage(text)` + (user-role chat message). Tool arguments are declared via + `options(shiny.mcp.tool = list(name=, description=, inputSchema=))`. + See `man/mcp-session.Rd` and `demo-app/app.R`; verified E2E in basic-host + (`screenshot-e2e-session-api.png`: tool input moves the slider and shows a + note; the host's Model Context panel tracks the app; `ui/message` logged + by the host). + +Implementation lives in `R/mcp-server.R`, `R/mcp-tunnel.R`, `R/mcp-app.R`, +`R/html-deps.R` (processDeps hook), `srcts/src/mcp/` (built to +`inst/www/shared/shiny-mcp-bridge.js`), with tests in +`tests/testthat/test-mcp-*.R` and `srcts/src/mcp/__tests__/`. + +## Contents + +| File | What it is | Source of truth | +|---|---|---| +| `architecture.md` | **How the system as built works** — start here | — | +| `research-notes.md` | Protocol research, Shiny transport seams, the three candidate architectures + recommendation | `.context/mcp-apps-research.md` | +| `design-spec.md` | Approved Phase 1 design | `docs/superpowers/specs/2026-07-10-shiny-mcp-apps-design.md` | +| `implementation-plan-phase1.md` | Phase 1 task-by-task plan (executed) | `docs/superpowers/plans/2026-07-10-shiny-mcp-apps-phase1.md` | +| `implementation-plan-phase2.md` | Phase 2 task-by-task plan (executed) | `docs/superpowers/plans/2026-07-10-shiny-mcp-apps-phase2.md` | +| `demo-app/app.R` | Demo app (slider/plot, upload, download, server-side selectize, dynamic UI) with MCP enabled | `.context/mcp-demo/app.R` | +| `demo-app2/app.R` | Second demo app (mtcars explorer, appId `cars`) for the multi-app gateway | — | +| `gateway/shiny-mcp-gateway.mjs` | Zero-dep Node gateway merging several Shiny MCP endpoints into one server | — | +| `gateway/README.md` | Gateway usage + design | — | +| `screenshot-e2e-gateway.png` | Gateway E2E proof: two apps behind one connector | — | +| `README-mcp-host.md` | How to run the ext-apps basic-host against a Shiny app, with all gotchas | — | +| `run-mcp-host.sh` | Start script for the basic-host (host :8090, sandbox :8081) | — | +| `screenshot-e2e-basic-host.png` | Phase 1 E2E proof: demo app reactive inside the sandboxed iframe | — | +| `screenshot-e2e-phase2.png` | Phase 2 E2E proof: upload + dynamic UI + selectize + theme | — | +| `screenshot-e2e-css-fonts.png` | CSS url() inlining proof: FontAwesome glyph renders in the sandbox | — | +| `screenshot-e2e-session-api.png` | Session API proof: tool input + Model Context panel | — | +| `mcptools-upstream-notes.md` | Gaps {mcptools} would need to close to host this (candidate upstream issues) | — | +| `comparison-shinymcp.md` | How this compares to JamesHWade/shinymcp (team-shareable) | — | +| `QUESTIONS.md` | Open decisions for Barret, with context | — | + +## Quick start + +```sh +# Terminal 1 +Rscript -e 'devtools::load_all(); shiny::runApp("mcp/demo-app", port = 7788)' +# Terminal 2 (needs a prepared ext-apps clone; see README-mcp-host.md) +mcp/run-mcp-host.sh +# Browser +open "http://localhost:8090/?server=shiny&tool=open_shiny_app&call=true" +``` + +## Backlog + +Upstreaming resources/`_meta`/async support to {mcptools} (see +`mcptools-upstream-notes.md`), and the open decisions in `QUESTIONS.md`. diff --git a/mcp/architecture.md b/mcp/architecture.md new file mode 100644 index 0000000000..12e1318901 --- /dev/null +++ b/mcp/architecture.md @@ -0,0 +1,255 @@ +# Shiny × MCP Apps — architecture + +How {shiny}'s experimental MCP Apps (SEP-1865) support is built, as +implemented on branch `schloerke/shiny-mcp-app-protocol` (PR +rstudio/shiny#4407). This is the "how it all fits together" document; +`design-spec.md` records only the original Phase 1 design, and +`research-notes.md` the pre-implementation research. + +## The problem + +MCP Apps hosts (Claude Desktop, claude.ai, basic-host, ...) render a tool's +UI as **static HTML in a sandboxed iframe**. The iframe may not load +external resources, and its only guaranteed channel to the outside world is +**postMessage JSON-RPC to the host**, which the host relays to the MCP +server as `tools/call` requests. There is **no server→app push**. + +Shiny's model is the opposite: a live server process, a WebSocket for +reactivity, and HTTP side channels (uploads, downloads, server-side +selectize/DataTables, dynamic dependencies) against the app's own origin. + +Everything below is about bridging those two models without changing app +code. + +## Big picture + +``` +options(shiny.mcp = TRUE) +┌─────────────────────────── R process ────────────────────────────┐ +│ httpuv (the app's normal port) │ +│ ├── / normal Shiny app (browser use unchanged) │ +│ ├── /websocket/ normal Shiny websocket │ +│ └── /mcp MCP JSON-RPC endpoint (streamable HTTP, JSON) │ +│ └── mcpDispatch() ── tools / resources │ +│ optional: stdio transport (newline JSON-RPC) → same dispatch │ +└──────────────────────────────────────────────────────────────────┘ + ▲ tools/call ▲ real WebSocket (fast path) +┌─────────┴───────────┐ ┌─────────┴──────────┐ +│ MCP host (Claude) │ postMsg │ sandboxed iframe │ +│ conversation UI │ ◄──────► │ single-file HTML │ +└─────────────────────┘ │ app + JS bridge │ + └────────────────────┘ +``` + +Three transports, one dispatcher: + +1. **Streamable HTTP** — `POST /mcp` on the app's own httpuv port + (`R/mcp-server.R:mcpHttpHandler`). JSON responses only (no SSE); + `GET /mcp` returns 405. CORS headers are sent on the `/mcp` endpoint + only. +2. **stdio** — `options(shiny.mcp.stdio = TRUE)` additionally speaks + newline-delimited JSON-RPC on stdin/stdout (`R/mcp-stdio.R`), so local + hosts can launch the R process directly (`claude mcp add -- Rscript + ...`). Non-blocking `file("stdin")` polled from the `later` loop + coexists with httpuv. stdout is reserved for the protocol; Windows + unsupported. +3. **postMessage tunnel / direct WebSocket** — how the *iframe* reaches + the server; see "Two transports for reactivity" below. + +All three go through `mcpDispatch(body, uiHandler, wsHandler)` +(`R/mcp-server.R`), which implements `initialize`, `ping`, `tools/list`, +`tools/call`, `resources/list`, `resources/read`. The stdio loop reuses +the closure `createAppHandlers()` stashes in `.globals$mcpDispatch`. + +## What the host sees + +- **Tools** (`mcpToolsList()`): + - the *app tool* (default `open_shiny_app`; customizable via + `options(shiny.mcp.tool = list(name=, description=, inputSchema=))`) + with `_meta.ui.resourceUri` pointing at the app resource — calling it + makes the host render the iframe; + - five *internal tunnel tools* `_shiny_connect/_send/_receive/_close/ + _http`, marked `_meta.ui.visibility = ["app"]` so only the iframe (not + the model) can call them; + - *author tools* from `options(shiny.mcp.tools = list(...))` — plain R + functions exposed to the model, run sessionless in the server process + (character → text content, list → structuredContent, promises + supported, errors → `isError`). Reserved/colliding names are skipped + with a one-time warning. +- **One resource**: `ui://shiny/app` (or `ui://shiny/`, see + gateway section), mime `text/html;profile=mcp-app`. + +Serialization gotcha: partially named R lists serialize as JSON *objects*; +`tools/list` needs `unname()` to stay a JSON array. R-side parse tests +don't catch this — only raw-JSON/curl checks do. + +## The single-file resource (R/mcp-app.R) + +`renderMcpAppHtml(uiHandler, config)` renders the app's UI page and makes +it self-contained, because the sandbox can't fetch anything: + +- `inlineHtmlAssets()` inlines every `") +} + +escapeScriptContent <- function(x) { + gsub(" + html <- inlineTagPattern( + html, + pattern = "]*\\ssrc=\"([^\"]+)\"[^>]*>\\s*", + build = function(file) { + js <- readAssetText(file) + paste0("") + } + ) + # + inlineTagPattern( + html, + pattern = "]*\\shref=\"([^\"]+)\"[^>]*/?>", + build = function(file) { + css <- readAssetText(file) + paste0("") + }, + onlyIf = function(tag) grepl("stylesheet", tag, fixed = TRUE) + ) +} + +readAssetText <- function(file) { + txt <- readChar(file, file.info(file)$size, useBytes = TRUE) + Encoding(txt) <- "UTF-8" + txt +} + +inlineTagPattern <- function(html, pattern, build, onlyIf = NULL) { + matches <- gregexpr(pattern, html, ignore.case = TRUE)[[1]] + if (identical(as.integer(matches[1]), -1L)) return(html) + + lengths <- attr(matches, "match.length") + out <- character(0) + last <- 1 + for (i in seq_along(matches)) { + start <- matches[i] + end <- start + lengths[i] - 1 + tag <- substr(html, start, end) + replacement <- tag + if (is.null(onlyIf) || isTRUE(onlyIf(tag))) { + url <- sub(pattern, "\\1", tag, ignore.case = TRUE) + file <- resolveAssetFile(url) + if (!is.null(file)) replacement <- build(file) + # If unresolvable, drop external refs entirely (sandbox can't load them) + else replacement <- "" + } + out <- c(out, substr(html, last, start - 1), replacement) + last <- end + 1 + } + out <- c(out, substr(html, last, nchar(html))) + paste(out, collapse = "") +} +``` + +Update `R/mcp-server.R`: + +```r +mcpResourcesList <- function() { + list(list( + uri = MCP_RESOURCE_URI, + name = "Shiny application", + description = "The interactive Shiny application UI.", + mimeType = MCP_RESOURCE_MIME, + `_meta` = list(ui = list(prefersBorder = TRUE)) + )) +} + +mcpResourcesRead <- function(body, uiHandler) { + uri <- body$params$uri %||% "" + if (!identical(uri, MCP_RESOURCE_URI)) { + return(mcpError(body$id, -32602L, sprintf("Unknown resource: %s", uri))) + } + html <- renderMcpAppHtml(uiHandler) + mcpResult(body$id, list(contents = list(list( + uri = MCP_RESOURCE_URI, + mimeType = MCP_RESOURCE_MIME, + text = html + )))) +} +``` + +Also create placeholder `inst/www/shared/shiny-mcp-bridge.js` containing `/* shiny-mcp-bridge placeholder; built by npm run build (Task 5) */` so R code paths work before Task 5. + +- [x] **Step 4: Run tests, verify pass** (all three mcp test files). + +- [x] **Step 5: Add `'mcp-app.R'` to Collate; commit** — `git commit -am "feat(mcp): ui://shiny/app single-file resource with inlined assets"` + +--- + +### Task 5: TypeScript bridge (`srcts/src/mcp/`) + build + +**Files:** +- Create: `srcts/src/mcp/tunnel-socket.ts`, `srcts/src/mcp/index.ts` +- Create: `srcts/src/mcp/__tests__/tunnel-socket.test.ts` +- Create: `srcts/build/mcp-bridge.ts` +- Modify: `package.json` (devDependency `@modelcontextprotocol/ext-apps`; scripts `bundle_mcp`, include in `build`) +- Produces artifact: `inst/www/shared/shiny-mcp-bridge.js` (committed) + +**Interfaces:** +- Consumes (server, Tasks 3-4): tools `_shiny_connect` → `structuredContent.connectionId: string`; `_shiny_send {connectionId, frames: [{data, binary}]}`; `_shiny_receive {connectionId}` → `structuredContent: {frames: [{data, binary}], closed: boolean}`; `_shiny_close {connectionId}`. +- Consumes (client): `window.Shiny.createSocket` extension point; WebSocket interface expected by `shinyapp.ts` (`send`, `close`, `readyState` truthy when open, settable `onopen/onmessage/onclose`). +- Produces: IIFE bundle that, on load, instantiates the ext-apps `App`, connects, and installs `Shiny.createSocket`. + +- [x] **Step 1: Install dep** — `npm install --save-dev @modelcontextprotocol/ext-apps`. Then inspect `node_modules/@modelcontextprotocol/ext-apps/dist/*.d.ts` for the exact `App` API (`connect()`, `callServerTool()`, teardown callback name) and adjust the code below to the real names before writing it. + +- [x] **Step 2: Write failing TS test** — `srcts/src/mcp/__tests__/tunnel-socket.test.ts` (node test runner style used by `npm run test_types`): + +```ts +import assert from "node:assert"; +import test from "node:test"; +import { McpTunnelWebSocket, type ToolCaller } from "../tunnel-socket"; + +function makeHost(receiveBatches: Array<{ frames: any[]; closed: boolean }>) { + const sent: any[] = []; + const caller: ToolCaller = async (name, args) => { + if (name === "_shiny_connect") return { connectionId: "abc" }; + if (name === "_shiny_send") { + sent.push(args); + return {}; + } + if (name === "_shiny_receive") { + const batch = receiveBatches.shift(); + if (batch) return batch; + return await new Promise(() => {}); // hang (no more data) + } + if (name === "_shiny_close") return {}; + throw new Error("unknown tool " + name); + }; + return { caller, sent }; +} + +test("opens, delivers frames in order, sends, and closes", async () => { + const { caller, sent } = makeHost([ + { frames: [{ data: '{"config":{}}', binary: false }], closed: false }, + { frames: [], closed: true }, + ]); + const sock = new McpTunnelWebSocket(caller); + const events: string[] = []; + sock.onopen = () => events.push("open"); + sock.onmessage = (e: { data: any }) => events.push("msg:" + e.data); + sock.onclose = () => events.push("close"); + await sock.start(); + // allow poll loop to drain + await new Promise((r) => setTimeout(r, 20)); + sock.send('{"method":"init","data":{}}'); + await new Promise((r) => setTimeout(r, 20)); + assert.deepEqual(events[0], "open"); + assert.ok(events.includes('msg:{"config":{}}')); + assert.ok(events.includes("close")); + assert.equal(sent.length, 1); + assert.equal(sent[0].frames[0].data, '{"method":"init","data":{}}'); +}); +``` + +Run: `npx tsx --test srcts/src/mcp/__tests__/tunnel-socket.test.ts` → FAIL (module missing). + +- [x] **Step 3: Implement `srcts/src/mcp/tunnel-socket.ts`:** + +```ts +export type ToolCaller = ( + name: string, + args: Record +) => Promise>; + +type Frame = { data: string; binary?: boolean }; +type ReceiveResult = { frames?: Frame[]; closed?: boolean }; + +function b64ToArrayBuffer(b64: string): ArrayBuffer { + const bin = atob(b64); + const bytes = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i); + return bytes.buffer; +} + +function arrayBufferToB64(buf: ArrayBuffer): string { + const bytes = new Uint8Array(buf); + let bin = ""; + for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]); + return btoa(bin); +} + +export class McpTunnelWebSocket { + readyState = 0; // CONNECTING + binaryType = "arraybuffer"; + allowReconnect = false; + + onopen: (() => void) | null = null; + onmessage: ((event: { data: string | ArrayBuffer }) => void) | null = null; + onclose: ((event: { code: number }) => void) | null = null; + onerror: ((event: unknown) => void) | null = null; + + private connectionId: string | null = null; + + constructor(private callTool: ToolCaller) {} + + async start(): Promise { + try { + const result = await this.callTool("_shiny_connect", {}); + this.connectionId = String(result.connectionId); + this.readyState = 1; // OPEN + this.onopen?.(); + void this.pollLoop(); + } catch (err) { + this.fail(err); + } + } + + send(data: string | ArrayBuffer): void { + if (this.readyState !== 1 || this.connectionId === null) return; + const frame: Frame = + typeof data === "string" + ? { data, binary: false } + : { data: arrayBufferToB64(data), binary: true }; + this.callTool("_shiny_send", { + connectionId: this.connectionId, + frames: [frame], + }).catch((err) => this.fail(err)); + } + + close(code = 1000): void { + if (this.readyState >= 2) return; + this.readyState = 2; // CLOSING + const id = this.connectionId; + this.connectionId = null; + if (id !== null) { + void this.callTool("_shiny_close", { connectionId: id }).catch(() => { + /* already closing */ + }); + } + this.finishClose(code); + } + + private async pollLoop(): Promise { + while (this.readyState === 1 && this.connectionId !== null) { + let result: ReceiveResult; + try { + result = (await this.callTool("_shiny_receive", { + connectionId: this.connectionId, + })) as ReceiveResult; + } catch (err) { + this.fail(err); + return; + } + for (const frame of result.frames ?? []) { + if (this.readyState !== 1) break; + const data = frame.binary ? b64ToArrayBuffer(frame.data) : frame.data; + this.onmessage?.({ data }); + } + if (result.closed) { + this.finishClose(1000); + return; + } + } + } + + private fail(err: unknown): void { + this.onerror?.(err); + this.finishClose(1006); + } + + private finishClose(code: number): void { + if (this.readyState === 3) return; + this.readyState = 3; // CLOSED + this.onclose?.({ code }); + } +} +``` + +- [x] **Step 4: Run TS test, verify pass** — `npx tsx --test srcts/src/mcp/__tests__/tunnel-socket.test.ts`. + +- [x] **Step 5: Implement `srcts/src/mcp/index.ts`** (adjust to the real ext-apps API found in Step 1): + +```ts +import { App } from "@modelcontextprotocol/ext-apps"; +import { McpTunnelWebSocket, type ToolCaller } from "./tunnel-socket"; + +declare global { + interface Window { + Shiny?: { createSocket?: () => unknown }; + } +} + +async function main(): Promise { + const app = new App({ name: "shiny", version: "0.1.0" }); + + const callTool: ToolCaller = async (name, args) => { + const result = await app.callServerTool({ name, arguments: args }); + if (result.isError) { + const text = result.content?.find((c: any) => c.type === "text")?.text; + throw new Error(text ?? "MCP tool error"); + } + return (result.structuredContent ?? {}) as Record; + }; + + let socket: McpTunnelWebSocket | null = null; + + // Install before Shiny's DOM-ready initialization runs. + if (window.Shiny) { + window.Shiny.createSocket = () => { + socket = new McpTunnelWebSocket(callTool); + // start() is async; shinyapp assigns handlers right after createSocket + // returns, so defer to the next macrotask. + setTimeout(() => void socket?.start(), 0); + return socket; + }; + } + + // Graceful teardown (verify exact API name in the SDK). + app.onteardown = async () => { + socket?.close(); + return {}; + }; + + await app.connect(); +} + +void main(); +``` + +- [x] **Step 6: Build script `srcts/build/mcp-bridge.ts`:** + +```ts +import type { BuildOptions } from "esbuild"; +import { banner, build, outDir } from "./_build"; + +const opts: BuildOptions = { + entryPoints: ["srcts/src/mcp/index.ts"], + bundle: true, + sourcemap: false, + format: "iife", + banner: banner, +}; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +build({ ...opts, outfile: outDir + "shiny-mcp-bridge.js" }); +``` + +`package.json`: add `"bundle_mcp": "tsx srcts/build/mcp-bridge.ts"` and append `&& npm run bundle_mcp` to the `build` script. Run `npm run bundle_mcp`; verify `inst/www/shared/shiny-mcp-bridge.js` is a non-placeholder bundle. + +- [x] **Step 7: Re-run R test file test-mcp-app.R** (bridge now real; assertions still pass). + +- [x] **Step 8: Commit** — `git add srcts package.json package-lock.json inst/www/shared/shiny-mcp-bridge.js && git commit -m "feat(mcp): postMessage bridge bundle overriding Shiny.createSocket"` + +--- + +### Task 6: End-to-end verification with basic-host + +**Files:** none committed (scratch demo app + local clone of ext-apps). + +- [x] **Step 1:** Scratch app `/tmp/mcp-demo/app.R`: + +```r +library(shiny) +options(shiny.mcp = TRUE) +shinyApp( + ui = fluidPage( + titlePanel("MCP demo"), + sliderInput("n", "Observations", 10, 500, 100), + plotOutput("hist"), + textOutput("txt") + ), + server = function(input, output) { + output$hist <- renderPlot(hist(rnorm(input$n), col = "steelblue")) + output$txt <- renderText(paste("n =", input$n)) + } +) +``` + +Run: `Rscript -e 'shiny::runApp("/tmp/mcp-demo", port = 7788)'` (background). + +- [x] **Step 2:** Smoke-test endpoint with curl: `initialize`, `tools/list`, `resources/read` (assert HTML > 100 KB and contains `createSocket`), `_shiny_connect` → `_shiny_send` init → `_shiny_receive` returns config frame. + +- [x] **Step 3:** `git clone https://github.com/modelcontextprotocol/ext-apps /tmp/ext-apps && cd /tmp/ext-apps/examples/basic-host && npm install && SERVERS='["http://127.0.0.1:7788/mcp"]' npm start` (port 8080). + +- [x] **Step 4:** Browser automation: open `http://localhost:8080`, call the `open_shiny_app` tool, verify the iframe renders the slider + histogram, move the slider, verify plot + `n = …` text update reactively. Screenshot for the report. + +- [x] **Step 5:** Fix any fallout found (iterate Tasks 1-5 tests alongside), commit fixes. + +--- + +### Task 7: NEWS + final checks + +- [x] **Step 1:** Add NEWS.md bullet under the development version: + `* Experimental: Shiny apps can be served as MCP Apps (SEP-1865). Setting options(shiny.mcp = TRUE) mounts a Model Context Protocol endpoint at /mcp that lets MCP hosts (Claude Desktop, VS Code, MCPJam, ...) render the live app in a sandboxed iframe. (#XXXX)` +- [x] **Step 2:** Run full R test suite (`devtools::test()`) and `npm run test_types`; fix regressions. +- [x] **Step 3:** Commit — `git commit -am "docs(mcp): NEWS entry for experimental MCP Apps support"`. + +--- + +## Self-review notes + +- Spec coverage: endpoint (T1/T2), tunnel + long-poll + GC (T3), single-file resource + bridge injection (T4), bridge/createSocket override + build (T5), E2E success criterion (T6), docs (T7). Phase-2 items (uploads, downloads, dataobj, host theming, tool-input) intentionally out of scope per spec. +- Known judgment calls: no piggyback of frames on `_shiny_send` responses (strict ordering via single in-flight `_shiny_receive`); unresolvable asset refs are dropped rather than left dangling; shared-secret apps unsupported over the tunnel (documented). +- The ext-apps `App` API names (`callServerTool`, teardown hook) must be verified against the installed package in Task 5 Step 1 and code adjusted accordingly. diff --git a/mcp/implementation-plan-phase2.md b/mcp/implementation-plan-phase2.md new file mode 100644 index 0000000000..8db40227cc --- /dev/null +++ b/mcp/implementation-plan-phase2.md @@ -0,0 +1,53 @@ +# Shiny MCP Apps (Phase 2) Implementation Plan + +> **Status: in progress 2026-07-10.** Executed inline by the same agent that did Phase 1. + +**Goal:** Close the HTTP side-channel gaps (uploads, downloads, server-side DataTables/selectize, dynamic htmlDependencies) and integrate host features (theme/styles, tool-input, model-context updates) so realistic Shiny apps work inside the MCP Apps sandbox. + +**Architecture:** One new app-only tool `_shiny_http` invokes the app's existing Rook handler chain in-process (promise-aware). On the client, the bridge swaps `window.XMLHttpRequest` for a tunnel implementation inside the sandboxed iframe — jQuery's ajax (uploads, DataTables, selectize) and raw XHR (restyle) all route through it with no shiny.js changes. Dynamic htmlDependencies are inlined **server-side** for MCP sessions via a `processDeps()` hook (the client executes `dep.head` HTML, render.ts:498). Downloads are intercepted at the `a.shiny-download-link` click and delivered as blob URLs. Host theme/styles apply via the SDK helpers; tool-input lands in `session$clientData`; `session$sendCustomMessage("shiny.mcp.updateModelContext", ...)` / `"shiny.mcp.sendMessage"` bridge to `app.updateModelContext()` / `app.sendMessage()`. + +## Global Constraints + +- Same as Phase 1 (no new R deps, no exported R API; options-gated; frames base64). +- `_shiny_http` args: `{connectionId, method, path, headers?, body?}` (`body` base64; `path` may include query string). Result `structuredContent`: `{status, headers, body}` (`body` base64). Requires a live `connectionId`. +- The tunnel handler chain excludes the `/mcp` endpoint itself (no recursion): `sessionHandler + app httpHandlers + sys.www.root + resourcePathHandler`. +- MCP sessions are detected via `HTTP_MCP_TUNNEL = "1"` on the fake ws request. +- Custom message types: `shiny.mcp.updateModelContext`, `shiny.mcp.sendMessage`. +- Tool input/result surface as `session$clientData$mcp_tool_input` / `mcp_tool_result` (JSON-encoded string values via `.clientdata_*` inputs). + +### Task 1: `_shiny_http` tool (R) + +- `mcpRookInput(bytes)`: stateful `read(l = -1)` (consumes; `raw(0)` at EOF), `rewind()`, `read_lines()` stub — the upload handler loops `read(2^16)` until empty, so Phase 1's replay-everything fake would infinite-loop. +- `McpConnection$new()` request gains `HTTP_MCP_TUNNEL = "1"`. +- `mcpTunnelToolCall()` gains `_shiny_http`, with a `tunnelHttpHandler` built in `createAppHandlers()` and threaded through `mcpHttpHandler(uiHandler, wsHandler, tunnelHttpHandler)`. +- Request env: `REQUEST_METHOD`, `PATH_INFO`/`QUERY_STRING` split from `path`, `CONTENT_TYPE`/`CONTENT_LENGTH` + `HTTP_*` from headers, `rook.input`. +- Response serialization handles `content` as character, raw, and `list(file=, owned=)` (read + optionally delete). +- Tests: chunked rook input; static asset GET via chain; 404; `registerDownload` → `_shiny_http` GET returns bytes + `Content-Disposition` (uses a real tunnel session). + +### Task 2: dynamic dependency inlining (R) + +- `isMcpSession(session)`: checks `session$request$HTTP_MCP_TUNNEL`. +- `mcpInlineDependency(dep)`: file-based scripts/stylesheets → `head` inline HTML (reuse `readAssetText`/`escape*Content`); keeps existing `head`; drops `meta`/`attachment`; falls back to `createWebDependency()` when no `src$file`. +- `processDeps()` picks the transform based on `isMcpSession(session)`. +- Tests: inline transform shape; processDeps with a real tunnel session produces head-inlined deps; non-MCP session unchanged. + +### Task 3: TunnelXMLHttpRequest + downloads (TS) + +- `srcts/src/mcp/tunnelXhr.ts`: minimal XHR surface used by jQuery 3 + render.ts restyle (`open/setRequestHeader/send/abort/getAllResponseHeaders/getResponseHeader/overrideMimeType`, `readyState/status/statusText/responseText/response/responseType`, `onload/onerror/onabort/ontimeout/onreadystatechange`). Tunnels same-origin/relative URLs via `_shiny_http`; delegates absolute foreign URLs to the native XHR. Body support: string, Blob/File (→ ArrayBuffer → base64), ArrayBuffer/TypedArray. +- Bridge installs it (`window.XMLHttpRequest = makeTunnelXhr(...)`) once the socket connects. +- Download interception: capture-phase click listener on `a.shiny-download-link` → preventDefault → tunnel GET → blob URL + `` click (filename from `Content-Disposition`). +- Tests: node test for TunnelXhr GET/POST/binary/headers/error with a mock caller. + +### Task 4: host integration (TS) + +- On connect + `onhostcontextchanged`: `applyDocumentTheme(theme)`, `applyHostStyleVariables(styles)`, `applyHostFonts(styles.css.fonts)` (SDK helpers). +- `app.ontoolinput` / `app.ontoolresult` → `Shiny.setInputValue(".clientdata_mcp_tool_input" / "_result", JSON string)` (queued until Shiny connects). +- `Shiny.addCustomMessageHandler("shiny.mcp.updateModelContext", ...)` → `app.updateModelContext(msg)`; same for `sendMessage`. + +### Task 5: rebuild, full test pass + +### Task 6: E2E in basic-host + +Demo app grows: `fileInput` (+ uploaded-file preview), `downloadButton` (CSV), `selectizeInput` with `updateSelectizeInput(server = TRUE)`, dynamic UI via `insertUI` carrying a new dependency. Verify each in the rendered iframe; verify theme toggle (host dark-mode button) restyles the app. + +### Task 7: docs — NEWS update, mcp/ mirror refresh, commit diff --git a/mcp/mcptools-upstream-notes.md b/mcp/mcptools-upstream-notes.md new file mode 100644 index 0000000000..fcce27c321 --- /dev/null +++ b/mcp/mcptools-upstream-notes.md @@ -0,0 +1,60 @@ +# What {mcptools} would need to serve MCP Apps (upstream notes) + +Barret's original preference was to build Shiny's MCP support on +{posit-dev/mcptools}. That wasn't possible (verified against v1.0.0 and the +dev branch on 2026-07-10), so shiny grew a minimal internal endpoint +(`R/mcp-server.R`). This file documents the gaps as candidate upstream +issues/PRs, so the two implementations can converge later. + +## Gaps in mcptools (as of 1.0.0.9000) + +1. **No resources support.** `resources/list` and `resources/read` fall + through to `Method not found` (`R/server.R`, + `handle_http_request_message()` / `handle_message_from_client()`), even + though `capabilities()` advertises `resources`. MCP Apps requires + `resources/read` to deliver the `ui://` HTML. + +2. **No tool `_meta`.** `tool_as_json()` emits + name/title/description/inputSchema/annotations only. MCP Apps needs + `_meta.ui.resourceUri` on the app tool and `_meta.ui.visibility` on + app-only tools; ellmer's tool annotations have no place to carry + arbitrary `_meta`. + +3. **Synchronous-only tool execution.** `execute_tool_call()` returns + immediately; the HTTP handler returns plain lists. Shiny's tunnel + requires long-poll semantics — a tool call whose response resolves + minutes later (promises + later). mcptools' httpuv `call` would need to + support returning promises (httpuv itself does). + +4. **Process-owning design.** `mcp_server()` blocks (stdio: nanonext + `wait(cv)` loop; http: own `httpuv::startServer` + `service(Inf)`), and + `check_not_interactive()` forbids embedding. Shiny needed the endpoint + *mounted into an existing httpuv app* and driven by an existing event + loop. An exported "give me a JSON-RPC dispatch function" seam + (essentially what shiny's internal `mcpDispatch()` is) would let any + httpuv-based framework (shiny, plumber2, ambiorix) embed mcptools. + +5. **Stdio + event-loop coexistence.** mcptools' stdio loop blocks the + process. Shiny's `R/mcp-stdio.R` shows a dependency-free alternative: + `file("stdin", blocking = FALSE)` polled from a `later` loop (Unix only). + nanonext's `read_stdin()` could do the same non-blockingly if mcptools + exposed it as a pollable rather than a blocking loop. + +## Suggested upstream shape + +```r +# mcptools could export: +dispatch <- mcp_dispatch(tools = ..., resources = ...) # function(body, req) -> list | promise +# so embedders do: +# response <- dispatch(jsonrpc_body) # shiny/plumber mount this +# and mcp_server() becomes a thin stdio/http wrapper around it. +``` + +Plus: `mcp_resource(uri, mime_type, handler, meta = NULL)` and a `meta` +argument on served tools. + +## Status + +Not yet filed upstream — see `QUESTIONS.md` (whether to open these as +issues on posit-dev/mcptools, and whether shiny should eventually delegate +its endpoint to mcptools once the gaps close). diff --git a/mcp/research-notes.md b/mcp/research-notes.md new file mode 100644 index 0000000000..31ede5913d --- /dev/null +++ b/mcp/research-notes.md @@ -0,0 +1,170 @@ +# Shiny × MCP Apps — Research Notes & Proposed Plans + +Date: 2026-07-10. Status: research complete, awaiting plan selection. + +## 1. MCP Apps protocol (SEP-1865, spec 2026-01-26) + +Docs: https://modelcontextprotocol.io/extensions/apps/overview +Spec: https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx +SDK: `@modelcontextprotocol/ext-apps` (MIT, v1.7.4) + +### Architecture +- An MCP server registers a **tool** with `_meta.ui.resourceUri: "ui://..."` and a + **resource** (`mimeType: "text/html;profile=mcp-app"`) whose text/blob is a full HTML5 doc. +- Host fetches the resource via `resources/read` and renders it in a **sandboxed iframe** + (web hosts: double-iframe sandbox-proxy architecture, different origin, raw HTML injected + via `ui/notifications/sandbox-resource-ready`). +- App ↔ host speak **JSON-RPC over postMessage** ("dialect of MCP"): + - App→host requests: `ui/initialize`, `tools/call`, `resources/read`, `ui/open-link`, + `ui/message`, `ui/request-display-mode`, `ui/update-model-context`, `ping`. + - Host→app notifications: `ui/notifications/tool-input[-partial]`, `tool-result`, + `tool-cancelled`, `host-context-changed`; request: `ui/resource-teardown`. + - App→host notifications: `ui/notifications/size-changed`, `notifications/message`, + `ui/notifications/initialized`. +- **No server-initiated push to the app.** All server communication is request/response + routed through the host (`tools/call`, `resources/read`). Push must be emulated + (long-poll via a held `tools/call`). +- Tool `visibility: ["model","app"]` — `["app"]`-only tools are hidden from the model and + callable only by the iframe. Host MUST reject app calls to tools without `"app"`. +- CSP via resource `_meta.ui.csp`: `connectDomains` (fetch/XHR/**WebSocket** — `wss://` + scheme must be declared explicitly), `resourceDomains` (scripts/img/css/fonts), + `frameDomains`, `baseUriDomains`. Default when omitted: no external connections; + `img-src 'self' data:` allowed (data: URIs work). +- Host context: theme, CSS variables, displayMode (inline/fullscreen/pip), + containerDimensions; app reports size via `size-changed`. +- Capability negotiation: client advertises `extensions["io.modelcontextprotocol/ui"]` + with supported mimeTypes in MCP `initialize`. + +### Host-reality caveats (July 2026) +- **claude.ai currently ignores/hardcodes CSP** (anthropics/claude-ai-mcp#40): + `frame-src 'self' blob: data:` hardcoded; `resourceDomains`/`frameDomains` ignored, + `connectDomains` only partially respected. wss:// unverified. ChatGPT, MCPJam, + basic-host honor the spec. ⇒ single-file inlined HTML is mandatory for portability; + direct network from the iframe cannot be relied on today. +- Claude (web + desktop) consumes MCP Apps via **remote custom connectors** + (streamable HTTP); local dev = `cloudflared` tunnel. Testing hosts: `basic-host` + from ext-apps repo (`SERVERS='["http://localhost:3001/mcp"]' npm start`), MCPJam. +- Hosts may require user consent for app-initiated `tools/call`; every tunneled frame is + a loggable JSON-RPC message (auditability by design). + +## 2. Shiny transport seams (from codebase exploration) + +### Client (srcts) +- **`Shiny.createSocket`** (srcts/src/shiny/index.ts:85, consumed shinyapp.ts:194-196) is a + sanctioned override returning a WebSocket-like object. Required surface: `send()`, + `close()`, `readyState` (truthy=open), `binaryType`, settable `onopen/onmessage/onclose`, + optional `allowReconnect`. Frames: JSON strings or ArrayBuffer (binary blob framing in + `makeRequest`, shinyapp.ts:405-470). Shinylive proves this seam (MessagePortWebSocket). +- **HTTP side-channels that bypass the socket** (must be shimmed for sandboxed iframe): + - upload POST `$.ajax` (srcts/src/file/fileProcessor.ts:185-218; url from `uploadInit` RPC) + - DataTables server-side ajax (bindings/output/datatable.ts:88-96 → `session/*/dataobj/*`) + - selectize remote GET (bindings/input/selectInput.ts:171) + - image `src` (bindings/output/image.ts:110-127) — renderPlot/renderImage default to + base64 `data:` URLs already; custom `session/*` srcs exist + - download links (plain href) + - async render dependency fetch via XHR (shiny/render.ts:255) +- Existing: `window.parent.postMessage("disconnected","*")` (shinyapp.ts:307-311); subApp + iframes (`R/server.R:358-382` `addSubApp`, deferred iframes). +- Build: esbuild via `tsx srcts/build/shiny.ts`, entry srcts/src/index.ts → + inst/www/shared/shiny(.min).js; jquery externalized to window.jQuery. + +### Server (R) +- httpuv app built in `HandlerManager$createHttpuvApp()` (R/middleware.R:309-368): + `call` (HTTP), `onWSOpen = wsHandlers$invoke(ws)` (R/middleware.R:364). +- `createAppHandlers()` (R/server.R:134-321): `ws(ws)` handler does + `ShinySession$new(ws)` + `ws$onMessage/onClose` wiring. +- **The R transport contract is duck-typed**: session/handlers use only + `ws$send(msg)`, `ws$close()`, `ws$request`, `ws$onMessage(fn(binary,msg))`, + `ws$onClose(fn)` (R/shiny.R:542, 1378, 999; R/server.R:306-315). A fake ws can be fed + straight to `createAppHandlers(...)$ws(fakeWs)`. `MockShinySession` proves detachment. +- **HTTP handler stack is invokable directly**: `handlers$invoke(req)` with Rook-style req + → `httpResponse`; session sub-paths in `ShinySession$handleRequest` (R/shiny.R:2248-2394): + `file/`, `upload/` (POST, chunked rook.input), `download/`, `dataobj/`. +- **Async-ready**: HTTP path wraps handlers in `hybrid_chain` (R/middleware.R:331-360) — + handlers may return promises; httpuv supports deferred responses ⇒ long-poll works. +- Client→server frames: `{method:"init",data}`, `{method:"update",data}`, + RPC `{method,args,tag,blobs}` (binary signature 0x01020202 + length-prefixed blobs). + Server→client: `{config:{workerId,sessionId,user}}`, `{values},{errors},{inputMessages}, + {custom},{response}` + binary custom messages. +- Message decode: `decodeMessage()` R/server.R:100-127. +- Sessions keyed by 16-hex token in `appsByToken`; side-channel URLs embed token + `?w=workerId`. + +### Prior art +- **Shinylive**: `Shiny.createSocket` override + `MessagePortWebSocket` + HTTP proxying over + MessagePort (`messageporthttp.ts`); uses a Service Worker for asset/HTTP proxying + (not available in MCP Apps sandbox — no allow-same-origin/SW registration for the view). +- **Shiny Server SockJS**: transport historically replaced *outside* shiny core at the + onWSOpen/static-index level. +- **mcptools** (posit-dev): R MCP server/client, stdio + HTTP transports (v0.2.0+), + deployable on Connect. Candidate dependency or reference for JSON-RPC plumbing. + +## 3. Proposed plans + +### Plan A — Direct connect (CSP-based, no tunnel) +ui:// resource = single-file inlined HTML (rendered app page + deps) + small MCP bridge; +declare `csp.connectDomains: ["https://","wss://"]`; shiny.js connects its +normal WebSocket to the app's public origin; all HTTP side-channels hit origin directly +(add CORS headers for sandboxed null-origin; absolute URLs via injected base/URL rewrite). +- \+ Minimal engineering; full fidelity (uploads, DT, downloads); low latency. +- − Requires publicly reachable app; **blocked on claude.ai today** (CSP hardcoding); + per-host variance forever. + +### Plan B — Full postMessage tunnel (the shim; works everywhere) +Client: `Shiny.createSocket` → fake WebSocket over the app bridge; outbound frames batched +into `tools/call` on hidden (`visibility:["app"]`) tools; inbound via long-poll +`tools/call shiny.receive` (R holds promise until flush/timeout ~25s, then app re-polls). +New client-side transport indirection in srcts routes all HTTP side-channels +(upload/dataobj/selectize/download/dependency-XHR) through a fetch-hook → +`shiny.http` tool → R `handlers$invoke(rookReq)` (reuses entire middleware stack). +Downloads → blob URLs; plots stay data: URIs. Hidden tool set (namespaced per app): +`shiny.connect` (→ fake ws + ShinySession, returns session token), +`shiny.send {session, frames[]}`, `shiny.receive {session}` (long-poll), +`shiny.http {session, method, path, headers, body_b64}`, `shiny.close`. +R: minimal MCP endpoint (initialize/tools/list/resources/list/read/tools/call) mounted at +`/mcp` on shiny's own httpuv via handlerManager (streamable HTTP, JSON responses). +ui:// resource = single-file bundle (portable on claude.ai today). +- \+ Host-agnostic (pure postMessage), spec-pure, no public URL beyond the MCP connection, + auditable; same design portable to py-shiny. +- − Most engineering; every interaction round-trips app→host→server (long-poll adds + latency to push); host consent/rate-limiting of tools/call is a risk; large payloads + (base64 plots) may hit host message-size limits (chunking needed). + +### Plan C — Sidecar adapter (zero core changes) +Separate process/package (TS or R) speaking MCP to the host, proxying tunneled traffic to +an **unmodified** Shiny app (real ws + HTTP client against the app), serving a rewritten +index.html (injected shim JS) as the ui:// resource. +- \+ Works with any deployed Shiny app (R or Python) immediately; no core risk. +- − Extra hop/process; session affinity/lifecycle management; not "native"; client shim + JS still needed, and without srcts changes it must monkeypatch ($.ajax/XHR) rather than + use clean seams. + +### Recommendation +Native, phased hybrid: **Plan B as the core**, with the client transport built as a clean +abstraction so **Plan A's direct-connect becomes a feature-detected fast path** later. +- Phase 1 (MVP): R MCP endpoint on httpuv + fake-ws session + bridge JS + fake WebSocket; + single-file ui:// bundle; inputs/outputs/plots/dynamic-UI work. Test against basic-host. +- Phase 2: HTTP side-channel completeness (srcts fetch-hook: uploads, DT/selectize, + downloads, dynamic dependencies), teardown/reconnect semantics, theming + (host CSS vars → bslib), `ui/update-model-context` + `ui/message` session API, + tool-input → session reactive. +- Phase 3: direct-connect fast path (connectDomains + wss detection), stdio transport for + local desktop hosts, display modes, resources-based asset loading. + +### Open decisions (need user input) +1. **Packaging**: inside {shiny} vs companion package (e.g. {shinymcp}) with shiny + exporting the seams (fake-ws session ctor, handlers$invoke access, bridge JS asset)? +2. **First target host**: claude.ai remote connector (streamable HTTP) vs local + Claude Desktop (stdio) vs basic-host-only MVP? +3. **JSON-RPC plumbing**: implement minimal in-repo vs depend on {mcptools}? +4. **Author-facing API**: how apps declare the model-visible tool(s) + (name/description/inputSchema) and consume tool input + push model context + (e.g. `session$mcp$onToolInput()`, `session$mcp$updateModelContext()`). +5. Vendor `@modelcontextprotocol/ext-apps` App class vs hand-rolled minimal bridge + (protocol surface used is small; MIT licensed either way). + +### Security notes +- Tunneled requests bypass network-layer auth; hidden tools must validate the session + token maps to the calling app instance; sessions are unguessable 16-hex tokens. +- Host sees all traffic (by design, auditable). Document that inputs flow through host. +- `shiny.http` must be constrained to the session's own sub-paths + app static assets + (no open proxy). diff --git a/mcp/run-mcp-host.sh b/mcp/run-mcp-host.sh new file mode 100755 index 0000000000..f18fd565ff --- /dev/null +++ b/mcp/run-mcp-host.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Runs the MCP Apps reference host (basic-host from modelcontextprotocol/ext-apps) +# against a local Shiny app's MCP endpoint. +# +# Usage: +# ./run-mcp-host.sh # expects the Shiny app on :7788 +# ./run-mcp-host.sh http://127.0.0.1:9999/mcp +# +# Start the demo Shiny app first (from the repo root): +# Rscript -e 'devtools::load_all(); shiny::runApp("mcp/demo-app", port = 7788)' +# +# Then open: http://localhost:8090/?server=shiny&tool=open_shiny_app&call=true +# +# Requires a prepared clone of https://github.com/modelcontextprotocol/ext-apps +# (see setup notes in README-mcp-host.md). Default location is +# .context/ext-apps; override with EXT_APPS_DIR. +# +# Notes: +# - SANDBOX_PORT must stay 8081: the sandbox URL is hardcoded in the built +# client (examples/basic-host/src/implementation.ts). +# - HOST_PORT defaults to 8090 here because :8080 is often taken locally. +# - serve.ts is plain express; tsx avoids the bun dependency of `npm start`. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +EXT_APPS_DIR="${EXT_APPS_DIR:-}" +if [[ -z "${EXT_APPS_DIR}" ]]; then + for candidate in "${SCRIPT_DIR}/ext-apps" "${SCRIPT_DIR}/../.context/ext-apps"; do + if [[ -d "${candidate}" ]]; then + EXT_APPS_DIR="${candidate}" + break + fi + done +fi +if [[ -z "${EXT_APPS_DIR}" || ! -d "${EXT_APPS_DIR}/examples/basic-host" ]]; then + echo "ext-apps clone not found. Set EXT_APPS_DIR or see README-mcp-host.md for setup." >&2 + exit 1 +fi + +cd "${EXT_APPS_DIR}/examples/basic-host" + +MCP_URL="${1:-http://127.0.0.1:7788/mcp}" + +HOST_PORT="${HOST_PORT:-8090}" \ +SANDBOX_PORT=8081 \ +SERVERS="[\"${MCP_URL}\"]" \ +npx tsx serve.ts diff --git a/mcp/screenshot-e2e-basic-host.png b/mcp/screenshot-e2e-basic-host.png new file mode 100644 index 0000000000000000000000000000000000000000..838180817c616d41784b5ce6bcfadb826683d9cc GIT binary patch literal 49296 zcmce;by!qy*e)`mNIE@2-ny(!G#Ux_*5{*8}e})#ts&u|pca(?U{w7;fhJnJ>krk6B+& zQu3sn*Fm=+M@N@2J3V;awGS7s>8`FUk8WQFe-O#J{TcH+P5GuM=K72N1|{aYOz`m` z=IRtEavO8y6Mudab4`Bn5Hsx$^8cHUFHl{^!eAuNNMoa-zGDWucF;FGJcb-<85`>g zPfEgf5geTCZ5wWr#?0#4x-QhgQq<5Pt*L}k;Kkt2ch7OJUh5-8Bg+v_27^JR{4n>W zG2&xU-*-?Z#{BsIYVQ9o-2ogOSh|-9XErrWR%RxNY9B8@Z(S`PKi@cX!S~M2D?{)^%+eJ9 z`QwtktV>KaeZv6iuv09EW2suQy0laf{@AQv_mAt=H%^8qMr7`r3PKfdB-K|{AxEvRT{OseFzq93{k2ZeGW=R^3x8~_ zmD+C)-oCr%>hylXbLPF1lWg+%uuLpdx&sR@??PwkJY~9pgLR|O6d@v(S-B2nQ_Y#3 zb?$ifyLOj|QI$!*+=CFI8q1+|!#6h23J?qZGfq_f;O-+#)=aly&I!=XC$Zg3LU($boyt&3*VhOBA+IP$!6Z!u+} z{G5L;{pF=s)%&iGEs`%^yr7mFE>ZV9N?U?NGuhV4CD3m~vNr0SB25E~@j3Wht*4vp zSZ#(cyc%gBA7-_8EFHKVzA+ z_glKT%6|TM(_d+`|AG6{=d4DoufW2i7&PbR4|AjyIx7|LI1_e9vr+t0+<+qyn#v$) zj$Ro#j<{p=)!l<&;7RJbu!{ES;*okz{du~3`QemD!%&M&Z;Op6aR`o1iL0@A79GBv(J~lR|g6DjDv_{%)T43j( z2o@RXJ6$G*%vSQ_bDT~^Z)`;O+F(4F|9NF(cXW5Efb#)zQ(gMT-oe4|!L+Ef!hD@t zgL#Y3i5Guplq`2seJyGipj*SKqqfTjsCzI*CZ5F8mASA*)+kQ84WkZ)hTU1(drf-T zMKE2ek7T?qqT@7?(&IaJ^PAc@4eWY@X^@gzU8Cn_`ec;DnOa==mZTaqf#?3Ao#;W$ zT0>sViH6O0NXb;M3dtry;q#MCY{^qRGK=U!wIWSnw^lcIi2`-wcU|JKK`f4%w(}WnPN8Q3 z!WT_>^Sz|jf9k2{%VkuzhIl!8iPzx^!g+g<>N!pPl4~pDE9ucPLi(>S{l4y7T9q6Q z-I_KglMDt0y|Avi=1?T{?)qXr*xPwa%tl+_Phr6D z>&d!_6Oqy4OF_1kML{FqlZ9&S0zTnF2g89J3V~AMNsohV$ML$dRwOk5QTR(x3<`L zQ<_}XSv0@L9aPDDt-oxPV4yYa)qdwJR1|+Er7^W7fj#OYnv|4;Dj$I~rW?%0z>UpF z!A7Mia!iX$G@f|4dq7Gd@RTjvNhOIf9m=RrsvCPVRD?~NzGvG16%>h1KRsI%)NV;`n_^`g$D}oj_mgQI+F+754h!apKmX=#7AbXTc9J< z8SFL@8B?7#rN_(;PCdg>_?lrxjW#_Xo}o&vX~88&Ly560pIrQ@YhlNQB$a!GjECs; z=Bu1cAD5ayChzVlT{h@&@c*?2btlS7n1SQk9DZww$=+$D6 zAMQh`z8XiTG0)%! zVm%@6lOK%r>C*mwj*F=bQD5M&zd2+_lo>5S?XO;}Aw+9*Rzig=M`rk}j7p=+Yc4|w-D4b=Sk(#@S-4p) z{%k92nJK;#k*~%uiMy9KdyR5*4 z#-u|%4`%cT(*v#o^{#>V&%F3Eo1@>|hX7RSJ*l4f-6(f&cf5Rw<^EGXZfNy__cXud=mo5{O|{ zSA&0(A7>5oY5-w^WTfO}|BEjjS;B?riPA|MyFqZpJ zAy$4vj%NS3nOf6Y*s{4I$HQ40?o(cyGu1@ozG(i}5(X`GW2hcawQ=TJ-}{W;;~_Az z(lKn+pVaUxUyM~)Sbw+PUEyFoADvYkCREr9%^lnnd70N=Z`soHn7dG`T<=CYXL~)n z;=RvHta{`e_I2)vzGvg{b{U2%L2WY3M4rw~?i)#deg=az>K=Q~azl2zi1Z6QW%b(l zDSQlv>FpdwB^}?ZE8HnaygWnXI}Yw0R<ayfC@C!xaP`1jDF&VwQ*2atI7MzRZ zoS$b7WETyrLC5mkymjzkUnTtlEVY%*jZ==Ptvx!}Sm#$?g#VL*G7rzn{uli7an4@3 zAtTFMidLyfODxCtnh{v1J#A%={?!7s4}yu=ay1lZniLLGL-++Js(hy}zqIR3QgHRZ zfn{9bQsdr-UR*t+@NZ?RPEI}hq!HACw`yxAdz(#6`*dse%)@*b&YP=xo4l6xr}-mj zXlSxXLKbI?pFDo-d2l99PZ7bFae6M?<4gXH40wueRoOETi&C)kg+; zUf$P7mc}X-C1I}bJ~R!NPmAw}7VF)Mrgd<74`>$N-TU=MK8-nm^;PHS{bKl>+7}pP#=`Fh-Osl)VR2?*!XH6Iiigm zy-8eNIhUP!?kSVsvQV|Dq@3!@UjrNbhjC`&6u&mRg58sul2d>NFp?3&z{u_OyEaCt%JTmNuxNI zm(2l7b@0SBFmPR1t^EC4#R4$5vnjbaCATkMbz=`DeX4qRKGeF-%|C7~nNFf=Y03E3 zq_32C6(Yl*MGR~M5eW=^ElmOcwoQ@?Mv%Cs_~(C9 z>St7Ne+FV z{d1T}!IdU8<8uF}dW%;>5XwBYbNMIs!3N*EtqBVm&d^-|vdFV`SnttLIokniMR0zs_(DIvv(^M*RuMxJhWFbIat5VSl?@F7_j!0H&X#mUN3x|? zId~IP66l$k`B(;M(LGx+DV6zZ9_iD{<7gQl4Z=r{c(;yodhI&;t#}GA7OMUHFY|N@ z#xueyHpVuTiY{knje=sCrcXwTfoLW8t8n{Q?1|a#Go3Q);lYIh{ncr+4ZEhzG1uG{ zv7%J>)$ROf#_kU#3ZB(K=7@+G5H3M#l)06rO!Dpf)CaBajKxkv`jL?x!^N6%Pp0Dz zrhrOB)PMPYpjw#e+@NyrY`RdP@xr#PtVF15UAo$Kn)C@dn@RI4BBEG@Mva}JaXGA% zjXcaIEF)))Xw}au42BazHng~`2I}pnTAMwIZx0Q!eAW?mSp9BRi!YJ$0(;@zd#4&r z8d>%!on#slKAfRm0rTJh>3SFHv$^5VtAq$%zR3#{84@p>K_t0&;DoP!%QN52Q_sVT ziVDs<7PJbf-UiEmYL1T7@VFx(<4Zv?*!r~x=->dD(5BnxM?5b80D0arQlLCE+`9nq z2&;Z=-B#q`{A2t~--CMAg%t*M2G--P&eF$1Q&V9Tc7#uSbk(S-Xe?iL9+btw5=frT z&|c25v=iaoE!1eVexk5CKR?`n5JRJF2a8oRx~DxKXxY49uw33zT`T_l`S`?be|4%9 z`XzC{oioy6Wk>%3xe$6`WxFR*7ZF2m!I@ojc3ka^a~V+ySm?^R8&Cytj;})?@W2#n?YtZ&G6o7 z8{Ihq!h+*e^2xdSZl<8wg{b?PK^urok?kQz#v|H{F&`C^661YTcdU-eC;JKAKw3Vf@YGo&jkW!=q^_6eynAWRa z5J;wsg8rc?uiqcNy=@g0ZcuRZoshf41IWb3Ee zB3;%S+*Sgw#P6r(rSEr;6m}PmIV*ZPTL&ec8kDl~kk?Ph2uVD85&NG92HJ*3`vkum1+R=ydh^ zZQOgKCje12X()c+9Iv#X4C_!xs)eVvDp>JIcC=63=2Z^SZc)@ z@;(Ha`uSdyeATh8#ky;Y_nMBCJV<^QQC~u>Rby3_C>dyE?`meYv>az{mx`P)pr&qsEY7VOqV46II)aUJ zfXu!pp5uFJ#|?{wsaDlq@D~OJ1(`JMHdU9}ODX(-`pcg3JcQgIBFW|?eL2@RiQ~G? z_saSghj?I(_JRIA+*l`C3&nA4zjU8T5-s0Ht~|_=MEm=L9=2~Kyeo}Ww}usM2FzuL zNT&3vxoes%8p@Yg`%Vq>A|sW{X`K08&DUn$FAbSvR*8DNR01NXC3VimpGt+Q61}3b z?#d0{&FF`8{SGr*z2$6HqlJshGc#x(j;3S*=f%eMed^E@A=fF(lA5E>{Gnbud&fX- zJ(w60WcR56j+13g_ft8@*I@RMxVN`0e`kWTZ}+ zZ8~l)6H|J$jmE|?yL^#NOH$YL`+Hnij;CcpSGW(CQD^0^9*MP~0whR)B(DI4Jt*S2 zXjJt`S>2DT=TGLZ(B2*@nV(K_M`=_KnXyVK7OLl%x|rUm&#+22P{4c2l5t*UTh8R- zRTCm$3G~Wi<5@s4FOyy~5B#q8-p}VzUe3|?@f4hE2dT+~+q$!Ii}lInuWXZY!#5X? zc)p`{D}%jE5K&SxGN&fz6dOp+Y4~O5sy=rE@5KT#G%_LK1y|1tbn#Ape-d2dyW59h zY!CzCWMn%aq86wZ(TR)twFuVhVE~8-i^b9%h;EM9DbA+dxQKTBDB9q;EEmaR{K&z< z&BsQH*sNhM#E|OdP|CSKmBtG*8U>#{hwe_<7Wc8)cV+M4+D^Htn2`A5G;PTm8V&}g z`X--_8Rm@(B6B(z#c-s2%d>H(lebSM6o|a5-Ul#MdHfgyg0qD(k?Cv|oA$lw#oJSW zJ%hp#Lai_&XAKG0ZW3z9EC*M*4Di97KrFra1Ae}RiO2H*61D&l@Rj+I$pO32max+&yr>@*_s#nbXb|Z;t zi`T)}7&SM|cuRTbr7f8yl%+4U?*RkXIYfXKM+}lr&&$Ouh?`I$OGr$-KoLHCrwnRa zZ~rpiTq!j;dMJ1KX_vgbyes7#`cI|nKjCcWCwpEtsPMQyuU&c63k>GxA48Ru8yXte z(TOqHs&5?=7a!x}SLV@|(MZmr(JA7@y!7;AU0vIucQAEUk@T3}IMYf*Lvq}ODa*-p zGB0j>q9Y#3{S{4mUR7eb>iqB7i64Ja@*i$Rku5JRc_LMXs)NjGmljqcO3S}F52Jkt zOBUewa*j=DaZSCcNYvGdFe&p|wIiz?!#v92+@rOq{LN-3RV7yj9PZC>tvi}t@L>2S zSH9|%8@+2n&(ddLp7>C2fTYiuaL32|_y;f-ge8kw*NB+vlPNqEs?sbNp3v%sdn<^OgRR z5ivcL+u#I1B~&fBPd;?#DN$=?b6rN`(Wjy|cEN!$q%J)5*=h z^QlH}aDBeyao#JPH=}xto^q`@_Qow5@i{$LFo6(m4#6Fj^eL{6rBnN`O4R(-Q_JC8 zonqOp$2onPMS-CKAt6C_$W@=g=U{r*P(k%IdBHh3l2B-%YL3ffT8=;b-z~iT8I(#z zMO%gjWn+?ms*9oqkVu(-*M74Zd*8CXgH|?f=O=~s<%oxAJ^y7vRskZKer5hIGQD>E z^RLb!6?za59NNFa($&=k0@1|eWaUk_m7U=i;uGiRUVqPG)cTu68KR*9ksBWrB(rV! zaj}g(OXjNOL8P%eNLk|Q#kU^*FS;AX@NYjOyWd{Hd9?#{*QnB@WtDjWnRIfrmzR~j zGQ$ryL~bOsaz;B=^@uIc%^7pX8yY@NP9npt%2dSc$v?X9*zxK^BJgz|xe`fAl5RdQGI~z16U8mehjrGcu2hN_`zV>Id?6}Q_$!7suBhlcJ| z;k6X`(7#Vz-8H7OK$Ffwfkk<>pr+U7iG(&rAeJqz=~79aO2zL?-?t2}8rC9O(#DBO zGBn1#jzP_&fnnHO_H@%%GC7$H7yIw)u4ZCg1PL>x*-wp&(FJlv)lJbcIjblp@-)ow z*N$m9&%U~l=izpR{ypKehvjwouO#FCDjEON$S~%h9G^4=zoO>v!%#G7N|gV#%Vo@= zJJ;RtGZL=z+P9t~D+Wbol`GZuD=L4NW!<`29gN zIAG<49T#nb&G-T;;BO3w(#wN3`tOhYP1;2K00zkT<|%s z3he(@-auBnzW*U4eo#=-I9_Vx-~HKIzus-zV}EtHSQl>C7P!hXR%U`2%#x`**qUvz z`kkAOnbGt9h5gn&WR*?1&P0Rf;cmY$1pz_S*n#i)eyp|8*h^yec~c7ui)pXj-XvZ} zfR|>Sc9;5Nx5g?glo6^#EIL0(gfoT<)DiPWVS?PIJx_Ufc%rRlXJ;2_aqr#x+ko;z zb2cT;2XG?ILfvZH2kT=-Lf7}#$I4}5nB0#SVy~hOfzL6; z?Jx>qpNq5OodtxM&i+!W@09%^E-AN0_RpyX&oFYqaj&9xAtYSm)po2O-}l6^X@zCN zzuY5|PvE4VSDb{q#!eRTnViORm_aOupAa!?Q8|m++1Xu%pD#Ke3t(%W&<)v1*_%ozGsyvth z3xP6SL6UWOAGO=mCKkjNy$M{b^;@5QzWbr$d496rba|m|b$Wa}$xU>AG#{3pp1wGM zegA3rn4|QH9eScxOFLz6c_71iZA5i!9*t&+ZU+Wp8KhpUlc(Qw@$3*HFMn~i+Yg5E zM3DW-S7k()duYQJgpN^<-Rov%-WBCokCn+KaJrwY?7*%g~&@(Q}sNu(5q!)uStls;> z>ahF0$aR2+nhVj^0+~&42m;Zdk;(!+qCSfzXKH99`4dun{X4B{;V0T=UMYOrEFnJc5 z-i&zZyWK{l425D`>_aoFFqQ$Z>K-=fxzq(`@6lr2NROxypY_rXcD*Nb`1treOF{Y8 zC{ARja-5x1M(zCl{T(ePEEG5xZo8>^;DQ(%`ebP8*@f^uoOJCCDyiS;4t>V2R;W?x zeR}Z54?F%;_-MwjhvmciP)?XN6TEXsbL9MOGM_Ul7xk2C0N8%-1go>CV_jr^b`(x; zL5lam7;wBoUAS6%l!^s9))Iv$e3phea{?cCLAC~Jzn{+y6d0w&-@aX+gpUeX)xRa# zHN_L$Q*?84YoDwvr{?nU@hL7YW^koqPv&)Ouc!Oc$f#Z%S7P*AYI$dWzthHuT{v+EqPXRwLoz4>tziA_B;8 z?mvCyw)JlJdW8+r1qAW))5B2@swfxqM7(y#FkavBr!^9CW%nRZs6ZRm6FE*sO z&D|-eTzo|n!=jsD@9O>nfo#y2Vwary$6=vc)7IL(*3{a%5YqH&(2G5v>_ZezQG1Cl z+~xFOqc@0FAw>nV&v$FRQv4Mym7Q0A59F&BsF#rQyA%?fu;|tq7u!l_F_wEXv&P)R z#pNOifqqgxl=Xk`45X^1m6iB?Q>Y4ObryMCsV#kJk!pcjjJmMp#qkn_qbG>04306o zED4(8LWsxaGO;W+m8EbvTs3TglMqDtNcQY*5xqVzP~`y#tRy_Pg;!^8dMwP=@K(sN zd92afGm+bdsh`LOtkjhM-5S*E-SSR3ETo);|dTE zG!JTOYYCaPRG@3;htsUo?9sR|)7}jjwak=DVsHn2Nwb$=W(6}VO??rl!W3|Dm%sMr zneSESc%s7G-&C0}(cHssoWk!ak4eyUs2$;lkQ-iWMb#AtAl;a3$LjkGJfZ#?U*ZKX z(yFxFm}=0rl9}>6+wLg;a|BW;4{bj(8xHQ`ohMGIjTnpaCT5I}8PY=CL*y;ldETSg zpKdYD$AFA~9-w@mN8#%fs1;S*`@?NJ;WqQn_1y+lklds88=(svIL&sA$JyG|w((!$ zYieF2IGBqT1?q#C3O@0Gys^O@lM`*3Ibl}pGE%6y8%ik3%F61ju9>2iu)W1eNlCfr z0uBI^?LLV1#Uyqgc@Pa;D8m{ylSHD6_b1O~rx<3^xKcwF4m=)Q3IN!1v$(qirEzMZdv zrr?;^tBXweF_0)+-{JAEonw}a1RQd=eZI!NE*qtKoKXuLp!%6!jjsxs3UKoPg)U5Ex1^xg$B(x%Qab)CN zEp1Y%lp&#|E%XUko2JcskPrbFNhAUe|JQyTZoPO2`Q`yaS|MLKG4kYKV{K{4OfO3I zXv%XFSQ0ZkJ3ANG{@%(Ee(F~cO{dc2llc?`_oM1!nK)KKhOV|AGt`U1BIR{J*&KR+ zRMxveubizhrMYx=ygT0!#>48eHX=8P#oBaMR(syZzX?KLv(A)&{aovZ>sUQjr-z%Y zT(TG>kQR>U4_IM#UjH*tc8&UFB5huO0vvvNy4fUb`J0Zu&_ZxJ3t@elr<^l2G)Dh+ zZKS9`CC_2?H@%G#e%jlS1THJ!h&^86#1_M#fp*C%2u78a1B_hFa}ppQToO*j!w+v4 z0NA_O8&Vjb)3$5ivKlEQ;j;Yv`SVR2oJ5|;(H)SluQn9F{)D6xo__(0x&@<`;9x^Qg5Q`X7N8)W)Qo>_s}$kI@6MNfqr-H zWtaeL>^2Jv3o*a9w>Pz)G_!oZWwrOPhto})38az@1b9P%&h%JHcoULa+8pX`-- zG?dX%cYnmfnL4GD%q|2%2M4f@o=(@8y|}3bbm+ z3V#{fJTuo8RO^9hi2p(Qb*8|8mzgPn5k?(ERCBLOmSzZqZdTnosxMp_0~+a~Ujhjk zv9YnI;Q8av!f2_e-ae3ikPUV@3liPE7$N112I!H9RS&fCu_UvcQV+pJAIwbDIszno z`}Xbd!|)(%5Gy`>T7gK_jQpS+8`JKj>m&JB3wVCT5_G%do-@&nUiDpH+lgZ~qnv7^ z|4SrlBN9JIeEF}v`>Kk6>BhA`|B(O3pHOW7i$4GV7u03U0oQRSDK?zwo7iNjJf+VZ;mZ zY=zXRG7}k#&9QQ`)^Cr1XI?HQ+NoSf%gLRiA{8>(-u-ipw|)T;+YgYuWEeScr>pYf zJJ1JXcmlGtx#n8BKRJWa_f}x=z!TXWP@O!}UgaQtfav067y!M-Uk3L zQc+Rutq!jpFQvLVIn}#tjC*c293D>lBCx^1djJarNr!Rc&mRr?X<(rGW%lK!y?X8o zgucF)0K9j_;iEE{2jsiMc7DTzvk2(n))O`MAQqk$*;94%UAq5Z(O%>d0Dj_*yYTQrWOA z8r%Sl#oo`YMc=-CQxHD?jYOUX(5A!*xR)6hVdIkA#KyijK-w8~ghnf>mm0PK-1bb^ zXQIEKm5ohlaPp@gj_=W|KR9o{m5S@YVJpS&7?qutG+i)k^d zq5BBK(A+G9xTQT{*IJsJjZeFy8D+v+5g>_ZknH^K82aMxkN1p^lZvW!hj@N|-ULM> zm*D2%0dZFH;B#7jJ}>pdYxWC~4`6cvHCLkoEkf?G@g?q3(AZFqz_?US@_vkC1K@ublCz-To&~6K zL=@ddPKpO4MP9FvO4i--YQncfrf!Mm;pXo#OaPzhO$OFhuESVSu>ZNBpkPEwUOwhU zN+ui}UTa5(9T*z8IP@E^X62QLL3-Uv%i+v9qNh)DH>iIO3a9|XMk%?R0T`xw!ux&a zs0B}0YFjbT2apb{>BjSCVfy(&^v3f8a zhM%gdfw23mIyGq^nqN!1)(ID(bLO@A^oD*;#mI#rw6z89yNj?pmG(M1Iz0-^ zNGTze6-vddR91#CVAe4mAnquC-5APIXvZ4CPm5Q>ixMeFKJ_?1ab_Na5G$I@wFW%K zzfDaCaI#ZdAmNTy=5A-i%YVHQo)=720a$7%x!}pnPd|V>qP?=H87Y$=Jh%+X21n*I z^ARUAC3{eTESd~#9YY>2gzX22Lt1f#fF%Qrz1W}HDmQe-TPt`^d#3r1b-eIQBh z{ubV00T=_2H1aNrHf^RGb?g!>EuE_OpS3=Q&I_EXk#v@V25ethSAlg6$3xL?- zPI|{0e3%mSgc){|j<5+t3Td@7pdMs>J_49QI#U1u*0(?P8a$*$hfb(}OOq5rv$_Ek zi5|;*Fs_-w;C=UP5!?G2k$?nJZtHNiUJGWBV(-F0)~JV+sHO~-&Qw+8+;^iga z@mT^#TP=82hxA;jZ}Zvwk#`9h>OlzKVX|vFuZnuHK-d6W9&Fduw_S?Yo_;F%Iwla7 z?(!fLmx@Gs4+cr*4bTku_Dyj`oYyg|%NQm;4pMhr0hDQM zY)nZ>Q7Zs7dngp9@`ywJ5vAvsFJEq9V{4^EC)^^2RK>o$fBSalA`8a!!sTGFD7hCI z^SiWv^Ef(i;%2je;NP#s6yN^=U$yN9`>R}iruW=89xDNN$p`x1^vVCO68Y z!@XaX=iik(&fZ}dMRz~1DVn(C+qwrr$GejMOEEomNexKmcO@70sRzb8DCD@<1H2F; zb!AFN#_D-=4Gbtzrrva`t4G4M;=kK=e7Anj!Zg+O^WAVpxIb`4F7Fekjn6iIKQUzd&PNzN22X4@UHWXz{5%r{zVkeB zXEsX7)%7rjSzBnk_3^l&sOTpGPI9-I>p)HLC-+zeirU>{+D_!c+B5Y}FC$R{nJNp0 zS((|#HT==Lu1)U+DJiL$jlx9rq(O|;j|Z~P##p%|oN4PFH!zVQf%jO95Uq=~VH0ASEv3xXyH4sgn^f#T@|gT!0b^;!H<-dwXlEo2REtPFPqN zH`lEz1L@2b0HwnN$r+S!W2z7E6#xxI8)1XfNWpwH=EZH_rj!tQDM2^-MTv^CqVk_#y}~0h@k7j| zD{*w$SFa#J&x68>!}T%cbkSR1&Xn1HbRPPx!uk0H&fC&)JBnq(R!oz(771J|Xom8v z?Az*f*bnGX(LmJbjpvXg0X_r-%Lx5c2Gx8r0XIbtkPV*OT)9ZN_pwW?lHbpFwiw(1 zuxBi5nRw6>ZvgfPcl!6xs-f5&!CEfO6T3a<)G~z5-Y2_a;yPqju{+}~s}k+xU+SSv zKIcHJx(_(1IcJsmz;}>@_4M?Vvt@yuh5W{%1*wr0Bej+FgBlo94xz+uy+3sjj7pQ07)N6U4KD$*gmt`2 zb1?GhIOr&3Sw~j0KG$s@BFNHunod6ui9Z%cQR-xZJqa0mNZHKR*Cv z5;SLGziHGtSqKX^0m}iNGLo-)RTicDY<=hRV!%q?!|_xw7oA#%ENB)4^sLul6?vUR zGpY*#dj>5vU@92P_;B{_fjM{5X*|G%X)|yjgabN?h-P%{;LMHaH8vWf77)}38!QERq z9$}zlCiX%(*y8T3fH!%cw`6>Tgt}>jgoJVwQsrf2II@)KUXhWJ)z{Ypz=atx{7njW zGmo!8*`|Y`*WHil@7N}Salhsu-bS-3DUG!P`q2F49>`6`&7UNMf`0sXrLRBDZqkh@ z)Xp^R*czS?7lhgI$EGP>BepdabrplO)8mv&yMQk#qv@C*G7wNfn{e^)Vl|!ucnF?( z=lUOP?NBFJmF|bFX>*13ln&?1F{STm0wnjbEjlw=Mal2=83F4r(QANUX!M6@z;Fhn z2}19(bxhiy%o=>?>byJ_!$Mhn93M?3+`3?hB7rgsV{gq!n{#?tP(8x(-^8AIq^Ls!{*-S zvW%vtCN)y3hfhRCOY~WlzJLCY;cv{gcI0=k@Oz;w@m-0T-^+FzE9T4xs@x5s)2pxP zt|jHMRmoMPeDPuh5Lm=5@Zez;1Pd}*sDM_?F zc{4@K`SY*_kHhYo*nv2g{qE>N6UdUe>QtEf@t}!&&q`dtodDs>vt1jU9*-U-H4`>d zQ_1hW0*~zF*>&H_FJ+H9q^aEI=;Mum!5lzM2k5y|E**G6MJGg?RXfT?6i3;=(k_k6xj7i4HWx) zL8AA^rsOv2Dmqv41;`ys*hI-m7tU7rcuIILi%P3?qub&%g>|18nc7qF&lT$d#)d#J zo{lC;e*k69Kmlw}0CDjHRJq!A@}#N&6@V%=?t<}74pgy$)6RFea4I_oD%mAa>?U1G znA&>`RY#0Ww^z%aa;)(@2B%iTYkcT>1kMO*gI7%{DF0?Qwgy1#U_d#G8d7x^ z&bCpA?I;t%zw;ToR{+?1PROQaFVv5f(?W`yOyCbmn1I{Fz7#%FxSUJ8Sf*0sMAh@Ez8Krz$lcj zo@!N?&;H*6;{DqAxRk{1nFmxC(t?Wok}4#bZ!nMB5`0pY*hu_6O{0)fh|c$9GX)uZ zFspgzIwr_)zq+Z9i?A>l(1~Eu6cEAu)wP}e=FeW0o6}QKp@2;K=FOYIMgY>j;*tXX)g47|^y;ZfA2<%;Sy?_1 zI$nqeg7|9(cr2*ffa(py5)fu6e9x3X%D3p~=m1q-G^#7o!EI;U$jGR&4S)tKeETh@@4BL1jCb z15OPv$T7gYm2K+!-l`9vhV6_c_1~GnS40q%r@Riv+&C2;U53Es#|OF@j-SsDO3R)A z?W>$Oo9YSgH9Nb_X`j;#&`D6{L26>ms})cNR3@F8_XgY@QK*A9BK^)&Zh+)LHqvS+ zPzxH{yExrMNX`IY+T`nd$6w#)IEyTuEQibn@NdW^Z^|o!PjBa}AJAD?c7{{Jx{d#= z4CTm#kwtrvIjC5y6pomtzRi=4r0Mdv+Bel|7_JJ*yEsiZ16%c=AWX#P9cm-GUxwU- ztUw&2OTdA>#q{q!gbWvhXSB2%+p0j_7Eo(Efvpe5Uy1a+lopbr{20`Wnb^_*BHQ_* zG1zvGwO$d_Xn=xwETIS7oh)Q=W#xFr53g9SL2LZcqeu9+K<&@M;__sz1o{$I@vF|+ zD(^9*i00HttI>E&9TE$zzkB=kuh1euKX#ae&-aFa>RZm6mKn8_;#mxeodCv0L947a z5!I!DEdxSc5K|1o*ch4eU9}c}yjWN0-DrSK!h1UvHV?9-0I}Eq1 zjO%3snv*B0GopjSS7++F^xHBxS^6Gg0HQMulriHrGI1hMxV4?EI|nKO?0Dg2cz%Yl zjJu5M`X4rrJ@bM}u=~v@;2exxs(Hrw_k|?&=Hw7i$qgz?9W_aAjqT6C<;&%dpd#)*rQb{kq^sUoQnCYd0pSv}qd@T=6eXf^Ba;oY*I8Ke)l2lCt&!auVt9fT zCWt3C(XI0Ce8dwDHZH}xQL*cbi!?u>>_`yRI4)$h8iyG?3)`c#a)E@H_;#8Af*;LuG^s@p&EnfP_&%jgfFyJD>=G{497J zs8giH6@3q%9*A@giHL|OD16ZqyhWdu78a;0Uj}>{%yY2aUF_8wmJd~9&>DOVf?9?| z2$it0??Y)t3Q&InM_njRP*4qY=s+kdOq_RTT~bXt8a9TBd#c5SQ>q1R)}i$Ke7yJp zEEg9S(5ifuJQy$w8JizKDHHVAs{u?M)EZvCd|9sf8wO2$s~oM@7})`oP|%Gcoz>w? zpWLMwV^#UVNfJ~yqEjCqr!8RNK6p^&!BI4|YF$RcG4F4S1tL$1DC2Oq(U?@BKcB)PUk&ZDz_cPdh;lwS|y7y&$H zHIy638PoQM9?7*oR4vc4`-uA0*Y2AenU#(uUzr2v5PtEfMaOXy!E0?7z16}j^%1vN zZkY&L1U704yk7+S&>xUsklg5_q&o4`;BXDG8Ykky|Dk8+QfuKvARq!Y62hi zBbJ8G|B~A!HLTy(q?#vp=1lOqtB&Sb5%G^M@6M47p6@%Q9x~BO=rZ;s*c)F@AX!oOEo}ladaoG>%!r%E)+9JJr#CTUu^j)zU`;>4KH| zW2Mfj`dvP;1dB;6kr(|urO{GRqi2;4V_2}E+O(yf-yJ`My4awG-+h2)M=A-RlUU~6 z$VXeZlpwi@`00PN0RBBtE3d=w^MK01F|JK&7 zN*f%8(H1^<*#1{Ntq`*j=})YY@vS`K8D~c1!ENmsf$) zPg4yI@ZCjUsAy@O`>S_>ZB3Bf8C+%i_4WFpsb9b9^e8TzxLf|1JQ6i^KtKTKre`|3 zUBR;}pl>ZKET-2Gm=46l6%|sQ*HjNgE$*!hKBD>ZsE|6$>$xcspldE&JMei!|!_(o1v!;^LwBi_-pOjoC-XW!b=J&m_GbDUSwidn9Oi zq@TOhXtX609=R+_{5+D+Wcrh$xZKGsKweppKcu6&cmRC*G_~WAd7W77gVx6=eX`0y zAsB>)G#E_gnl;Pc33VX=GvAEfy!Y3E%FcEI_qEZCnr$kc4r$uC^mttF_d{`W=26)_6DSDXF|F7 z!A7?#h!vsnm;yU&-kz798J_EkeE^$~1iSamby;`-bLxLKlL5?~I|G04lu+G*Qf%eaI+nMtVpd z*fK$j41sc{*2>|*m5kQ1s&ZVxy$PpzhXO;Gs?JaQjvl;A5aq9v!^6X=Q+vOC!_sj! zC_N2F222MdYR=std#3}s3?>lceT9OolqPAuIW>vI?a(-QK+%4^?BDo115`7UAY$t#i{(teSGlL0RokIv#AbgfOX9 z=!RnnWq#i)0|Q56Z74m!%bP)42YNf$ro$8LD)4;y=fTum9;Y3D5Hi}2KdTRB$mV7v zWlgiyT;`gHC~iWLaQot|{s`8RiH?E`+K=ddTu>C{N5-W2G<-KWK8T||@k}`6SaJ*@ zc_FO*QdQq$TFt_@^-ZA@wOJf6JHLj^aX`K@{gb1)tbG(OIoVt+xZ|9a@Xxh})E+9T zhD@?$o}{cnvdmqaM7BM%0>&bzF|3b9Zf91}+pVcGRo|c>W0{j%3=rX@t>miGLIo4l z_^?lrQ}N-(@O#uRS#BuAh^U)hpgd}DhSN>%>zNohmo0W66>WZw8QjDw^Z&eyfA3yN2 zD_#4gl?z??vgExBq2lf?a>(c(SB+P{X*FH7omOBJ4Q1FeNSUE%hpxa6oJz-hnva+z z-sg&}(pV2?Ba+OmmB6f~V=INA$1RKel9Q7|?j=yONj*hZAh%1YXv#MvFK75XP@RM> z)~2KB$JzK32WlhF7%GsfQwp)DJ=4gQSCtzM@Q(VNg$ST8REh@MAOanHO?C*E%CHZ2 z>DAV(#EVZr_|mGIIflmD?>5BZ4u45MxJ!uBLoOolyYf)@X$^l)#Ye4E)SSwvW2Eu| z4Gzl0O#Rf@|KJOAMh^NjJWhnGc=@tMZl9^zZ&#a|p)E7`(UbU=T}m=F@Tr1qUdYEY zK@p=I{laoy11i&9rfK_~M|sqLqWDbtpzdlFq)$&zpSYHj`}^&U`vZCtauOM$LPA1X z&6@hiOcb*CH3 zd}PPK#3ae37PLQC>e`8ooIEBTY;yFJISDd(o40Pw>Bw}MpB@;ro1ZrHx|CItaKTG7 zE3-e0QaJaX0M%W08pn{prZEG1k>PWP9>_3%l@X>KbIet4r+**bW9+!-AaWy>sak)x zv97#HgUz~{wU6ynQMX+Ns{A9#012DP zo|8jF$N6@%*KSZP8@JO1s6hO$Y@S2cZ4=Z^U^vnNZEYw{d0plvg}Vm$j;Ygqq@S&= zODJlk5l;@DH5F=&>bEg~%4k{}idVDmRs@n>6MN;#l}64qe>$NcYwoeJrT%aoXj{E- zMryVM(sezN+7cSmp6x1qt^4s~24ZuX18}#R*hhA&Ge9HkZ8n57a^~lUvM+>iC`szY z{mvie*MH{=z#Ig8A;K#H=5R+rc3%Jrf}g}Q-pfh5mG1atZnHM6$c;$^LK}$R4^`VL z8wX#q>wUX9Rl0hUvU`pYm65fGLxt9XG9U}e_Sx5tctR&t=|A0YRgE3By!LRWvYzPm z0pE+7iP!9M6Z$tcBZ>m2kSmh(AV(VyY{{Z6$AmzMT&2e@YPTw*V$oc!FJGOdEMXzL zs&>Z&P<(=nFt<|Vug8e6TuWzGhz=Ny0K&E0^MJ)kRv?rxY3=(RummFWdG_8dy2T8oCGxwAL)1rV&3b zL@5_ET}&yTyCZZaf^!b49AvVi6;AbODT2%0n|Kr(Cm zF(#DvBHGcig>hkzm7ve;CiD2a1;7 zkc%T;IRdYEJ_5q_$2dyLf(uafu~3x$9!^6BDV5xyTpo!-0cW~Q zWIH~TmXwqPRK2d?LsIw4k-qq1;QSES)h1W2C7Zrv!R5Xxp5Sbg~0B1_BdDaOXAMUq&FUPYp_+4=ad?@S5JkI`U zZmnqH0N_(KpXeD+oca1LFdf9X64~Qp#KKxRACW4K_PKHJrj(nY2RL;~^4F5J@DqJ0!{xAN z8fxi3&L`4d$>fBN{V_#l?b{hbTvNGQ##k+*cUP#z@e@UyWVcGb9U;*;|D1^JENsXJ zIV%L7Y;4l|&`5T5b%BuZ_xC4hvnF-ycWr`9Q4C%mNGbsG3kwO+_(?<9iK=VIKE4z* zIi%mzEq~6I6nnz%Y2Pa-z}Kx?C#!OP?Ufrh=AKCTKwp~f(0x;lfD3MQUeWt~83GV{ zXtyDcy{-s37^K|FB~Es$i*hM5EwVb~pqd4;9@H9e_GDe#lKBJ?f{iO8`4Eo@ngSM8$@V?s5!?Sc4?!OFBMzLLm3MTY!ac)XLQPA%0O52L z981TK&wWn4fIX+8iCD9n3@g)Dd5~e z;J7c;6cpTQkoE>ACd#1e!x{nr7YF{%0s8{P!l0s(h*u+9F;u%<-`QCL73%}hUzebT z($jlVt~)t72|YJvP+uf|>DEeCn%5A2%n)hO1|=-mk{n1bVKS}%Zd?`~BFQ{D!zQ@K z4{!v&{xO}sdOJJGNJ_S(`#%9${`VpUxmbKdL|E7WFqR&PUgFW*YR|?UvaZ`N<^sX0 z9|Unho3%7GtHTbr!%=`(UfYmABt zl|LPwW`b-WD!lpmdBeozBhXMeCZ;c}!*d(i;BcS~H zD?wplg#pXJEc5VZgdENEvuqpW*4Wb_*!7iBoV7QA zZP5$cb96#^aN}KY0vWY*!RD*>cGW5JWxo`;T!Y9G<9@z<_ilI25D&Q9lfjSn7TJz< zZIh7<5lcu+;^P`y1}Mfw_8a&20?8dtLOAAqA3Q**;G9#3z(cSZc)|?Vl^JchFMLcc z)wbXa52B#8cS>CQ*qJz+FbV@;_}1H-zy&c`lHHdKot1*`F@&5(o%i?&q2mP{H?6E} zRLMryQ+?`IX3>(6xMi4paZ`clR^k>73@n=|j85-^$OGFlE6s$R_%2zi3-W_h^q2~FxGJ>#r{x~kL4rmH&*H2m{~P8@Bz`h7T;l^ep(itMNgu8-x&>iPmq7DM z_@?bh8D;MUKiud7F{HnR31*e1G+&3MBl3a@8y&dtB(@M)+uQ&#!pa^m$Ds4ShsI`h ztmDIo)01IALC6Y}R8-8{5Pm_+qS=A|iF6Q=AIRO&B>^@0y1cZ21&@x3@|A{0#SI5| zXTyh2^E{35Y7uIWD~eJZXXp9aY0J4Ecy8b{MhPI8;AIXIBKvk zjw1RaQ4YkQW<{5nh_kR7o?isTI?$X|P`K!zf;Jx#VoC@b!@}5npi^aJB-HU}QAoz) zTPxKc$-la9rrO7MwH~Ht$e=nyvlWeDp9Xh~1_es{&#kSkSNWu+rT2rB{yj7FCv?oy zY)X8b4^IzTl#A$WV8T7DkrNQp!SV)S0OyHhGeMI8@r(f^>S*tCfcU77!n2rKwzAy* z^nw#up(n(CdF9$~%-{m1MNePt;I5wPYXXuB<9-B1&g zQTki{sefYxuc5q=bCaxb)6m!$J=zlDVjk-rd`5)<@1hGx)k4rp8|0xqtOMo>whMYq zLY#`SL&s%GD)f}Hxh525kgyVDqSV=+mII^%aH;B}#Et2`Dm;>H`$aCTjROn=8OZLg z80T>zV`Jmc>#(k9Bgi7@8*dH+bNMnnycu-_!B`O&K}OTUJ9c_iWKd_8QL-BiKImGN zazKo((^c%qw2g%OPd=0@HR_;pf-J5#S>d4#LJQFG11D_nkB||I(vsh?E@v^y^E|l| z&_uu(A$hT}-FQF~)iYCQqhgO+_o9*Jg$oULNAl%BI{ck89`^4}yb>$9d=aoK;CUwz z)sxRgCfUIKmku%?i3E%Ln8@U09fW@!0M(0=jp~LS1Dn9(@FA+lu zyr|d(uC;vzAs`@N55aF1L0|%zWrEfDdtJ28u7fbTl)*fVhSql<|5L!gq&*kFK7C#9 zH@*q~8oFuJJHjVUXcyQRqWi$bk)(jPMmh2D6l2AfAmW9Fz{aZb;~5%aB_v{}k5OQj z!40fB+!PH1@x*)xvOdz0vHV&VeQXB`4|{(%b1$U6;uI+R?E1j3UqElMy;l z!hQ+CNkKL|o}^!~n!vvG_49-KY7q_`EiJ9u=+z@wNsIH*edF7#>lFgAZSWZfL33=eRN;DV*RscD4mN1?hPO*~*w>@#MF5^=P_?j@8Au+*p% z+JYGl;;JQLD&bRXex`nXdC@U-o9U->Go!87p>SSZsB4I}^XiN^&;wu6FGF&e7>!8; zs5G%%NY9w~`^ai=k%l${C)i9T47%{>xgUK&}JP4YY}hO#$Urgupco zKsKxGy5TiIIBd%OTT-Nx_!TKDMO{JcuK z1~I3!XMga7E{qz#(He(ZyeusIHQaPz&0NOfR`=;x#_J5!pzB4TG5Ycxj|UqpG##Nk z1fyYz;)7U&<%5S=r)HXHv(+Y)3a#zBoz^l2C}HTq3i#%0&_|#WSEk*%V~0+e>&;I| zXQ6mvPs0;Pv^gi)1MN2Io4xz?aXqZBs7M6k0AMFgvmomt1F?RMRR{XDT<$Cm=cyH1 zyLKC`Z%KW9g6F2DW(OWB6d8wiErNoRIdIb!2?9c*Ko#YV3qtw!V;VGsBL%g1&;~qr zWE32Nrx>9id*~vuRAgJQF9pq8Cac(EVaAtj|MV#v!0<|aj+~qv&Pyb^jaAO^8FnRb+i$S&Ec_h#j*%0)UL%ZLu2qP*fTes2+3jcAT&XIe zJAixX1f*A_!@sD8r%hP=N@lxgPuQkV&-C{8qGV+k<=O+ouP~G#auL``Hum-~M&Za{ z%)~g&^2e-f-i1@`;C_G>QVES z7l(cY^%|fwQZcr*&FQBHtAJdy+=rqBk2Xr|=5N$@=c0}?jsg6%0YyX1(a7V{$QdN4 zJT6q@eCQY$M~^N4x0hmw+xhJ2|<67sL19lu$Bqc1+41 zo|&D+)vj7J%ZPXh6%fQXDn;2>(R=}1wQ=0`6`UVfS%x8KoNi`a%Fq^dbb%4$*ltqF zcqK;t#cK%3gcpupMEQio#1g3XfE(8vCFVawrGE8lil?W{?09EwzI&i#tUwbZv9n$& z;}HYj{0L2dwG#qHzz2l+9MlD=ntNdyL>3c(t?7r$J)#^!XxXrxZZ-0+gvQ>sf;mm+ z=1&!DngmG<3w&&It^V;zh#~UmhOtlJHX4F>>7UyH4ZSNO7X1m#FSO=y_`R@j@bWH< zWkF^N6Fp}1;RPKXaZ$QqvA2&hGJXYHLg@W7GBOITm)}`GJkCh^xGM=GVu{c@l+HAs zAq76&wAX?>OW@%M(3#L{wLz(OQ1w{^>8<warp#^i)+A-dg7QXt;g2ku^?d+Qi z_N%3w9Lm{`v8#O~LwA3>mNW*LVHl^K-D=I{%2=dUNyhC5`G*bY(Nrf@L8V5|R204&!f zVtqZ2V5~$UZQXbbdF2LF(Ri-Wm>Yp0dDF#(Wg8niJ769hITgSgftOOqdbA7C*wm_xpbd#E0C1og&b!twVBLFqE#oa`1Zl^#Ws#n~q;Q`!<~tv0 z))MLQd_=1XLx{MV8k)nVCY8$}3WRkBy)+t0F0z;J(QFTB4y}3cidX)?le4sbRbJRR z)JAA$ZsI(_Bi)&yQ-(@fNLZNG?;T_k6+U}rLF}%1Rq}nXccAZSICBO~o_3&G`p{_^t<95%BiM5{U!K7_7@>;-{|5iov# zIZl`y^&#kGVfhRXSJTz)L4~!rxX9an5P5))@AK1RTwL-@P(0vk!4Qqc3M`%oD1KgE zfxiM6PZ1MIuH|__ae$WmNOp;7a`v!hp83NN8d55!HYb1@@MoE|Bu5*a@r&&Q_*eGh=B+i+zjB_^)^mRoBRXFU9B&|lwi zm$;S*@`WHuiyg1;&fiNqft>^rge*OhbZiz<1%gcj8Kz2Hh3hVRXkE_ zddBKPUe^BrS^ZU6)o^kl*{1IKIhtscFQ_*VhlwulNttcChku^o6HjEzgAMe9~AgO{Ra!jVBIA&TK@K%g8jqGU~_<O89XlE|XuyMSV9 z&rEc8>mKDGTYtN}ysGxX(7n6yT1#Hr@MgPVHt6aqE&ZH+nS_AMKzw1tl1D`Sx`#$**fNe{TEjb5aHo1jjQ;uXnl>1+mwI z2Wo{o&lC_y*!r!vDdvsP9Gr2}92@L=GV|5xMhX#V$tl+|PS?VOvO~&wJ}fnEhOxKp zWa1HGk34?GK*1zl;JC17iaT|N@yKGiP3jA7Af_)r!Q1t6a~P zlyAhh5AF$~^`JA4eZn*0N5?-r>IZ5jT=4*>y&GwY9m5`kw%wa=LwnZs(mFn*jfJZ4 z<;xJr%b+?zAtkVP>(f`l&f~?GYvSYuqn-p4_jPMgANhdLr9k@wyyw@{R3KkORFn%q z8i1pIG{>a%;2Yu7dmm6SVRW z!;N-s;?^$au#-xw16&7zmwf+WPQ81v9qG2r%T6!K%NY;zOAVc}olKphWi0%C->+(O zp;L)mL$hU+c+lR|@Ode{jA+HP-px%iQI9CnGMXdzIxl^2WmhZdIL>fnG%McB-BqkN zp`|h*g7)`sox~6pt&*;nBjwYEm#V~X%HAh;;J6%dWOq>!u^SoZOfQ|Yq||>-5eB^% zc@V-9y{Ho(Lyx$O9ZGgo5gzx9e(xHCLL1b7-f##@D=K7y^zDzspeyZ{HfM+K@vyd* zmpAkbrp%NZD4ac(bfU1uwaPLsIEdo==y;s%n}`qwJIhmXg|Pj3g&{qLLg`Tk%Y(Hb9YC|Z^7I=Jh+ErhVtQ=;uDs#!L5OK zI%JiP7^53m*M2>$yfsSPZ5cH0n>TM*)vI>6{{v_r`2K!o1M$0~6t^ec05_T(h4qA! zQ_kBR{@B~MZ=XB&OK5d)XCE6yTl?D?U?UZcq#Rto=8qILx*8nc?-D^$=o^dz?oFDZ z>Gb9g?0W%GCr0AF%XQ>%W*PtE!$zeS>Ak(YrlzNrUtCBX>gX^p^QK>~iGgRy$^J%D zUl_&o7Q!MT=IT%F2*n76HR?R3^t~9eSWSbyk7Wcr$aXe zGRc;oOGiXS;pXzz-W;tICMTIoNZgLRzSjW|)LY;u^Sko&K}c-h-XTuu@J?|vv1o%K zC4cU_m{o4fAFBCbZVX{a_%Il z68Oi56aPEued3Sa`4(MvqU6<>*?`q}%-}{aLx9PNVayJvY;9){EIK+m0B|Fi?Hcu| zG9b!!j5dH2o^y|B_mKQ!OGX3(_(H2fxA{Rb>95vn4 z&XJSg#GA1@fI{{_olCxb`>*L~oaH7|v=K+&*MThFK}-eVrkgI42Dt=IwcyUpzz+v# zX@!9efFB0mD^;#tsWUb`;jNyxa&ASl5C=gW6mOZYHW98zpC5{@U8^3fX;@1-k)7k61&Q|=}hg(@={rqGAs!!^C~a6 zQNr{?p$iu83no6z*K|TV_Dol2u0PijO$#w5)8#Gpoh6nK)dqEd&^a2ZQW`;vC=vN< zlK?z`eMe>K8TXwrKo_R++e?lBuQBYQU|Z;tBc=iMS);@uw`YM%Zu#+rG}Xh`2*n(@ zMZEXobXz{gBc+`7qHM&cp<+m@4w{`^0Ycat76YR0bM#8x{NWn2CVHWFC-bKvQEqFLfabgy-t7^isjL}aZahO)h zodAUN*SyCbBIv}mSFX%LMtu`VL*otb6MYkbm?9Q|TG)Ux4 zM0kMJ}Kzy4_YvLiWXAqX6&WY6*l> z67$-KSq=j+C`p{0oVZ$|(JITGl`HqhjD{PKl0i^4`|~G?{tfG|I9G6IXvv>F3n#h` zYrPlWjqGVH#pZrVJ`){6+ zTjxme*Fz3Nt*Q(#Sf@{rsE70SfXWqRV_``tl4 zaYEhncruXA4nZIxAp!6Psy?ixW3kJ87Tzu%`S$9v*Gszbh!Qu8RwZV-a zUShz<`5r?NuDX(Q_F}gx>_gp|ekrr}TCCKD@clHZw5QvZXj`)YuVc6M0Vt@_1~MWI z85$BgFTB_&NijTWDUTTtwiTicOrhjtx16i~Sek{}-d9yMR8+_<7Zer(FPn~H$;4>S zc`OAns!^-x7vdjlot*n+=zKtpLOOA<$`l6%XfvRo>zHZBTPN6*Jd`d?@Rtg?(`g#jwp(bOW;YXp6b;L!&}TMxPq zh)+>L0nOHXzRWep!9;{sC-|b#tqiIPNm|dhapNg}dj$pg%tXn-zQM;!=p_0!a=u?e zatg|2k(awR22leHqc?&15Y|0H3A-VvKjAZ*+$g3&fmu?7mnOAw#Ez0d#%~|%{CUc6 zkYTViU>gwfT5#%F)(G-tPlr}bnsA{F`fqB>g+oED1`;$UV=TZ?5%UvuPoX_zKGMry=myx_a(muIcO(=d^85$s~V=x6W=)%qUf zyAt-Iet1P_Tc0G+bz#Rts(Or8eb^naK=mloDO@Kxl9ahi&@c330g8aO2KsEx1UfPH z^6E8E{&IJr4}&O}=TW||w|8Tk#;wm+jqT){&g~Z!5&2we#uSxvxlHz4a8Pv9F%40l zFPLPYlCD(h;&`}IJh#DX^(nJfuAMN#K)_ zZ@`?xzz3QdKh^{2_0`XK0nW#4%w+qO#&-WhCg-JB#Zv~Hco4)`|6lK#ntnp@OKcX_ z2TMQ+iQ!DBtNo<|Y;?dE+2<`{!(fVUCipZ$IUaK{anF7NA)mKGP6h)Mw4YN=zF-37 z0$f8-Cjg@KhB>PO(&bdNFAx0={gg(%no2`#0GicULLOs(B_<$51wc#s;h%hCZDr7( zEr3cuG>S%k0~<5)Ih8q@7@5>`mkGy)+)IPdYHOVOQZ3MUqc2cq`vEcYf_}si6!*?B z-oR!L`sgF>fLj!j!5y172PTIN>tIi@M4Lu8GVc;64FkaAmbOpT$bC8*+FFSnIs!|A zyBrZG|M^J@r={PU`2|({1&qk?2tPkRTp~5@Z3?$El6d#|;XF3+s-S+IITIG_n;ad? z=_A#cIwS0l)K;wl=N$Oi!&KErplJ#sV=WN<)uK=6@N8o95>MCreq<_88V=wsouTH| z?r?ERrY6(Z)58YaO-p-lK|WNm`X&)JU&pT#QRl}gC8q!R>on>bz2{zo$5(9uOy2vBY!W_v?-kxJ+7?L7?(-;>|TwT9>kU7lmo zS%;Fv+PL6qA;lffjUg5&fT2k4+R>3~F@(@unpdd*+qdAK84nKRiPX3)`~P9>%);X@FEB5xU; z@i^+{;qFe@7(n2;VdsKR6v1p^2!|ltvOpHX?ge><%Bmb$_n1i|%aB{I7rQ|uQo%Bw zD>MQrU|C5onNWktPplE5h~jwa;m6r`6|ebg13G@~{th$_1QZK!5q&c-Px*U6fr)M) zbF(-?-@uD!3xo%%OG2*i8eGMa_!>)R zr$1`6RIh^E%Q5ILHImt3x0hSv3c4KvD{5zhA2=orIkPeBeJMt55;uN}Ekltel!HS` z#N@P$j2oJFRWo8&qUO}F`vqb|-bXbW8e^p1U}-=_$d6AO@5biIH}+s&BV_qG?4-Nx zP}NpczvA47iDo}kYDm1cV{_H(;F${SHpaU4lQ+Ny@Oc6~qpZcRth6tH(T0-`K zg?sN$PfJ1Zn7E}^T_`_yJuC7hk-IE6KW^J)T}AwIH($)~M@k}Y@$ z5iDo}L2uUhk^1O|oR_FRiT@sq#~S1fA5zas=bbtEeE3fR%K3Nx^b43PvVxJ1SuGgh z2kubz8?Y@DOJV)xV6X6z7**3`m{+*EFZC`44})rZj!;~z%*ZVrf7tZe+0rXn9)Wstc%{97uKaw+;` z!&eGb+Ktu$o+r;=&0dp!@9y#Y|ME}e8-_@hf*8J8oqf6TrRppjH#gt$_TH2!S2ljx z)X?c@Nrh=m?Xe}(01ejeVQNeKY2`PD%G#PeWdo(lq5twi_(@6+gMMjZy%wL+;~?hE z8w>V?bbn0x&hLJj^i`(j+PuNg5TB8xojl*vN3MCP@+95G>XYlODK`G=KfB!9)Z(VY z7u2>>8m4TkUUb~fh=+u)r7lAwTE}V*(*Gz0=rOQhKqM0rx$@RO?{L!lb^yAY`}a9y zc_=7JzqX!pgCyy33M=mS!gKFAY%GE`f zX>UkTaf+5soK9~0uE=nD--oJWG&61W6w$ER;p<7af2-api7h*t76LafZ4OM?#J_IHGdyB^%$T&f8=QE$fS1YY{SI!weQTh5{mtUkt^bq7QMtijd;GH+ciOja z4UD9fxIdVGA@eqc$)xQa``?0X6J_VwS&r^pUBab%Tt_IlM(ux2#mnC9on{RTPJB3> zIB+^ja{Bw1l-1k1XuoUECVCp0#$LxpzmXt=aJuczHbHi62F@Cf{=PBEiuIC_6hfT~ z>P;s?SyIgff;A$KU5!Xk_PX^@%(=Y7qejX@c)y!zwQqrOofh@#3p*UmP2m`hh?p$8 zcgEA9U%QBjnp~!7U*H>0;fs$XA58M2Z5i{Is!{daJHtG&?~qG) zaAdM->edY<9Cv^0$>^y)E$zN#^|`EFyLS`)cF!vFbG5nZ^!r#F!{iz1m@Frm!=4@5 z+H}vu(@=G%1*AU@I6h|GS*mh;HDCPp1jxXqntv9zaO0Wu)D_DveaGYQ{%C+ zSb+n#>n-vHQ`8o!tY^(~HD)V+?9LF{7j8At`Ioc(2!ni<)zI&_yH0lI&B_$SHfV_E z;{JGJdd9;(J(6*^mp5fSdEB?@T(ek9xf-vlyJ&VZQOkSC_n&v5o>qS%9oJ&)AS>W` z>S3_4|A(SU<%#;Rv$Uf8uD*-C1wNP^W-PYQ7e8K+X*!m)%S_;1^l^M_&8H&I?KiAG zciODHq}rT4aHQ+!kK2WIroTqNnDicd5dL!A#-9_NWr_~AGefOEr;K&9imcP-4$MDa${XbkK z3@VPt?~gg3CjE1wbg^DE+^m@@*6rt6+m7N;-sw2@n47(UJKt<{bP<2=AN#22s$H~3 zQ?O-cX^PF)M!Q@y724U!5}|^3ilvKJR^q5ioNYrkMvJ-$jlUfVptwugqEA+Ku~XI^ z(JC;RAFlmt!G5GO{zApu*JK+cL-L-pB)^X>qEpR(s-+?mM?oHXD(=M=<8Z4M`n`Xx zw6Susvx^Jy{4@>9RDa{dmHYjHAKzSC`vH%8?zR(cS0E(q$+)5%FTGVX(CRmK zvd64|#fQIq!qew_M^fqA^7gglfA8I8rnB5Gd}ctwqAO=Av8MTmPRV${fs{e3p8nn0 zi9K&K$!Wi&`794wbi8oAapRJ;CG$by*#}hn1@`^;&aKWqYjVEKenFsiij(Q}DYK>& zZ@r|BZlhoddYP>w4n32b9|UWZxYBO8k|U7*$bUco#pfB?r8fGV@8}C0=f~RkR^BW* zTxr!TaQe&e-Hh+E%KMW%@e|TJDJQ;ulKWI>Z~Eg$DYO25oAqgj{>B1|i?ll*Wq&_X zX3tDh^`kWKZhM|77bya9=u%j@XO~;Hzc8E)qhH`++r8l^MQ^aCY@Nc{62nbpTppfj zIZlk6(fOH59CWYe#oZ-Yjuh1<@EIE$B}A89q0`Mq2r66nDzmuoDJSE6QPGY0;rkm8 ztPC&EY;yMrdoJznyzo<8bg@U2EqH!8Q!&0{cKV0nm**;PYMg~_S?csMS=hSY)=V9I z&9aP7@?FpNb8OGbXmgRXMT~XJ%?IaVcsAaiys9a3PfYl0Lzie_hug==3&wRLKNAa6 zGEB`wKZ?1eoy}()oST)gbf(F+%&40a6#M$D=wtoul0N^@sNxzm%a=8GFFTAjjpT?H z*-h?+G(_yB^F*M`%2DOii?upgMnCc<OF#fa^9Gb#_tO@Ab) zyncGS1SydA4fuQ9{cShVoopu5HI)#6UF}ohGVSyQaQvGbW0p`hK3?f`CC;c>e!KOO z#`{B9A`f?mSn?Qk6^7dWHchAs$@t`aoQjuyPu!prOtyg=rpyp(H2BP-tbS{nYW!~a z#@=8o(H%3VmeIUzwArj}bUwK*W_JH3_kZI#lcAHJmqJllBmP0-VzTPbuv*$J#>YQ&7G7V; zR$PvIxvf`L^Y!CpQH|WIcgDZR?h7{Nt6Iw3#<;xMSWhG%!ez_tNxw3YgHa=uZKw|Y#@!?UwAbfm;#$D&DjwcAY|{zH5Qa{*%b_}<;5Z9*;KktVkDYus!H z|4}QG^XvF1o;E#demBD-UVkA`$?$u-@%Y(Rt8ydd!EGA3=Q%#8dY&?&ZPes1J##VP zLD?IBA)O?)^O8dyd8Zp8Lg&-R*fQTV`a=(S9!5lhxYw zm&{Su>?FV9GQrO~l+0b`=QnS1?^cNU`KrXh!_&ilyk)%2kA-?`dyc8UbzM|ZgfZW{ z(=yRTR-AeA{U60$+P}VVn|<@3`&@L1-NMIB?$g(_>U4^IZTdaVsFi#;((IUh-cxz# za}NPa2G|r9YhIjO60mId5Yw0L_DMXZ*YYayVDnP9 z@PYU2z9-zK$nP+5IVXxFX4};mEiKq~=Utz8@FPrQWk!EGL3_Dfd_V0E2@UCYGp$?p z38WP1E!(=k`WczmjoRbmc(nif*wm})R|=O$-mb5%;CYg z^*T*Y)Z_gw&+7W0h#qK9{ej?c+|=E3;gLpq-D?K6tC?*A=3PTm+g!x2VXhGW#vOyL zg;M$kuO%$+la}w~xkP31@6nvOZ#MiK?n*3KG<&@MD22QLXSYG#nV=CtsZ002&Y#?N zqDfKwq4_)GYbv$%xhE5}ldGz7k4IG~^=&Kq5q7NN#(1hVTd?EMQ@d`3haPP``uYcM zIQFianfQ|UCV9nWB(myQ@`s3nn)#mdgPqN1ikG~EI~808tk+4Nu0`4SIzh~F1s+rJ z=o!%sc0(=WOJytT4NID}9mTjmzBF%gT70~6Oi_&2+)8{tSEjdDDfYDO;-?=}rHl4$ zV_qwTpBENCed}JD^JyB%&$;#~Yv#69g@*C#D1L{6MYHsMDmqT%nGu8X<2!9n9G17| zVA|u-^x|ZRWnzNca_rFHbFJ*QfHk6`uD@Ei8dA2MdzdM4{6gmUcF$i!t@Fw259W`y zBwys>iLSh_XBj9@S~bJwLMf`8lJ;DSq=t(f*Ej7F3{rl=BU~Rc+@(kQF>^kzL4MUQ#&qycY6U@=);G*F0{69&f*X>GB8kiO0Axw z8yXr-wNLMSS`A~bk&)p@j>g@uYWbA8moN>dHB|q}mfC&HBX%d|xlVJxpyL`n5*-v= z@|O0qM&H3>CH_Wy1F&7HZX`7=<5r2jCLY?9ugDpL_OE^JBCe#i!^1%4$*CBduB)F9 z3B{h~2tOIE&qbYBz`aEq40ykFzAsVe^+OZ`gXzNE2}#=Yz`zMrh$^@mwc$)^12ILHyqQ<`aKoW6vwHaX+xcUgbi zNBT>q!oU9Cwut0C`s^Jna&6fwm-MF7ll(^V%{mp%Pgx`;(4W}%VEdu8dp}1)jxYNq zT=w*js;sT0J?504to~@D*lHWqsk(F5>u*!Ws_E@dRXOA1nTmbwN8b*)x&FQ>Z4_3a zck(^rp;SRuJH5%!!ytn_hCS9yIyVKKD;^yt1@W@dxsxGl)_(n^wef?|L8FV0ri>R~ z&W+BWX?j}0Mcvi-INTv3-1tLPEmeQI<`*_?|7Jbq!59JOsp1N=j=R-{*CdTp^Qz1_ zTQ+VX_t`@K{fK6H2UW1e=5EJ_n|5y!3+IS@a-h2=Yg(@1?D`*VFAN$eFlVRO8066Mr-3Yfl2u*^C~es-JKiT z$AAQ0A9D(ttVun#r|ZV-mPLi%_FE&%{Dj9?5yk0RIAup8v>)F4_2#48x53|Mm%~HcBJ~%x6?tE ziHXJrCp?V|;?9J$-elg$Z*eLAZ9_fN$GWPb+3}O8;D0>YSW@yvsz&gTX5qPzd>i%1 z8$#MXa&f}*MyB%ekDSjJJUcr#nnts6M=ZymWqId9HK5ILBrGW0i%!gb8g;BxEA`Tx zc37yQw*}XB&u<@EeddH5hZn=foOjTBg}X_4*GSzxp8QOP>U_8B_ctrgT3?(>y{KIh zcHFtkyM3wToMxgjl9_jRT>bgG+8I<10+F>)8Pfl{vr&`!%9S|N+*tNdzGpfMAGyW4 zQg7CD6uaz{ou5w{jZz-FR$a>EJuWhpxasW_Kd^yYPw!ulP8UcWJ)4hmJ2GGS)Tynx zW=&R}vA!S7XMDYVQ&e-aI^OGL4)hI3OG#@N#q6b_Q5p(=)R!J&TktS4EGF?hN3I6H zw%x**db%K`B~v~GZD-S($c?vLdYtOl{A81UZkuV-Gu7VH-gn)S!QD3**6Feckb)q{@<IX6cSS=-@o&>c`z{L^WgAd{=>|L%I?DNblbm}@W)lS8NR@$ z#s>OYUJI>m7#~|xkr}0_f8$bRf0|d|&MU`@S!ZPoa)p_LnRteb{Dw1ke!cSgARYbD z$XbVOLwA2(x=K;H^Zrzed}k5w1MhbJ&1&vN{_8D*O~0g=T4C7lXWQm|D--AT>o`8! z!+m*+n3(A;^2F(8rTT(lox^b`!r||?g*Idr)7M@79HYJ6Jd!AWZJ?leEW$RgaRp}Tuc=E z{N~5YLR??zbR77eA>uepry($Ry`|XX4g3C*151MDt$t1(BIkmof3k`EdMp`te7~F1 z*Q}pB4WWI#(%st86Z_kCT=UN;U1?~trON((_`U7q?D9kQ{jW3Bo_9r@FyqhaqHX7 z@gs+L52c02IzN-|mmloPUKyNjid5<dhI-a_Ubd-@woP00-(L|yn?%Ny;uMSjTMFYkG8KR54Y zq?f6C`}1=Zt&oF#RG()jT_*?Li@NOCoyB1!MJ?#jp{ZXU;jPv%b z+@&n79ch=3UpU+KekF!?puDI({~C}L#~&r!S`+Gbe_x8ULQrgDSrM~ju*B+;Ifh)-mkx|rrBJ`VY%_LoAdteB}X4s zdSPpgT_?jP5?c5p4@!~c`=)*00GJ0>N zEj)O>C%P@)wBv<^f-TGP=cWEc_D-3p25p&rE^}D-T#I}0p8;7?J~!RmsQb}^UV7_@ z=dbcRtY+WNMOic_6)Xk;KiN*-a((O_z4MN@Unh9{54ugxhED~#-JE)Jkm`NW4vlZe z$9;uro~orU&c)9%E1ZkW-BdxIv!_3fBd}!lOU>LVv1`A2Lq2bHKk$I+HaZY@y4&}5 zjQj1rwMnG-dJY2$L(c)p@;7}IQ*+xl{u;X%`|x_$mDJtl%)f>kOuC*l9hZIZrt$co zzmaW*1%2Pil|vnG~)Oxhbxl8a5&~ep?&gcN$re+q4y^n(fD#a-}zY z_LqOK{p6XIS4w;;MBQu66v5v$kMc$>z1@HNY-PpaH;jKd1Ae2SvFUg-+gtg1vixRW z@N-dDmj^Y~J4!7+w1~v)6W@3Ct7USXsMXxMw)(CzRVllX#_c*^%iNBpURVf2lXYaT zy3aW}(J2~nm+zr-?%CtPXFADmPFZWl-;5mC)IPmW{6^opymtcW#fEvA@iIB44SVCY zid~i#On#h;7V3T~Mde7*wLi)0e(C>H+<8Sc^+kVPe@KxYnt~uzIs(!`dJ%$@&_RkI zz1M_}(u)M?AOZr42+~1HC>ok{P)G33+hX{$@h3geg>ey|0Hf$}MDV0b8rgiRC8qC&dTUE*+oemw3qQ&UwI zORoXab1aRX1ofTubgN&-+Tr{cVJb1a-D}Hz%;{q9tNsyq0j$B7wJLj;FR5y}=xahV zV=1&m-eb0jg1#~+6FSw}lP?`(Ci+YJ!3tG0>3Uo;1*05X3x#>G<1zYSsaJo^VbCHP z&yAbIhL)XBJJ_Bdp3F)geG|-`8(S!D3$6;zj4Ku z?~u-_mjF=hF1$zbQ!LU^;kyU4^ha*f)WG=%>k}lFD1WWk+R`K$P5fc$ZPgvcW5+ zV@aX3?!vo*hFrcVJA8({xzZBB8Xwa>?fr!4Ix)KCJ4;>ZC~|$I;w`uFEOh%~@`gUO zc7E7;oAq1z#eNz7QmuYYlRQFmMVt#Xh7?uIurG~!eRmhKbp1eXVY6!>@*y%rH*nxk&yXi-pSb1w&w z2qsS-CQIl#QdQs`XUT|5Ey?6_>doEjEL0X|#5YW9+8lq+^X}!czm<^=9Kqb*(rG9d zJZEslkSX{<)#p0L38Dbyw1axyQpMI8ZXZ^CCh0(`@?%q<%%JQ>m}>ixqEbgH}Z;_E~lG=8{`e5X)P z-Q+cRvRxu-Z);Do7D&-yRPC?`^37M5j7fZ_`A&Qt?lVrHliO5f+tvNeLGbnI2x!e& z$=zeV=6Z_tp|jzx7U+D>FNjaOV0&cJqw}yc$A9T*+x#l^{MLB+9cIX0V+KA51j)w# zsB~0`JrD1`dyf@9h+UsiJi_0W5+x@-9PqPfWTp*3U?SyTH3c*XqI#@snzRdH7T1>F z#${xqT<;ZQry|xCKn9gpoS&2g1{0EgJteeZZ+RbKNYs#gb-29oXKg za(RMt;kJ>@8oa!+d~OVgc3xaDA23z3%wW|s{nmX5Va>eN8OnD;#w$2QwMtGStgAq0 z2?UtbiUM145118L?M`>_Zi%D8ZP~n5U}N89OMig*Ga*>Uk#It*QrlXLkk%#n?^@zC+nDoHc|>24z2n`WzBB4HI(syVG?3 zyYUv02UWV&A8uA))_B+$9#j#E7TdC})mYHHeYn zOYh(;;)0tlIhfeR2r6D< zP0gzqR_Ag47J7g4e%N<%U>E98*nhW(Mr}VY?KjuEypn?Tq7`D5f7}qX;v3Ul@|pE%_f0@yp&J^as9dhM=qY2* z_3|`P8iyCMLhv9D9}(2AL`zH}<&awYu$9kGj#KPLbbe05S5BS$_JC8%V+N;u7Fu(i zhZ%_Et;j9ChXF3rjeZiPnV9Pivs<5lo+uzSD zUIHtCg^T5+y;{yIF5$in%Tql*Nqo`M?!Vz&kYFKOVRuclOzW$Yn0lT`(^RX8n|Qfe zN6%L(5M;x!^9k3;Q}GAFJ)Q5m3Q zxEdl&l;LRodN4CR*99s|a7Bujv-xWZ?U0Oe;|@vY0iY?hX?M!BJQ7t)W>dNH<;D-w z@^isQOV0R~t$DtOW`(1EJ@=cq;59|E4S=}vL+cjJ{r^ICkm-Q4vIJ)T)%W{@79=fx z{l!FFJ~zr0edy5FaF~@4xMXRfT}|+zJ%r$`RgStAkZ_b57Hv`|$;H-mB<&kN&H*wh zt-2>%+AB|$oV44Tle1cE1~U$GpmFzryn`-df2jzwC%~+V>8H%LJx{4GAt(xr#$*0w zF9@weXS zIaaZ0=QhQnrfUMIeMMb$Cr?$XdYR%h)gLzB$*<$@SoUl8G1whpmA|t8X=$YdMZEN) za+>dG2nbUq`59OgndG2U$`}kvpDo#KcYC(c4)%GAtD3vn&piUiC8t))Nw%7&{*mYf zpnUcF<(@Y?T!4(<=g z7OyzA27hWR+nSRa>+!S=#OxhnuCGOISweTzB5rgLVl8W}d(M@6l7S~iE>la2U#vC~ z+7DVt+jakkZJA@gfi1x*QDdZ)mv8|XI}R%$s4T{QkijsjT~}Df|L7WT;(FfhR0OwL zFD}T}t-*Et$Bsqlcyt9LwHU7F4l20Evvc=9NziaJY^Ss$rpC;Vt%nEPM~P)ThIxrHp-Waa4=_(RlW1CtPB9 zR~e{3Y@10u`W_f;ioTtzMvg{%(HDlq{b1^=iXc2llb-?dz?wkZ$DkdCb<9da{Od+s z7@9o*XGR<4&FDN@W)7j89S5YJgV5^rW!hUPlC#MDJcXg0a5~uRL+pW99rx0~F_j=n zm5jdY%%gaSwj$M)MD`X7kJMq&aBc%Dz3_+pQ(Jk_ISF@Mz_!|&GEIKKGKD24e8m(U zdX_ksco54R(Dk<1uCarQ_&IwF1?3%{X5%IoN2{Ng_mX%-9Z;YA;t_vKg9id?o4HV`$gBc_wH%G`#FczW}K>&c`0`Xo+M5QPk2(@vVTHy zK28^33k0g{UR;YIE2=P;pXFFCGWrqfnC--4du&sJyQAEUMG`s5dg?7OyQhoKuNIW# z70lVUC;i?l#DY7o>`d;0+u3&CLpBZG8|EcDE~@ zlPQYD0Q`CsWyEKkm;I1w^y7VC$d59!PM}i{gh0UV5p3w;Ha^g%eaZJ@nAO~cHira7 zj+Od`w!n}?He@%`gOeZ2<8B)8jLk&b-Ey=c*YgB9Af;&)gyK0qf9NjxF*YqB%V2$k z^jsk_is1}FV$ikgH_0KdOsiS^oxH$&;vN8SRqlxu_X@s`C1xep4AXa$4!m-O;9P;_x!CZl;D}{yvuIS|0pEX% zJ6FU!b@HU!FGi}<#-7J8HzLvmF?)Hk8F!QMPzh~k(XRTwYd>Oy+HddZ`LkKe*?LD< z8qckaY92rLUphM~RdQL(@|bDc`jm%z0IB0oBZzW&7G!P?3su|mo1|f2&^vf0i>k>0 zWDnv}ppm$?H^p}5?a7Q5Jf+&(R`Wl|0er@guOFsQs!f+b`x$Z2FkG-W2grIp-h0jl zNdo=QoV?@!c8vX~18Jcoy4fk-13PrQXf#)|7uRd6E$MT$_njhc#yNBz5H!Gp?Zm8q z0k%>oQn&4|eLgTNH}jVC_SSN)2QTRm|G7w^_jgaC94$Q;gIFgd?7W45R66mE zk*QnCKj4c9?8{0}4o0obTLZgCJvBX%HU9JOP6mZXe{*V}|Ic{d|1&t420V-&3`P8H z>FZ}VV}(jcDM*B~-2iuSd4v<#Ja#NmWTGl;(9qM)(Ei(BO1SDtG2 ze^E-La01SE6M)6bJA1D-4j9EFAEz$eBG*Vf)JR`h0&{TsSh?CjT?og)|^ z6|bm$C0|hs;{E$Q1+N9|F~9lOyD_%I8lG9H3Adj2+AL>9?cVrzu7Y}sET7CIT152@ z0?aKs@do|o`61H%mn1nS-1M;;Qt)3JuO_Fuj5&#gF6z@%>PL%Bs8Q5&h1zSKX;0N8 zz$4lKlJC(6JxWxZLF@hD{gl33$YJqAHn|us3m9g z`&yy*L)y5-sO(I15T$XSL+6sK^;n7JB`Iq^JwHRFy!fB5vKBar@IaNyY`hTVtvAy%hS*l{gfOVp7DFwk;f=gf<`@h z{I*}H6^k(Ap{+> z%Ww_b)|43Z-LvA@&Q!WsfqHzr5iPEbS z%B5Svkt7xv@VI`Uq=MiJF=$n+=twK7sKBmiS+?QJti7OYWhs=2n0FWK!CNCnXxO#$ z^N12Vj6y1_IOv!NYdaoBCHa%Ff{yvQCQBwUo>YMQx`wc8XV%nGdG>U(wU807Kn(J> z#aX04Vck<}tRqcWM*c3!8i0lKHJ}J^Z!6)SGkURoS3o#9$;iIC-ik!etUX$C4c2U? zndZV*RT>X|o0q|mF4F-NEsNj)_qfvb{mdVK>0?v`o~nuJDAYA!Vl7XA$4wtYQf&W{ z$h;2Vw_h!TSq!G{#-@X+(M9nju5l`{V~ z2vHBqjb`84;1wt{6%XZGYs##n%spbXsGJ`8o*aVR?)U_9_C=5*RLg~?`4X$j*y7VY=N613&R?LVEP49x01-xf_=E~e;2hRh~AeW zknDCbwv$pN+9xgP?h@~ad8`EP4Q`&mt3q#+1f|SZd^ zMk!5+;_9t2!khH;PKf=l3{$k##8C_Mv`kVAUE?Dow@w%!Db*=FcQk5jNglO$sYQf!doQcU2Ioqofo0>xUjxV^ zxv9XVCO)eVHV2M3=j@2d)DpTAex|%|h30g*)@wq0H}C5kIMu{$mTpoTq{m1_u5D43 z8(puZZhP{t8^hEcd7QGP%bOdy#$=ea3gGo!XQLJ9H$!Gc1M^#yJSlJLz`TgnDiRHA ziAS^m)rVx_VH-ws$QTe+Y<`k*SN?#7R; zUvrXCm{+zMUfiTg`ug-=rzjV|j%7qqGyNh2!XyJkwbY?48h~M39#<)E(|PlWF+sG- z_kMkne@j&_A0Z@abdzDlI6pjBt0qTaVybTmDH!}0m4^WHd*7GXs^C=BYovg~D=`S= zl=;`E3fG0#fr9SSd#s!Zai=gDdisCv?TV^udR zti;+^t-by#4JkHVb7@eQ2eD+NM7mjSszZ$i6hh!H#Tl-VE=xuXT&&dpz0(GO3y5Y9 zT+V#lSt_cLfD*n+KT2LB%}8!#1<(8*1)QMQEuuPqGhr~ud>`s z6t}zr1Cl|`%RwF$^xyNSd6$ArC`XJ4@eIdVJVzY!MV=fQpD$9yKykutE;=m84}CWN z4!v>M9QkdnTYjIoGz!3c>8C0)iLU&VMp^LwMz9G+@3P&ek*6ygw5fiXdr>{J4Q+ZH z!%0e2XjZN!CCvY@X#5&)BjCFs_{RZ@tY@bH{KiUFSfpCp?QwP(#on`gM+@SXCd$l1s8HZcr$4=*8Ur=`7u%uSa-WFRKgA2#) z#;cRs*>Vmm6S+XuE^KMK$7lb!{J<;36Kva-L<$17{Z#7L_W0n6FWrTx>18;GE2jLl zOHJoY*^YnNhb(}8njn)bNvHH|*Z ze{>lR&t9DP01*)3BSCfY8GC%W!8}o6+8R*XeH{Rp^TJNQ`4CK|nyd*}#_`H#e9iWeaHU0({G{gfmLW%*bzd@ z0NgxT4y+L^CcQDcp&r2=O*YpQ+Pjmed9nLR{p@6WY&8wXCrYM}Kai;LeD4G+nlVmyHAD(vS%gWKA|6z|X}8>2MUTBsCp zAOPw6?A8 zoL<@(#3$i2_S!n4`Ah19m1XQt`RAFit*=*cTN4%ZFgELf^`IX3ZB!l{{Jzw*XeP1K z_O}ni-@R-Vk+??S*|c$w{C;0?Ibv0gE(qxOSGS)J?miHx_51~F)Wqz9TEx4}Z_zVI<Z7uiNi_k~@MSpHQ$jX=TfCov&_` zRvU`DPsfEX`RF9>-y39&IJsO#0$BBkZ1DP(rZr&ki2bms@6mePX}8>bg+ZlJl(9$PB4-775Lmgl~SS|LHWDJk}awD$yJp{yx6ik^1o|JKdrIIv5+fTgd)e2*8-F zq&Usq^Xq%pPP+oGSa@`lfh;K)1kwF6AU;uI1ep7AI1q#e8)aP1RacR~Yv^|^yGz6S vzh4`LlLr>MU0h5kmZbo12riR(yek*CUduS#^zFD@1gD{@tx}=%IQ)MBu0jyp literal 0 HcmV?d00001 diff --git a/mcp/screenshot-e2e-css-fonts.png b/mcp/screenshot-e2e-css-fonts.png new file mode 100644 index 0000000000000000000000000000000000000000..b9fb6176cfab625631ba947341782979f3df3527 GIT binary patch literal 67693 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∓A4M5ho&>C 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 O0000UigZ|z% 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 7551c27a1a..4dbd692ef4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@posit/shiny", - "version": "1.13.0-alpha.9000", + "version": "1.14.0-alpha.9000", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@posit/shiny", - "version": "1.13.0-alpha.9000", + "version": "1.14.0-alpha.9000", "license": "MIT", "dependencies": { "@types/bootstrap": "5.2.x", @@ -18,6 +18,7 @@ "lit": "3.2.x" }, "devDependencies": { + "@modelcontextprotocol/ext-apps": "^1.7.4", "@selectize/selectize": "https://github.com/selectize/selectize.js.git#e3f2e0b4aa251375bc21b5fcd8ca7d374a921f08", "@types/highlightjs": "9.x", "@types/jqueryui": "1.12.24", @@ -1846,6 +1847,20 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1927,6 +1942,104 @@ "@lit-labs/ssr-dom-shim": "^1.4.0" } }, + "node_modules/@modelcontextprotocol/ext-apps": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/ext-apps/-/ext-apps-1.7.4.tgz", + "integrity": "sha512-QQqysE549cf/Y0VabBmAACXhj92EhB3t8yVct2BHbkWiPTFA1S91EqTVjYXXcZEefXU0pmHcdObhsNMcomJIOQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "examples/*" + ], + "dependencies": { + "@standard-schema/spec": "^1.1.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2317,6 +2430,13 @@ } } }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/bootstrap": { "version": "5.2.10", "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.10.tgz", @@ -2667,6 +2787,21 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2707,6 +2842,51 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2775,6 +2955,47 @@ "dev": true, "license": "MIT" }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/bootstrap-datepicker": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.10.0.tgz", @@ -2862,6 +3083,50 @@ "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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", @@ -3000,6 +3265,54 @@ "dev": true, "license": "MIT" }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/core-js-compat": { "version": "3.44.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", @@ -3014,6 +3327,25 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3137,9 +3469,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -3161,6 +3493,17 @@ "dev": true, "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -3175,6 +3518,30 @@ "node": ">=0.10" } }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/electron-to-chromium": { "version": "1.5.194", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", @@ -3182,6 +3549,17 @@ "dev": true, "license": "ISC" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3192,6 +3570,42 @@ "is-arrayish": "^0.2.1" } }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "peer": true, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", @@ -3270,6 +3684,14 @@ "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==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3592,8 +4014,109 @@ "node": ">=0.10.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "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, @@ -3650,6 +4173,24 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -3686,6 +4227,29 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3724,6 +4288,17 @@ "dev": true, "license": "ISC" }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -3738,6 +4313,17 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -3770,6 +4356,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-tsconfig": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", @@ -3809,6 +4436,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3826,6 +4467,20 @@ "node": ">=8" } }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -3839,6 +4494,17 @@ "node": ">= 0.4" } }, + "node_modules/hono": { + "version": "4.12.29", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.29.tgz", + "integrity": "sha512-1hNiRjawYrLq/4m3DQQjPGFg0VZkk4RjQJDff/excI6Dm9BiL75qxGrd7/c6YOxPdq6AscP3LiXhQ6fKFC1Waw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -3846,6 +4512,46 @@ "dev": true, "license": "ISC" }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -3900,6 +4606,36 @@ "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==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3972,6 +4708,14 @@ "node": ">=0.12.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3979,6 +4723,17 @@ "dev": true, "license": "ISC" }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/jquery": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", @@ -4040,6 +4795,14 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true + }, "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", @@ -4139,6 +4902,42 @@ "dev": true, "license": "MIT" }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4163,6 +4962,35 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -4232,6 +5060,17 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -4270,24 +5109,74 @@ "semver": "bin/semver" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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", + "peer": true, + "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==", "dev": true, "license": "MIT", + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "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==", "dev": true, "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" } }, "node_modules/optionator": { @@ -4382,6 +5271,17 @@ "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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", @@ -4409,6 +5309,18 @@ "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==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4429,6 +5341,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -5245,6 +6168,21 @@ } } }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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", @@ -5255,6 +6193,24 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "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", @@ -5276,6 +6232,38 @@ ], "license": "MIT" }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -5429,6 +6417,17 @@ "jsesc": "bin/jsesc" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -5481,6 +6480,24 @@ "node": ">=0.10.0" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5523,6 +6540,14 @@ "dev": true, "license": "ISC" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/sass": { "version": "1.89.2", "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", @@ -5904,6 +6929,63 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5927,6 +7009,86 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5973,6 +7135,17 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -6079,6 +7252,17 @@ "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -6197,6 +7381,41 @@ "node": ">=8" } }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -6218,6 +7437,17 @@ "dev": true, "license": "MIT" }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -6285,6 +7515,17 @@ "license": "MIT", "peer": true }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6311,6 +7552,14 @@ "node": ">=0.10.0" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -6323,6 +7572,28 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peer": true, + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } } } } diff --git a/package.json b/package.json index 770799b30a..4ec55d88c5 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "lit": "3.2.x" }, "devDependencies": { + "@modelcontextprotocol/ext-apps": "^1.7.4", "@selectize/selectize": "https://github.com/selectize/selectize.js.git#e3f2e0b4aa251375bc21b5fcd8ca7d374a921f08", "@types/highlightjs": "9.x", "@types/jqueryui": "1.12.24", @@ -58,9 +59,10 @@ }, "scripts": { "watch": "npm run bundle_shiny -- --watch", - "build": "npm run build_shiny && npm run bundle_extras && npm run bundle_external_libs", + "build": "npm run build_shiny && npm run bundle_extras && npm run bundle_external_libs && npm run bundle_mcp", "build_shiny": "npm run checks && npm run bundle_shiny", "bundle_shiny": "tsx srcts/build/shiny.ts", + "bundle_mcp": "tsx srcts/build/mcp-bridge.ts", "bundle_external_libs": "tsx srcts/build/external_libs.ts", "bundle_extras": "tsx srcts/build/extras.ts", "checks": "npm run lint && npm run build_types && npm run test_types && npm run coverage && npm run circular", diff --git a/srcts/build/mcp-bridge.ts b/srcts/build/mcp-bridge.ts new file mode 100644 index 0000000000..7518db12af --- /dev/null +++ b/srcts/build/mcp-bridge.ts @@ -0,0 +1,26 @@ +// Builds the MCP Apps bridge (inlined into the ui://shiny/app resource): +// ``` +// npm run bundle_mcp +// ``` + +import type { BuildOptions } from "esbuild"; +import { banner, build, outDir, shinyDesc } from "./_build"; + +const opts: BuildOptions = { + entryPoints: ["srcts/src/mcp/index.ts"], + bundle: true, + format: "iife", + sourcemap: false, + define: { + // eslint-disable-next-line @typescript-eslint/naming-convention + "process.env.SHINY_VERSION": `"${shinyDesc.version}"`, + }, + banner: banner, +}; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +build({ + ...opts, + outfile: outDir + "shiny-mcp-bridge.js", + minify: true, +}); diff --git a/srcts/src/mcp/__tests__/hybridSocket.test.ts b/srcts/src/mcp/__tests__/hybridSocket.test.ts new file mode 100644 index 0000000000..3ba8292cd3 --- /dev/null +++ b/srcts/src/mcp/__tests__/hybridSocket.test.ts @@ -0,0 +1,137 @@ +import assert from "node:assert"; +import test from "node:test"; +import { McpHybridWebSocket } from "../hybridSocket"; +import type { McpTunnelWebSocket, ToolCaller } from "../tunnelSocket"; +import { McpTunnelWebSocket as Tunnel } from "../tunnelSocket"; + +// A controllable fake WebSocket constructor +function makeFakeWs(behavior: "open" | "error" | "hang") { + const instances: FakeWs[] = []; + class FakeWs { + url: string; + binaryType = ""; + onopen: (() => void) | null = null; + onerror: (() => void) | null = null; + onclose: (() => void) | null = null; + onmessage: ((e: { data: unknown }) => void) | null = null; + sent: unknown[] = []; + closed = false; + constructor(url: string) { + this.url = url; + instances.push(this); + setTimeout(() => { + if (behavior === "open") this.onopen?.(); + else if (behavior === "error") this.onerror?.(); + }, 5); + } + send(data: unknown): void { + this.sent.push(data); + } + close(): void { + this.closed = true; + this.onclose?.(); + } + } + return { ctor: FakeWs as unknown as typeof WebSocket, instances }; +} + +function makeTunnelFactory() { + const caller: ToolCaller = async (name) => { + if (name === "_shiny_connect") return { connectionId: "tid" }; + if (name === "_shiny_receive") { + return await new Promise(() => { + // hang + }); + } + return {}; + }; + let created: McpTunnelWebSocket | null = null; + const make = () => { + created = new Tunnel(caller); + return created; + }; + return { + make, + get created() { + return created; + }, + }; +} + +void test("adopts the direct websocket when it opens", async () => { + const { ctor, instances } = makeFakeWs("open"); + const tunnels = makeTunnelFactory(); + const kinds: string[] = []; + const sock = new McpHybridWebSocket({ + directWsUrl: "ws://127.0.0.1:1/websocket/?mcp=1", + makeTunnel: tunnels.make, + wsConstructor: ctor, + timeoutMs: 200, + onTransport: (k) => kinds.push(k), + }); + const opened = new Promise((r) => (sock.onopen = () => r())); + void sock.start(); + await opened; + + assert.deepEqual(kinds, ["direct"]); + assert.equal(sock.readyState, 1); + assert.equal(tunnels.created, null); + + sock.send("hello"); + assert.deepEqual(instances[0].sent, ["hello"]); + + // messages flow through the facade + const got: unknown[] = []; + sock.onmessage = (e) => got.push(e.data); + instances[0].onmessage?.({ data: "frame" }); + assert.deepEqual(got, ["frame"]); +}); + +void test("falls back to the tunnel when the direct attempt errors", async () => { + const { ctor } = makeFakeWs("error"); + const tunnels = makeTunnelFactory(); + const kinds: string[] = []; + const sock = new McpHybridWebSocket({ + directWsUrl: "ws://127.0.0.1:1/websocket/?mcp=1", + makeTunnel: tunnels.make, + wsConstructor: ctor, + timeoutMs: 200, + onTransport: (k) => kinds.push(k), + }); + const opened = new Promise((r) => (sock.onopen = () => r())); + void sock.start(); + await opened; + + assert.deepEqual(kinds, ["tunnel"]); + assert.equal(sock.readyState, 1); + assert.notEqual(tunnels.created, null); +}); + +void test("falls back when the direct attempt hangs past the timeout", async () => { + const { ctor, instances } = makeFakeWs("hang"); + const tunnels = makeTunnelFactory(); + const sock = new McpHybridWebSocket({ + directWsUrl: "ws://127.0.0.1:1/websocket/?mcp=1", + makeTunnel: tunnels.make, + wsConstructor: ctor, + timeoutMs: 30, + }); + const opened = new Promise((r) => (sock.onopen = () => r())); + void sock.start(); + await opened; + + assert.equal(sock.transportKind, "tunnel"); + assert.equal(instances[0].closed, true); +}); + +void test("goes straight to the tunnel without a direct URL", async () => { + const tunnels = makeTunnelFactory(); + const sock = new McpHybridWebSocket({ + directWsUrl: null, + makeTunnel: tunnels.make, + }); + const opened = new Promise((r) => (sock.onopen = () => r())); + void sock.start(); + await opened; + assert.equal(sock.transportKind, "tunnel"); +}); diff --git a/srcts/src/mcp/__tests__/tunnelSocket.test.ts b/srcts/src/mcp/__tests__/tunnelSocket.test.ts new file mode 100644 index 0000000000..631b303982 --- /dev/null +++ b/srcts/src/mcp/__tests__/tunnelSocket.test.ts @@ -0,0 +1,113 @@ +import assert from "node:assert"; +import test from "node:test"; +import type { ToolCaller } from "../tunnelSocket"; +import { McpTunnelWebSocket } from "../tunnelSocket"; + +function makeHost( + receiveBatches: Array<{ frames: unknown[]; closed: boolean }>, +) { + const sent: Array<{ [key: string]: unknown }> = []; + const closed: Array<{ [key: string]: unknown }> = []; + const caller: ToolCaller = async (name, args) => { + if (name === "_shiny_connect") return { connectionId: "abc" }; + if (name === "_shiny_send") { + sent.push(args); + return {}; + } + if (name === "_shiny_receive") { + const batch = receiveBatches.shift(); + if (batch) return batch as unknown as { [key: string]: unknown }; + return await new Promise(() => { + // hang: no more data (simulates a long-poll that never resolves) + }); + } + if (name === "_shiny_close") { + closed.push(args); + return {}; + } + throw new Error("unknown tool " + name); + }; + return { caller, sent, closed }; +} + +async function tick(ms = 20): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +void test("opens, delivers frames in order, sends, and closes", async () => { + const { caller, sent } = makeHost([ + { frames: [{ data: '{"config":{}}', binary: false }], closed: false }, + { frames: [], closed: true }, + ]); + const sock = new McpTunnelWebSocket(caller); + const events: string[] = []; + sock.onopen = () => events.push("open"); + sock.onmessage = (e) => events.push("msg:" + String(e.data)); + sock.onclose = () => events.push("close"); + + await sock.start(); + sock.send('{"method":"init","data":{}}'); + await tick(); + + assert.equal(events[0], "open"); + assert.ok(events.includes('msg:{"config":{}}')); + assert.ok(events.includes("close")); + assert.equal(sock.readyState, 3); + assert.equal(sent.length, 1); + const frames = sent[0].frames as Array<{ data: string }>; + assert.equal(frames[0].data, '{"method":"init","data":{}}'); +}); + +void test("binary frames round-trip as ArrayBuffer/base64", async () => { + const { caller, sent } = makeHost([ + { frames: [{ data: "AQICAg==", binary: true }], closed: false }, + ]); + const sock = new McpTunnelWebSocket(caller); + const received: ArrayBuffer[] = []; + sock.onmessage = (e) => received.push(e.data as ArrayBuffer); + + await sock.start(); + await tick(); + + assert.equal(received.length, 1); + assert.deepEqual( + Array.from(new Uint8Array(received[0])), + [0x01, 0x02, 0x02, 0x02], + ); + + sock.send(new Uint8Array([0x01, 0x02, 0x02, 0x02]).buffer); + await tick(); + const frames = sent[0].frames as Array<{ data: string; binary: boolean }>; + assert.equal(frames[0].binary, true); + assert.equal(frames[0].data, "AQICAg=="); +}); + +void test("connect failure surfaces as close with code 1006", async () => { + const caller: ToolCaller = async () => { + throw new Error("no host"); + }; + const sock = new McpTunnelWebSocket(caller); + const events: string[] = []; + sock.onclose = (e) => events.push("close:" + e.code); + sock.onerror = () => events.push("error"); + + await sock.start(); + assert.deepEqual(events, ["error", "close:1006"]); + assert.equal(sock.readyState, 3); +}); + +void test("client-initiated close calls _shiny_close once", async () => { + const { caller, closed } = makeHost([]); + const sock = new McpTunnelWebSocket(caller); + const events: string[] = []; + sock.onclose = (e) => events.push("close:" + e.code); + + await sock.start(); + sock.close(); + sock.close(); + await tick(); + + assert.deepEqual(events, ["close:1000"]); + assert.equal(closed.length, 1); + assert.deepEqual(closed[0], { connectionId: "abc" }); +}); diff --git a/srcts/src/mcp/__tests__/tunnelXhr.test.ts b/srcts/src/mcp/__tests__/tunnelXhr.test.ts new file mode 100644 index 0000000000..800d8b8168 --- /dev/null +++ b/srcts/src/mcp/__tests__/tunnelXhr.test.ts @@ -0,0 +1,145 @@ +import assert from "node:assert"; +import test from "node:test"; +import type { ToolCaller } from "../tunnelSocket"; +import { createTunnelXhrClass } from "../tunnelXhr"; + +type HttpCall = { [key: string]: unknown }; + +function makeEnv( + respond: (args: HttpCall) => { + status: number; + headers?: { [key: string]: string }; + body?: string; // base64 + }, +) { + const calls: HttpCall[] = []; + const caller: ToolCaller = async (name, args) => { + assert.equal(name, "_shiny_http"); + calls.push(args); + return respond(args) as unknown as { [key: string]: unknown }; + }; + const xhrClass = createTunnelXhrClass({ + callTool: caller, + getConnectionId: async () => "abc", + pageOrigin: "http://sandbox.example", + }); + return { xhrClass, calls }; +} + +function once(xhr: { onload: (() => void) | null }): Promise { + return new Promise((resolve) => { + xhr.onload = () => resolve(); + }); +} + +void test("GET tunnels relative URLs with query strings", async () => { + const { xhrClass, calls } = makeEnv(() => ({ + status: 200, + // eslint-disable-next-line @typescript-eslint/naming-convention + headers: { "content-type": "text/plain", "X-Extra": "yes" }, + body: Buffer.from("hello").toString("base64"), + })); + const xhr = new xhrClass(); + const loaded = once(xhr); + xhr.open("GET", "session/abc123/dataobj/tbl?w=&nonce=1"); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + xhr.send(null); + await loaded; + + assert.equal(xhr.readyState, 4); + assert.equal(xhr.status, 200); + assert.equal(xhr.responseText, "hello"); + assert.equal(xhr.getResponseHeader("content-type"), "text/plain"); + assert.ok(xhr.getAllResponseHeaders().includes("x-extra: yes")); + + assert.equal(calls.length, 1); + assert.equal(calls[0].method, "GET"); + assert.equal(calls[0].path, "/session/abc123/dataobj/tbl?w=&nonce=1"); + assert.equal(calls[0].connectionId, "abc"); +}); + +void test("same-origin absolute URLs are tunneled with origin stripped", async () => { + const { xhrClass, calls } = makeEnv(() => ({ status: 204 })); + const xhr = new xhrClass(); + const loaded = once(xhr); + xhr.open("GET", "http://sandbox.example/shared/shiny.min.css"); + xhr.send(); + await loaded; + assert.equal(calls[0].path, "/shared/shiny.min.css"); + assert.equal(xhr.status, 204); +}); + +void test("POST tunnels string and binary bodies as base64", async () => { + const { xhrClass, calls } = makeEnv(() => ({ status: 200 })); + + const xhr = new xhrClass(); + let loaded = once(xhr); + xhr.open("POST", "session/x/upload/1"); + xhr.setRequestHeader("content-type", "text/plain"); + xhr.send("a=1&b=2"); + await loaded; + assert.equal( + Buffer.from(String(calls[0].body), "base64").toString(), + "a=1&b=2", + ); + const headers = calls[0].headers as { [key: string]: string }; + assert.equal(headers["content-type"], "text/plain"); + + const xhr2 = new xhrClass(); + loaded = once(xhr2); + xhr2.open("POST", "session/x/upload/2"); + xhr2.send(new Uint8Array([1, 2, 2, 2]).buffer); + await loaded; + assert.equal(calls[1].body, "AQICAg=="); + + // Blob bodies (file uploads) + const xhr3 = new xhrClass(); + loaded = once(xhr3); + xhr3.open("POST", "session/x/upload/3"); + xhr3.send(new Blob([new Uint8Array([5, 6])])); + await loaded; + assert.equal(calls[2].body, Buffer.from([5, 6]).toString("base64")); +}); + +void test("arraybuffer responseType yields ArrayBuffer response", async () => { + const { xhrClass } = makeEnv(() => ({ + status: 200, + body: Buffer.from([9, 8, 7]).toString("base64"), + })); + const xhr = new xhrClass(); + const loaded = once(xhr); + xhr.open("GET", "shared/thing.bin"); + xhr.responseType = "arraybuffer"; + xhr.send(); + await loaded; + assert.deepEqual( + Array.from(new Uint8Array(xhr.response as ArrayBuffer)), + [9, 8, 7], + ); +}); + +void test("tool failure surfaces as onerror with status 0", async () => { + const caller: ToolCaller = async () => { + throw new Error("gone"); + }; + const xhrClass = createTunnelXhrClass({ + callTool: caller, + getConnectionId: async () => "abc", + pageOrigin: "http://sandbox.example", + }); + const xhr = new xhrClass(); + const errored = new Promise((resolve) => { + xhr.onerror = () => resolve(); + }); + xhr.open("GET", "session/x/y"); + xhr.send(); + await errored; + assert.equal(xhr.status, 0); + assert.equal(xhr.readyState, 4); +}); + +void test("upload property exists for jQuery progress wiring", () => { + const { xhrClass } = makeEnv(() => ({ status: 200 })); + const xhr = new xhrClass(); + assert.ok(xhr.upload); +}); diff --git a/srcts/src/mcp/hybridSocket.ts b/srcts/src/mcp/hybridSocket.ts new file mode 100644 index 0000000000..eaae09a79f --- /dev/null +++ b/srcts/src/mcp/hybridSocket.ts @@ -0,0 +1,143 @@ +// The direct-connect fast path: when the ui://shiny/app resource declared +// the app's origin in its CSP (`connectDomains`), spec-compliant hosts let +// the sandboxed iframe open a real WebSocket straight to the app — +// dramatically lower latency than tunneling frames through tools/call. +// Hosts that ignore declared CSP block the attempt, so this facade tries a +// direct WebSocket (bounded by a timeout) and falls back to the +// McpTunnelWebSocket. Shiny only sees the facade: onopen fires once, after +// a transport has been adopted. + +import type { McpTunnelWebSocket } from "./tunnelSocket"; + +type SocketEvents = { + onopen: (() => void) | null; + onmessage: ((event: { data: string | ArrayBuffer }) => void) | null; + onclose: ((event: { code: number }) => void) | null; + onerror: ((event: unknown) => void) | null; +}; + +export interface HybridSocketOptions { + // Full websocket URL for the direct attempt (null = tunnel only) + directWsUrl: string | null; + makeTunnel: () => McpTunnelWebSocket; + timeoutMs?: number; + wsConstructor?: typeof WebSocket; + // Called once a transport is adopted (for diagnostics/tests) + onTransport?: (kind: "direct" | "tunnel") => void; +} + +export class McpHybridWebSocket implements SocketEvents { + readyState = 0; // CONNECTING + binaryType = "arraybuffer"; + allowReconnect = false; + transportKind: "pending" | "direct" | "tunnel" = "pending"; + + onopen: (() => void) | null = null; + onmessage: ((event: { data: string | ArrayBuffer }) => void) | null = null; + onclose: ((event: { code: number }) => void) | null = null; + onerror: ((event: unknown) => void) | null = null; + + private transport: WebSocket | McpTunnelWebSocket | null = null; + private closedEarly = false; + + constructor(private opts: HybridSocketOptions) {} + + async start(): Promise { + const direct = this.opts.directWsUrl + ? await this._tryDirect(this.opts.directWsUrl) + : null; + if (this.closedEarly) { + direct?.close(); + return; + } + if (direct) { + this._adopt(direct, "direct"); + this.readyState = 1; + this.onopen?.(); + } else { + const tunnel = this.opts.makeTunnel(); + this._adopt(tunnel, "tunnel"); + tunnel.onopen = () => { + this.readyState = 1; + this.onopen?.(); + }; + void tunnel.start(); + } + } + + send(data: string | ArrayBuffer): void { + if (this.readyState !== 1 || !this.transport) return; + this.transport.send(data); + } + + close(code = 1000): void { + if (this.readyState >= 2) return; + if (!this.transport) { + // Direct attempt still in flight; remember to discard it. + this.closedEarly = true; + this.readyState = 3; + this.onclose?.({ code }); + return; + } + this.readyState = 2; + this.transport.close(code); + } + + private _adopt( + transport: WebSocket | McpTunnelWebSocket, + kind: "direct" | "tunnel", + ): void { + this.transport = transport; + this.transportKind = kind; + this.opts.onTransport?.(kind); + transport.onmessage = (e: { data: string | ArrayBuffer }) => { + this.onmessage?.({ data: e.data }); + }; + transport.onclose = (e: { code: number }) => { + this.readyState = 3; + this.onclose?.({ code: e.code }); + }; + transport.onerror = (e: unknown) => { + this.onerror?.(e); + }; + } + + private _tryDirect(url: string): Promise { + const wsCtor = + this.opts.wsConstructor ?? + (typeof WebSocket !== "undefined" ? WebSocket : undefined); + if (!wsCtor) return Promise.resolve(null); + + return new Promise((resolve) => { + let settled = false; + const settle = (value: WebSocket | null) => { + if (settled) return; + settled = true; + clearTimeout(timer); + resolve(value); + }; + + let ws: WebSocket; + try { + ws = new wsCtor(url); + } catch { + // CSP violations can throw synchronously + resolve(null); + return; + } + ws.binaryType = "arraybuffer"; + const timer = setTimeout(() => { + try { + ws.close(); + } catch { + // ignore + } + settle(null); + }, this.opts.timeoutMs ?? 2500); + + ws.onopen = () => settle(ws); + ws.onerror = () => settle(null); + ws.onclose = () => settle(null); + }); + } +} diff --git a/srcts/src/mcp/index.ts b/srcts/src/mcp/index.ts new file mode 100644 index 0000000000..0ebf487971 --- /dev/null +++ b/srcts/src/mcp/index.ts @@ -0,0 +1,342 @@ +// Entry point for inst/www/shared/shiny-mcp-bridge.js (built by +// `npm run bundle_mcp`; see srcts/build/mcp-bridge.ts). +// +// This script is inlined at the end of in the `ui://shiny/app` +// resource, after shiny.js has created `window.Shiny` but before Shiny's +// DOM-ready initialization runs. It: +// +// 1. starts the MCP Apps handshake with the host (`ui/initialize`); +// 2. synchronously installs `Shiny.createSocket` so that when Shiny +// initializes, its "websocket" is a McpTunnelWebSocket that tunnels +// frames over the host's postMessage channel via app-only tools +// (`_shiny_connect` / `_shiny_send` / `_shiny_receive` / `_shiny_close`); +// 3. replaces `window.XMLHttpRequest` with a tunnel implementation so HTTP +// side channels (uploads, DataTables/selectize, restyles) go through +// `_shiny_http`; +// 4. intercepts download-link clicks and delivers files as blob URLs; +// 5. applies host theme/styles and forwards tool input/results into +// `session$clientData`; +// 6. bridges `session$sendCustomMessage("shiny.mcp.updateModelContext", ...)` +// and `"shiny.mcp.sendMessage"` to the host. + +import type { McpUiHostContext } from "@modelcontextprotocol/ext-apps"; +import { + App, + applyDocumentTheme, + applyHostFonts, + applyHostStyleVariables, +} from "@modelcontextprotocol/ext-apps"; +import { McpHybridWebSocket } from "./hybridSocket"; +import type { ToolCaller } from "./tunnelSocket"; +import { McpTunnelWebSocket } from "./tunnelSocket"; +import { createTunnelXhrClass } from "./tunnelXhr"; + +type ShinyGlobal = { + createSocket?: () => unknown; + setInputValue?: (name: string, value: unknown) => void; + addCustomMessageHandler?: ( + type: string, + handler: (message: unknown) => void, + ) => void; +}; + +function getShiny(): ShinyGlobal | undefined { + // eslint-disable-next-line @typescript-eslint/naming-convention + return (window as unknown as { Shiny?: ShinyGlobal }).Shiny; +} + +// Shiny.setInputValue only exists once Shiny's DOM-ready initialization has +// run; retry briefly so early host notifications aren't dropped. +function setShinyInput(name: string, value: unknown, attempts = 100): void { + const shiny = getShiny(); + if (shiny?.setInputValue) { + shiny.setInputValue(name, value); + return; + } + if (attempts > 0) { + setTimeout(() => setShinyInput(name, value, attempts - 1), 100); + } +} + +function applyHostContext(ctx: Partial | undefined): void { + if (!ctx) return; + if (ctx.theme) applyDocumentTheme(ctx.theme); + if (ctx.styles) { + if (ctx.styles.variables) applyHostStyleVariables(ctx.styles.variables); + if (ctx.styles.css?.fonts) applyHostFonts(ctx.styles.css.fonts); + } +} + +function filenameFromDisposition(disposition: string | null): string { + if (!disposition) return "download"; + const match = /filename="?([^";]+)"?/.exec(disposition); + return match ? match[1] : "download"; +} + +// Intercept clicks on Shiny download links: the sandboxed iframe can't +// navigate to session URLs, so fetch the bytes over the tunnel and hand the +// browser a blob URL instead. (Whether the save dialog is allowed is up to +// the host's sandbox flags, e.g. `allow-downloads`.) +function installDownloadInterceptor(xhrClass: typeof XMLHttpRequest): void { + document.addEventListener( + "click", + (e) => { + const target = e.target as HTMLElement | null; + const link = target?.closest?.( + "a.shiny-download-link", + ) as HTMLAnchorElement | null; + if (!link) return; + const href = link.getAttribute("href"); + if (!href || link.classList.contains("disabled")) return; + + e.preventDefault(); + e.stopPropagation(); + + const xhr = new xhrClass(); + xhr.open("GET", href); + xhr.responseType = "blob"; + xhr.onload = () => { + if (xhr.status !== 200) { + console.warn("shiny-mcp-bridge: download failed:", xhr.status); + return; + } + const filename = filenameFromDisposition( + xhr.getResponseHeader("content-disposition"), + ); + const url = URL.createObjectURL(xhr.response as Blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + a.remove(); + setTimeout(() => URL.revokeObjectURL(url), 60000); + }; + xhr.send(); + }, + true, + ); +} + +type ShinyMcpConfig = { + // Set via options(shiny.mcp.appId=): namespaces the internal `_shiny_*` + // tool names so a gateway can merge several Shiny apps into one server. + appId?: string; + directBase?: string; + displayModes?: Array<"inline" | "fullscreen" | "pip">; +}; + +function getConfig(): ShinyMcpConfig { + return ( + ( + window as unknown as { + // eslint-disable-next-line @typescript-eslint/naming-convention + __shinyMcpConfig__?: ShinyMcpConfig; + } + ).__shinyMcpConfig__ ?? {} + ); +} + +function initShinyMcpBridge(): void { + const shiny = getShiny(); + if (!shiny) { + console.error( + "shiny-mcp-bridge: window.Shiny not found; load shiny.js first.", + ); + return; + } + const config = getConfig(); + + const app = new App( + { + name: "shiny", + version: process.env.SHINY_VERSION ?? "0.0.0", + }, + { + availableDisplayModes: config.displayModes ?? [ + "inline", + "fullscreen", + "pip", + ], + }, + ); + + // Kick off the ui/initialize handshake immediately, but install + // createSocket synchronously: Shiny's DOM-ready init may run before the + // handshake completes, and tool calls must wait for connect() anyway. + const connected = app + .connect() + .then(() => { + applyHostContext(app.getHostContext()); + // Make the initial context available to session$clientData right + // away (mcpHostContext() on the R side). + setShinyInput( + ".clientdata_mcp_host_context", + JSON.stringify(app.getHostContext() ?? {}), + ); + }) + .catch((err) => { + console.error("shiny-mcp-bridge: failed to connect to MCP host:", err); + throw err; + }); + + const callTool: ToolCaller = async (name, args) => { + await connected; + // The server namespaces its internal tools when an appId is set, so a + // multi-app gateway can route each iframe's calls to the right app. + const fullName = + config.appId && name.startsWith("_shiny_") ? config.appId + name : name; + const result = await app.callServerTool({ + name: fullName, + arguments: args, + }); + if (result.isError) { + const content = result.content as + | Array<{ type: string; text?: string }> + | undefined; + const text = content?.find((c) => c.type === "text")?.text; + throw new Error(text ?? "MCP tool call failed: " + name); + } + return (result.structuredContent ?? {}) as { [key: string]: unknown }; + }; + + // Direct-connect fast path: the resource CSP declared the app's origin, + // so try a real WebSocket first and fall back to the tunnel (see + // hybridSocket.ts). The ?mcp=1 marker lets the server treat direct + // sessions as MCP sessions (isMcpSession()). + const directWsUrl = config.directBase + ? config.directBase.replace(/^http/, "ws") + "/websocket/?mcp=1" + : null; + + let socket: McpHybridWebSocket | null = null; + // Resolves with the tunnel connectionId, or "" when connected directly + // (HTTP side channels then call _shiny_http without a connectionId). + let resolveConnection!: (id: string) => void; + const connectionId = new Promise((resolve) => { + resolveConnection = resolve; + }); + + shiny.createSocket = () => { + let tunnel: McpTunnelWebSocket | null = null; + socket = new McpHybridWebSocket({ + directWsUrl, + makeTunnel: () => { + tunnel = new McpTunnelWebSocket(callTool); + return tunnel; + }, + onTransport: (kind) => { + ( + window as unknown as { + // eslint-disable-next-line @typescript-eslint/naming-convention + __shinyMcpTransport__?: string; + } + ).__shinyMcpTransport__ = kind; + console.log("shiny-mcp-bridge: connected via", kind); + if (kind === "direct") { + resolveConnection(""); + } else { + void tunnel?.whenConnected.then(resolveConnection); + } + }, + }); + // shinyapp.ts assigns onopen/onmessage/onclose right after + // createSocket() returns; defer start so they're in place. + const s = socket; + setTimeout(() => void s.start(), 0); + return socket; + }; + + // Tunnel HTTP side channels (uploads, DataTables/selectize ajax, restyle + // XHRs) through _shiny_http; these stay tunneled even for direct-connect + // sessions (cross-origin XHR to the app would require CORS). + const tunnelXhrClass = createTunnelXhrClass({ + callTool, + getConnectionId: () => connectionId, + nativeXhr: window.XMLHttpRequest, + }); + window.XMLHttpRequest = tunnelXhrClass; + installDownloadInterceptor(tunnelXhrClass); + + // Host -> app integration ----------------------------------------------- + + app.onhostcontextchanged = (params) => { + applyHostContext(params); + setShinyInput( + ".clientdata_mcp_host_context", + JSON.stringify(app.getHostContext() ?? {}), + ); + }; + + app.ontoolinput = (params) => { + setShinyInput( + ".clientdata_mcp_tool_input", + JSON.stringify(params.arguments ?? {}), + ); + }; + + app.ontoolresult = (params) => { + setShinyInput(".clientdata_mcp_tool_result", JSON.stringify(params)); + }; + + app.onteardown = () => { + socket?.close(); + return {}; + }; + + // App -> host integration (from R via session$sendCustomMessage) --------- + + const registerCustomHandlers = (attempts = 100): void => { + const s = getShiny(); + if (!s?.addCustomMessageHandler) { + if (attempts > 0) { + setTimeout(() => registerCustomHandlers(attempts - 1), 100); + } + return; + } + s.addCustomMessageHandler("shiny.mcp.updateModelContext", (message) => { + void connected.then(() => + app + .updateModelContext( + message as Parameters[0], + ) + .catch((err) => + console.warn("shiny-mcp-bridge: updateModelContext failed:", err), + ), + ); + }); + s.addCustomMessageHandler("shiny.mcp.sendMessage", (message) => { + void connected.then(() => + app + .sendMessage(message as Parameters[0]) + .catch((err) => + console.warn("shiny-mcp-bridge: sendMessage failed:", err), + ), + ); + }); + s.addCustomMessageHandler("shiny.mcp.requestDisplayMode", (message) => { + void connected.then(() => + app + .requestDisplayMode( + message as Parameters[0], + ) + .then((result) => { + // Reflect the (possibly declined) resulting mode back into + // session$clientData via the merged host context. + setShinyInput( + ".clientdata_mcp_host_context", + JSON.stringify({ + ...(app.getHostContext() ?? {}), + displayMode: result.mode, + }), + ); + }) + .catch((err) => + console.warn("shiny-mcp-bridge: requestDisplayMode failed:", err), + ), + ); + }); + }; + registerCustomHandlers(); +} + +initShinyMcpBridge(); diff --git a/srcts/src/mcp/tunnelSocket.ts b/srcts/src/mcp/tunnelSocket.ts new file mode 100644 index 0000000000..ffa859267b --- /dev/null +++ b/srcts/src/mcp/tunnelSocket.ts @@ -0,0 +1,126 @@ +// A WebSocket-shaped transport that tunnels Shiny's protocol over MCP Apps +// tool calls (postMessage -> host -> MCP server). Shiny's client uses this +// via the `Shiny.createSocket` extension point; it only requires `send()`, +// `close()`, a truthy `readyState` when open, and settable +// `onopen`/`onmessage`/`onclose` (see srcts/src/shiny/shinyapp.ts). +// +// Outbound frames go through the app-only `_shiny_send` tool. Inbound frames +// are pulled by a long-poll loop on `_shiny_receive`; the server resolves the +// call as soon as frames are available (or with an empty batch on timeout), +// and keeping a single receive in flight guarantees frame ordering. + +export type ToolCaller = ( + name: string, + args: { [key: string]: unknown }, +) => Promise<{ [key: string]: unknown }>; + +type Frame = { data: string; binary?: boolean }; +type ReceiveResult = { frames?: Frame[]; closed?: boolean }; + +function b64ToArrayBuffer(b64: string): ArrayBuffer { + const bin = atob(b64); + const bytes = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i); + return bytes.buffer; +} + +function arrayBufferToB64(buf: ArrayBuffer): string { + const bytes = new Uint8Array(buf); + let bin = ""; + for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]); + return btoa(bin); +} + +export class McpTunnelWebSocket { + readyState = 0; // CONNECTING + binaryType = "arraybuffer"; + allowReconnect = false; + + onopen: (() => void) | null = null; + onmessage: ((event: { data: string | ArrayBuffer }) => void) | null = null; + onclose: ((event: { code: number }) => void) | null = null; + onerror: ((event: unknown) => void) | null = null; + + private connectionId: string | null = null; + private resolveConnected!: (id: string) => void; + + // Resolves with the connectionId once the tunnel session is open (used by + // the XHR tunnel, which shares the session's connection). + readonly whenConnected: Promise = new Promise((resolve) => { + this.resolveConnected = resolve; + }); + + constructor(private callTool: ToolCaller) {} + + async start(): Promise { + try { + const result = await this.callTool("_shiny_connect", {}); + this.connectionId = String(result.connectionId); + this.readyState = 1; // OPEN + this.resolveConnected(this.connectionId); + this.onopen?.(); + void this._pollLoop(); + } catch (err) { + this._fail(err); + } + } + + send(data: string | ArrayBuffer): void { + if (this.readyState !== 1 || this.connectionId === null) return; + const frame: Frame = + typeof data === "string" + ? { data, binary: false } + : { data: arrayBufferToB64(data), binary: true }; + this.callTool("_shiny_send", { + connectionId: this.connectionId, + frames: [frame], + }).catch((err) => this._fail(err)); + } + + close(code = 1000): void { + if (this.readyState >= 2) return; + this.readyState = 2; // CLOSING + const id = this.connectionId; + this.connectionId = null; + if (id !== null) { + void this.callTool("_shiny_close", { connectionId: id }).catch(() => { + // Best effort; the server GCs idle connections anyway. + }); + } + this._finishClose(code); + } + + private async _pollLoop(): Promise { + while (this.readyState === 1 && this.connectionId !== null) { + let result: ReceiveResult; + try { + result = (await this.callTool("_shiny_receive", { + connectionId: this.connectionId, + })) as ReceiveResult; + } catch (err) { + this._fail(err); + return; + } + for (const frame of result.frames ?? []) { + if (this.readyState !== 1) break; + const data = frame.binary ? b64ToArrayBuffer(frame.data) : frame.data; + this.onmessage?.({ data }); + } + if (result.closed) { + this._finishClose(1000); + return; + } + } + } + + private _fail(err: unknown): void { + this.onerror?.(err); + this._finishClose(1006); + } + + private _finishClose(code: number): void { + if (this.readyState === 3) return; + this.readyState = 3; // CLOSED + this.onclose?.({ code }); + } +} diff --git a/srcts/src/mcp/tunnelXhr.ts b/srcts/src/mcp/tunnelXhr.ts new file mode 100644 index 0000000000..9187d465d0 --- /dev/null +++ b/srcts/src/mcp/tunnelXhr.ts @@ -0,0 +1,300 @@ +// An XMLHttpRequest replacement for the MCP Apps sandbox: same-origin and +// relative requests are tunneled through the app-only `_shiny_http` tool +// (postMessage -> host -> MCP server -> in-process Shiny handlers). This +// covers every HTTP side channel in the Shiny client without touching +// shiny.js itself: jQuery.ajax (file upload POSTs, DataTables/selectize +// requests) creates its XHR via `new window.XMLHttpRequest()` per request, +// and render.ts's restyle fetch uses raw XHR. +// +// Only the XHR surface those callers use is implemented. Foreign-origin +// absolute URLs are delegated to the native XHR (the sandbox CSP decides +// their fate, same as without the patch). + +import type { ToolCaller } from "./tunnelSocket"; + +export interface TunnelXhrOptions { + callTool: ToolCaller; + getConnectionId: () => Promise; + // Origin whose absolute URLs are treated as same-origin (defaults to + // window.location.origin when available). + pageOrigin?: string; + nativeXhr?: typeof XMLHttpRequest; +} + +type HttpToolResult = { + status?: number; + headers?: { [key: string]: unknown }; + body?: string; // base64 +}; + +function b64ToBytes(b64: string): Uint8Array { + const bin = atob(b64); + const bytes = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i); + return bytes; +} + +function bytesToB64(bytes: Uint8Array): string { + let bin = ""; + for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]); + return btoa(bin); +} + +async function encodeBody( + body: unknown, +): Promise<{ b64: string | null; error?: string }> { + if (body === null || body === undefined) return { b64: null }; + if (typeof body === "string") { + return { b64: bytesToB64(new TextEncoder().encode(body)) }; + } + if (body instanceof ArrayBuffer) { + return { b64: bytesToB64(new Uint8Array(body)) }; + } + if (ArrayBuffer.isView(body)) { + const view = body as ArrayBufferView; + return { + b64: bytesToB64( + new Uint8Array(view.buffer, view.byteOffset, view.byteLength), + ), + }; + } + if (typeof Blob !== "undefined" && body instanceof Blob) { + const buf = await body.arrayBuffer(); + return { b64: bytesToB64(new Uint8Array(buf)) }; + } + return { b64: null, error: "Unsupported request body type for MCP tunnel" }; +} + +function statusText(status: number): string { + const texts = new Map([ + [200, "OK"], + [202, "Accepted"], + [204, "No Content"], + [302, "Found"], + [400, "Bad Request"], + [403, "Forbidden"], + [404, "Not Found"], + [405, "Method Not Allowed"], + [500, "Internal Server Error"], + ]); + return texts.get(status) ?? ""; +} + +export function createTunnelXhrClass( + opts: TunnelXhrOptions, +): typeof XMLHttpRequest { + const pageOrigin = + opts.pageOrigin ?? + (typeof window !== "undefined" ? window.location.origin : "null"); + const nativeXhrClass = + opts.nativeXhr ?? + (typeof XMLHttpRequest !== "undefined" ? XMLHttpRequest : undefined); + + class TunnelXMLHttpRequest { + readyState = 0; + status = 0; + statusText = ""; + responseText = ""; + response: unknown = ""; + responseType = ""; + responseURL = ""; + timeout = 0; + withCredentials = false; + // fileProcessor.ts guards `if (xhr.upload)` before assigning onprogress; + // tunneled uploads complete without incremental progress events. + upload: { onprogress: ((e: unknown) => void) | null } = { + onprogress: null, + }; + + onreadystatechange: (() => void) | null = null; + onload: (() => void) | null = null; + onerror: (() => void) | null = null; + onabort: (() => void) | null = null; + ontimeout: (() => void) | null = null; + + private reqMethod = "GET"; + private reqUrl = ""; + private tunnelPath: string | null = null; + private reqHeaders: { [key: string]: string } = {}; + private respHeaders: { [key: string]: string } = {}; + private aborted = false; + private nativeReq: XMLHttpRequest | null = null; + + open(method: string, url: string): void { + this.reqMethod = method.toUpperCase(); + this.reqUrl = url; + this.tunnelPath = this._classify(url); + this.readyState = 1; + } + + setRequestHeader(name: string, value: string): void { + this.reqHeaders[name] = value; + } + + overrideMimeType(): void { + // Not needed for tunneled responses. + } + + getResponseHeader(name: string): string | null { + return this.respHeaders[name.toLowerCase()] ?? null; + } + + getAllResponseHeaders(): string { + return Object.entries(this.respHeaders) + .map(([k, v]) => `${k}: ${v}\r\n`) + .join(""); + } + + abort(): void { + this.aborted = true; + this.nativeReq?.abort(); + if (this.readyState !== 4) { + this.readyState = 4; + this.onabort?.(); + } + } + + send(body?: unknown): void { + if (this.tunnelPath === null) { + this._delegateToNative(body); + return; + } + void this._sendTunneled(body); + } + + private _classify(url: string): string | null { + let parsed: URL; + try { + parsed = new URL(url, "http://tunnel.invalid"); + } catch { + return null; + } + if (parsed.origin === "http://tunnel.invalid") { + // Relative URL + const path = parsed.pathname + parsed.search; + return path.startsWith("/") ? path : "/" + path; + } + if (parsed.origin === pageOrigin) { + return parsed.pathname + parsed.search; + } + return null; + } + + private async _sendTunneled(body: unknown): Promise { + try { + const encoded = await encodeBody(body); + if (encoded.error) throw new Error(encoded.error); + const connectionId = await opts.getConnectionId(); + const args: { [key: string]: unknown } = { + method: this.reqMethod, + path: this.tunnelPath, + headers: this.reqHeaders, + }; + // Empty id = direct-connect session (no tunnel connection to tie to) + if (connectionId) args.connectionId = connectionId; + if (encoded.b64 !== null) args.body = encoded.b64; + + const result = (await opts.callTool( + "_shiny_http", + args, + )) as HttpToolResult; + if (this.aborted) return; + + this.status = result.status ?? 0; + this.statusText = statusText(this.status); + this.respHeaders = {}; + for (const [k, v] of Object.entries(result.headers ?? {})) { + this.respHeaders[k.toLowerCase()] = String(v); + } + + const bytes = result.body ? b64ToBytes(result.body) : new Uint8Array(0); + this._setResponse(bytes); + this.readyState = 4; + this.onreadystatechange?.(); + this.onload?.(); + } catch (err) { + if (this.aborted) return; + this.status = 0; + this.readyState = 4; + this.onreadystatechange?.(); + this.onerror?.(); + console.warn("shiny-mcp-bridge: tunneled XHR failed:", err); + } + } + + private _setResponse(bytes: Uint8Array): void { + const contentType = this.respHeaders["content-type"] ?? ""; + switch (this.responseType) { + case "arraybuffer": + this.response = bytes.buffer.slice( + bytes.byteOffset, + bytes.byteOffset + bytes.byteLength, + ); + break; + case "blob": + this.response = new Blob([bytes], { type: contentType }); + break; + case "json": { + const text = new TextDecoder().decode(bytes); + try { + this.response = JSON.parse(text); + } catch { + this.response = null; + } + break; + } + default: { + const text = new TextDecoder().decode(bytes); + this.responseText = text; + this.response = text; + } + } + } + + private _delegateToNative(body: unknown): void { + if (!nativeXhrClass) { + this.status = 0; + this.readyState = 4; + this.onerror?.(); + return; + } + const native = new nativeXhrClass(); + this.nativeReq = native; + native.open(this.reqMethod, this.reqUrl, true); + for (const [k, v] of Object.entries(this.reqHeaders)) { + native.setRequestHeader(k, v); + } + if (this.responseType) { + native.responseType = this.responseType as XMLHttpRequestResponseType; + } + native.onreadystatechange = () => { + this.readyState = native.readyState; + if (native.readyState === 4) { + this.status = native.status; + this.statusText = native.statusText; + this.response = native.response; + if (!this.responseType || this.responseType === "text") { + this.responseText = native.responseText; + } + this.respHeaders = {}; + for (const line of native.getAllResponseHeaders().split("\r\n")) { + const idx = line.indexOf(": "); + if (idx > 0) { + this.respHeaders[line.slice(0, idx).toLowerCase()] = line.slice( + idx + 2, + ); + } + } + } + this.onreadystatechange?.(); + }; + native.onload = () => this.onload?.(); + native.onerror = () => this.onerror?.(); + native.onabort = () => this.onabort?.(); + native.ontimeout = () => this.ontimeout?.(); + native.send(body as XMLHttpRequestBodyInit | null | undefined); + } + } + + return TunnelXMLHttpRequest as unknown as typeof XMLHttpRequest; +} diff --git a/srcts/types/build/mcp-bridge.d.ts b/srcts/types/build/mcp-bridge.d.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/srcts/types/build/mcp-bridge.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/srcts/types/src/mcp/hybridSocket.d.ts b/srcts/types/src/mcp/hybridSocket.d.ts new file mode 100644 index 0000000000..fd4c088f41 --- /dev/null +++ b/srcts/types/src/mcp/hybridSocket.d.ts @@ -0,0 +1,42 @@ +import type { McpTunnelWebSocket } from "./tunnelSocket"; +type SocketEvents = { + onopen: (() => void) | null; + onmessage: ((event: { + data: string | ArrayBuffer; + }) => void) | null; + onclose: ((event: { + code: number; + }) => void) | null; + onerror: ((event: unknown) => void) | null; +}; +export interface HybridSocketOptions { + directWsUrl: string | null; + makeTunnel: () => McpTunnelWebSocket; + timeoutMs?: number; + wsConstructor?: typeof WebSocket; + onTransport?: (kind: "direct" | "tunnel") => void; +} +export declare class McpHybridWebSocket implements SocketEvents { + private opts; + readyState: number; + binaryType: string; + allowReconnect: boolean; + transportKind: "pending" | "direct" | "tunnel"; + onopen: (() => void) | null; + onmessage: ((event: { + data: string | ArrayBuffer; + }) => void) | null; + onclose: ((event: { + code: number; + }) => void) | null; + onerror: ((event: unknown) => void) | null; + private transport; + private closedEarly; + constructor(opts: HybridSocketOptions); + start(): Promise; + send(data: string | ArrayBuffer): void; + close(code?: number): void; + private _adopt; + private _tryDirect; +} +export {}; diff --git a/srcts/types/src/mcp/index.d.ts b/srcts/types/src/mcp/index.d.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/srcts/types/src/mcp/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/srcts/types/src/mcp/tunnelSocket.d.ts b/srcts/types/src/mcp/tunnelSocket.d.ts new file mode 100644 index 0000000000..aa356922b1 --- /dev/null +++ b/srcts/types/src/mcp/tunnelSocket.d.ts @@ -0,0 +1,29 @@ +export type ToolCaller = (name: string, args: { + [key: string]: unknown; +}) => Promise<{ + [key: string]: unknown; +}>; +export declare class McpTunnelWebSocket { + private callTool; + readyState: number; + binaryType: string; + allowReconnect: boolean; + onopen: (() => void) | null; + onmessage: ((event: { + data: string | ArrayBuffer; + }) => void) | null; + onclose: ((event: { + code: number; + }) => void) | null; + onerror: ((event: unknown) => void) | null; + private connectionId; + private resolveConnected; + readonly whenConnected: Promise; + constructor(callTool: ToolCaller); + start(): Promise; + send(data: string | ArrayBuffer): void; + close(code?: number): void; + private _pollLoop; + private _fail; + private _finishClose; +} diff --git a/srcts/types/src/mcp/tunnelXhr.d.ts b/srcts/types/src/mcp/tunnelXhr.d.ts new file mode 100644 index 0000000000..67a4db5f3a --- /dev/null +++ b/srcts/types/src/mcp/tunnelXhr.d.ts @@ -0,0 +1,8 @@ +import type { ToolCaller } from "./tunnelSocket"; +export interface TunnelXhrOptions { + callTool: ToolCaller; + getConnectionId: () => Promise; + pageOrigin?: string; + nativeXhr?: typeof XMLHttpRequest; +} +export declare function createTunnelXhrClass(opts: TunnelXhrOptions): typeof XMLHttpRequest; diff --git a/tests/testthat/helper-mcp.R b/tests/testthat/helper-mcp.R new file mode 100644 index 0000000000..35a00c2f4f --- /dev/null +++ b/tests/testthat/helper-mcp.R @@ -0,0 +1,62 @@ +# Helpers for MCP Apps tests (test-mcp-*.R) + +fakeRookInput <- function(bytes) { + list(read = function(...) bytes, rewind = function() NULL) +} + +mcp_req <- function(body, method = "POST", path = "/mcp") { + req <- new.env(parent = emptyenv()) + req$REQUEST_METHOD <- method + req$PATH_INFO <- path + req$QUERY_STRING <- "" + req$HTTP_HOST <- "127.0.0.1" + if (!is.null(body)) { + json <- jsonlite::toJSON(body, auto_unbox = TRUE, null = "null") + req$rook.input <- fakeRookInput(charToRaw(json)) + } + req +} + +as_bytes <- function(x) if (is.raw(x)) x else charToRaw(enc2utf8(x)) + +wait_for_result <- function(x, timeout = 5) { + if (!promises::is.promising(x)) return(x) + result <- NULL + done <- FALSE + err <- NULL + promises::then( + x, + onFulfilled = function(value) { + result <<- value + done <<- TRUE + }, + onRejected = function(e) { + err <<- e + done <<- TRUE + } + ) + end <- Sys.time() + timeout + while (!done && Sys.time() < end) later::run_now(0.05) + if (!done) stop("timed out waiting for promise") + if (!is.null(err)) stop(err) + result +} + +mcp_post <- function(handler, method, params = NULL, id = 1) { + body <- list(jsonrpc = "2.0", id = id, method = method) + if (!is.null(params)) body$params <- params + resp <- wait_for_result(handler(mcp_req(body))) + expect_s3_class(resp, "httpResponse") + jsonlite::parse_json(rawToChar(as_bytes(resp$content))) +} + +# Replicates one iteration of serviceApp() without blocking on httpuv +pump_shiny <- function(seconds = 0.1) { + end <- Sys.time() + seconds + while (Sys.time() < end) { + timerCallbacks$executeElapsed() + flushReact() + flushPendingSessions() + later::run_now(0.02) + } +} diff --git a/tests/testthat/test-mcp-app.R b/tests/testthat/test-mcp-app.R new file mode 100644 index 0000000000..cc582dfffa --- /dev/null +++ b/tests/testthat/test-mcp-app.R @@ -0,0 +1,308 @@ +test_that("resources/list and resources/read serve a self-contained app page", { + ui <- fluidPage( + sliderInput("n", "N", 1, 10, 5), + plotOutput("p") + ) + app <- shinyApp(ui, function(input, output) {}) + withr::with_options(list(shiny.mcp = TRUE), { + handlers <- createAppHandlers( + app$httpHandler, + function() function(input, output) {} + ) + h <- handlers$http + + out <- mcp_post(h, "resources/list") + res <- out$result$resources[[1]] + expect_equal(res$uri, "ui://shiny/app") + expect_equal(res$mimeType, "text/html;profile=mcp-app") + + out <- mcp_post(h, "resources/read", params = list(uri = "ui://shiny/app")) + content <- out$result$contents[[1]] + expect_equal(content$mimeType, "text/html;profile=mcp-app") + html <- content$text + + # All scripts and stylesheets inlined: no external file refs remain + expect_false(grepl("]+src=", html)) + expect_false(grepl("]+href=", html)) + # Bridge script injected + expect_match(html, "shiny-mcp-bridge", fixed = TRUE) + # App UI present + expect_match(html, "sliderInput|shiny-plot-output|slider") + # jquery + shiny.js payloads inlined + expect_match(html, "jQuery", fixed = TRUE) + + out <- mcp_post(h, "resources/read", params = list(uri = "ui://nope")) + expect_equal(out$error$code, -32602L) + }) +}) + +test_that("resolveAssetFile maps registered resource paths and shared dir", { + # createWebDependency() registers e.g. jquery- -> local dir + jq <- resolveAssetFile("shared/jquery.min.js") + skip_if(is.null(jq)) # only if shared assets aren't installed + expect_true(file.exists(jq)) + + expect_null(resolveAssetFile("nonexistent-prefix/some.js")) + expect_null(resolveAssetFile("noslash")) +}) + +test_that("escapeScriptContent defuses closing script tags", { + expect_equal( + escapeScriptContent('var a = "";'), + 'var a = "<\\/script>";' + ) +}) + +test_that("mcpInlineDependency inlines file-based scripts and stylesheets", { + dir <- withr::local_tempdir() + writeLines("window.__mcp_test__ = 1;", file.path(dir, "dep.js")) + writeLines(".mcp-test { color: red; }", file.path(dir, "dep.css")) + dep <- htmltools::htmlDependency( + "mcptestdep", "1.0", + src = c(file = dir), + script = "dep.js", + stylesheet = "dep.css", + head = "" + ) + + inlined <- mcpInlineDependency(dep) + expect_null(inlined$script) + expect_null(inlined$stylesheet) + expect_match(inlined$head, "window.__mcp_test__ = 1;", fixed = TRUE) + expect_match(inlined$head, ".mcp-test { color: red; }", fixed = TRUE) + expect_match(inlined$head, "window.__mcp_head__ = 1;", fixed = TRUE) + expect_null(inlined$src$file) + + # href-only dependencies fall back to createWebDependency behavior + href_dep <- htmltools::htmlDependency( + "mcphrefdep", "1.0", + src = c(href = "https://example.com/lib"), + script = "lib.js" + ) + passthrough <- mcpInlineDependency(href_dep) + expect_equal(passthrough$src$href, "https://example.com/lib") +}) + +test_that("processDeps inlines dependencies for MCP tunnel sessions", { + dir <- withr::local_tempdir() + writeLines("window.__mcp_dyn__ = 1;", file.path(dir, "dyn.js")) + dep <- htmltools::htmlDependency( + "mcpdyndep", "1.0", + src = c(file = dir), + script = "dyn.js" + ) + tag <- htmltools::attachDependencies(htmltools::div("hi"), dep) + + ui <- fluidPage(textOutput("out")) + server <- function(input, output) {} + app <- shinyApp(ui, server) + handlers <- createAppHandlers(app$httpHandler, function() server) + con_res <- mcpTunnelToolCall("_shiny_connect", empty_named_list(), 1, handlers$ws) + cid <- con_res$result$structuredContent$connectionId + session <- appsByToken$values()[[length(appsByToken$values())]] + expect_true(isMcpSession(session)) + + res <- processDeps(tag, session) + dyn <- Filter(function(d) d$name == "mcpdyndep", res$deps)[[1]] + expect_match(dyn$head, "window.__mcp_dyn__ = 1;", fixed = TRUE) + expect_null(dyn$script) + + mcpTunnelToolCall("_shiny_close", list(connectionId = cid), 2, handlers$ws) +}) + +test_that("processDeps is unchanged for regular sessions", { + session <- MockShinySession$new() + expect_false(isMcpSession(session)) +}) + +test_that("rewriteCssUrls inlines local url() refs and leaves the rest", { + dir <- withr::local_tempdir() + dir.create(file.path(dir, "css")) + dir.create(file.path(dir, "webfonts")) + writeBin(as.raw(c(0x77, 0x4F, 0x46, 0x32)), file.path(dir, "webfonts", "fa.woff2")) + writeBin(as.raw(1:4), file.path(dir, "css", "img.png")) + + css <- paste( + "@font-face { src: url(../webfonts/fa.woff2?v=6.4#frag) format('woff2'); }", + ".a { background: url('img.png'); }", + ".b { background: url(\"data:image/png;base64,AAAA\"); }", + ".c { fill: url(#gradient); }", + ".d { background: url(https://example.com/x.png); }", + ".e { background: url(missing.png); }", + sep = "\n" + ) + out <- rewriteCssUrls(css, file.path(dir, "css")) + + # Local files (including ../ paths with query/fragment) become data: URIs + expect_match(out, "url\\(\"data:font/woff2;base64,d09GMg==\"\\)") + expect_match(out, "url\\(\"data:image/png;base64,AQIDBA==\"\\)") + # data:, fragment-only, absolute, and missing refs are untouched + expect_match(out, "url(\"data:image/png;base64,AAAA\")", fixed = TRUE) + expect_match(out, "url(#gradient)", fixed = TRUE) + expect_match(out, "url(https://example.com/x.png)", fixed = TRUE) + expect_match(out, "url(missing.png)", fixed = TRUE) +}) + +test_that("stylesheet inlining rewrites url() refs (page + dynamic deps)", { + dir <- withr::local_tempdir() + dir.create(file.path(dir, "fonts")) + writeBin(as.raw(c(0x77, 0x4F, 0x46, 0x32)), file.path(dir, "fonts", "f.woff2")) + writeBin(as.raw(c(0x00, 0x01, 0x00, 0x00)), file.path(dir, "fonts", "f.ttf")) + writeLines( + paste0( + "@font-face { font-family: x; ", + "src: url(fonts/f.woff2) format('woff2'), ", + "url(fonts/f.ttf) format('truetype'); }" + ), + file.path(dir, "style.css") + ) + dep <- htmltools::htmlDependency( + "mcpfontdep", "1.0", + src = c(file = dir), + stylesheet = "style.css" + ) + + inlined <- mcpInlineDependency(dep) + expect_match(inlined$head, "data:font/woff2;base64,d09GMg==", fixed = TRUE) + expect_false(grepl("url(fonts/f.woff2)", inlined$head, fixed = TRUE)) + # Legacy fallback formats are left alone (never fetched once woff2 loads) + expect_match(inlined$head, "url(fonts/f.ttf)", fixed = TRUE) +}) + +test_that("resources/read inlines fontawesome webfonts for icon() apps", { + ui <- fluidPage(downloadButton("dl", "Get")) + app <- shinyApp(ui, function(input, output) {}) + withr::with_options(list(shiny.mcp = TRUE), { + handlers <- createAppHandlers( + app$httpHandler, + function() function(input, output) {} + ) + out <- mcp_post(handlers$http, "resources/read", + params = list(uri = "ui://shiny/app") + ) + html <- out$result$contents[[1]]$text + # The fontawesome stylesheet references ../webfonts/*.woff2; those must + # now be data: URIs rather than unreachable relative URLs. (Legacy .ttf + # fallback refs stay as-is; browsers never fetch them once woff2 loads.) + expect_match(html, "data:font/woff2;base64,") + expect_false(grepl("url\\([\"']?\\.\\./webfonts/[^)\"']*\\.woff2", html)) + }) +}) + +test_that("rewriteCssUrls produces single-line data URIs for large files", { + dir <- withr::local_tempdir() + writeBin(as.raw(rep(1:255, 40)), file.path(dir, "big.woff2")) + out <- rewriteCssUrls("a { src: url(big.woff2); }", dir) + expect_match(out, "data:font/woff2;base64,") + expect_false(grepl("[\r\n]", out)) +}) + +test_that("resources/read declares connectDomains derived from the request", { + ui <- fluidPage("hi") + app <- shinyApp(ui, function(input, output) {}) + withr::with_options(list(shiny.mcp = TRUE), { + handlers <- createAppHandlers( + app$httpHandler, + function() function(input, output) {} + ) + h <- handlers$http + + req <- mcp_req(list( + jsonrpc = "2.0", id = 1, method = "resources/read", + params = list(uri = "ui://shiny/app") + )) + req$HTTP_HOST <- "myapp.example.com" + req$HTTP_X_FORWARDED_PROTO <- "https" + out <- jsonlite::parse_json(rawToChar(as_bytes(wait_for_result(h(req))$content))) + csp <- out$result$contents[[1]]$`_meta`$ui$csp + domains <- unlist(csp$connectDomains) + expect_true("https://myapp.example.com" %in% domains) + expect_true("wss://myapp.example.com" %in% domains) + + # Plain http host -> ws scheme + req2 <- mcp_req(list( + jsonrpc = "2.0", id = 2, method = "resources/read", + params = list(uri = "ui://shiny/app") + )) + req2$HTTP_HOST <- "127.0.0.1:7788" + out2 <- jsonlite::parse_json(rawToChar(as_bytes(wait_for_result(h(req2))$content))) + domains2 <- unlist(out2$result$contents[[1]]$`_meta`$ui$csp$connectDomains) + expect_true(all(c("http://127.0.0.1:7788", "ws://127.0.0.1:7788") %in% domains2)) + + # Config injected into the page for the bridge + html <- out2$result$contents[[1]]$text + expect_match(html, "__shinyMcpConfig__", fixed = TRUE) + expect_match(html, '"directBase":"http://127.0.0.1:7788"', fixed = TRUE) + }) +}) + +test_that("shiny.mcp.direct = FALSE omits CSP and directOrigin", { + ui <- fluidPage("hi") + app <- shinyApp(ui, function(input, output) {}) + withr::with_options(list(shiny.mcp = TRUE, shiny.mcp.direct = FALSE), { + handlers <- createAppHandlers( + app$httpHandler, + function() function(input, output) {} + ) + req <- mcp_req(list( + jsonrpc = "2.0", id = 1, method = "resources/read", + params = list(uri = "ui://shiny/app") + )) + req$HTTP_HOST <- "127.0.0.1:7788" + out <- jsonlite::parse_json(rawToChar(as_bytes(wait_for_result(handlers$http(req))$content))) + expect_null(out$result$contents[[1]]$`_meta`$ui$csp) + # The injected config object must not carry a directOrigin (the bridge + # bundle source mentions the name, so scope the check to the config) + html <- out$result$contents[[1]]$text + config_json <- regmatches( + html, + regexpr("__shinyMcpConfig__ = \\{[^;]*", html) + ) + expect_length(config_json, 1) + expect_false(grepl('"directBase"', config_json, fixed = TRUE)) + }) +}) + +test_that("isMcpSession recognizes direct websocket connections via ?mcp=1", { + req <- new.env(parent = emptyenv()) + req$QUERY_STRING <- "?mcp=1" + fake_session <- list(request = req) + expect_true(isMcpSession(fake_session)) + + req2 <- new.env(parent = emptyenv()) + req2$QUERY_STRING <- "" + expect_false(isMcpSession(list(request = req2))) +}) + +test_that("createWebDependency inlines file-based deps for MCP sessions", { + dir <- withr::local_tempdir() + writeLines("console.log('widget');", file.path(dir, "w.js")) + writeLines(".w { color: red; }", file.path(dir, "w.css")) + dep <- htmltools::htmlDependency( + "testwidget", "1.0", + src = c(file = dir), + script = "w.js", stylesheet = "w.css" + ) + + # Outside an MCP session: normal resource-path behavior + plain <- createWebDependency(dep) + expect_equal(plain$src$href, "testwidget-1.0") + + # Inside an MCP session (e.g. {htmlwidgets} calling it directly for + # render-time deps): diverted to the inline representation + req <- new.env(parent = emptyenv()) + req$HTTP_MCP_TUNNEL <- "1" + fake_session <- list(request = req) + inlined <- withReactiveDomain(fake_session, createWebDependency(dep)) + expect_equal(inlined$src$href, "_mcp_inline") + expect_match(inlined$head, "console.log('widget');", fixed = TRUE) + expect_match(inlined$head, ".w { color: red; }", fixed = TRUE) + + # href-only deps fall through untouched (no infinite recursion) + href_dep <- htmltools::htmlDependency( + "cdn", "1.0", + src = c(href = "https://cdn.example.com"), script = "x.js" + ) + passed <- withReactiveDomain(fake_session, createWebDependency(href_dep)) + expect_equal(passed$src$href, "https://cdn.example.com") +}) diff --git a/tests/testthat/test-mcp-server.R b/tests/testthat/test-mcp-server.R new file mode 100644 index 0000000000..1e6499c14a --- /dev/null +++ b/tests/testthat/test-mcp-server.R @@ -0,0 +1,373 @@ +test_that("mcpHttpHandler ignores other paths and handles OPTIONS/GET", { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + expect_null(h(mcp_req(NULL, method = "GET", path = "/other"))) + + opts <- h(mcp_req(NULL, method = "OPTIONS")) + expect_equal(opts$status, 204L) + expect_equal(opts$headers[["Access-Control-Allow-Origin"]], "*") + + get <- h(mcp_req(NULL, method = "GET")) + expect_equal(get$status, 405L) +}) + +test_that("initialize negotiates protocol version", { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + + out <- mcp_post( + h, "initialize", + params = list(protocolVersion = "2025-06-18", capabilities = empty_named_list()) + ) + expect_equal(out$result$protocolVersion, "2025-06-18") + expect_equal(out$result$serverInfo$name, "shiny") + expect_true(is.list(out$result$capabilities$tools)) + + out2 <- mcp_post( + h, "initialize", + params = list(protocolVersion = "9999-01-01", capabilities = empty_named_list()) + ) + expect_equal(out2$result$protocolVersion, "2025-06-18") +}) + +test_that("notifications get 202, unknown methods get -32601, ping works", { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + + notif <- h(mcp_req(list(jsonrpc = "2.0", method = "notifications/initialized"))) + expect_equal(notif$status, 202L) + + out <- mcp_post(h, "bogus/method") + expect_equal(out$error$code, -32601L) + + out <- mcp_post(h, "ping") + expect_true(is.list(out$result)) + expect_length(out$result, 0) +}) + +test_that("invalid JSON gets a parse error", { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + req <- mcp_req(NULL) + req$rook.input <- fakeRookInput(charToRaw("not json")) + resp <- h(req) + expect_equal(resp$status, 400L) + out <- jsonlite::parse_json(rawToChar(as_bytes(resp$content))) + expect_equal(out$error$code, -32700L) +}) + +test_that("tools/list includes the visible app tool with ui metadata", { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + out <- mcp_post(h, "tools/list") + tools <- out$result$tools + tool_names <- vapply(tools, function(t) t$name, character(1)) + expect_true("open_shiny_app" %in% tool_names) + app_tool <- tools[[which(tool_names == "open_shiny_app")]] + expect_equal(app_tool$`_meta`$ui$resourceUri, "ui://shiny/app") +}) + +test_that("tool name and description are configurable", { + withr::with_options( + list(shiny.mcp.tool = list(name = "show_dashboard", description = "Show it")), + { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + out <- mcp_post(h, "tools/list") + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true("show_dashboard" %in% tool_names) + + called <- mcp_post(h, "tools/call", + params = list(name = "show_dashboard", arguments = empty_named_list()) + ) + expect_match(called$result$content[[1]]$text, "displayed") + } + ) +}) + +test_that("createAppHandlers mounts /mcp only when enabled", { + ui <- fluidPage("hello mcp") + app <- shinyApp(ui, function(input, output) {}) + make_handler <- function() { + h <- createAppHandlers(app$httpHandler, function() function(input, output) {}) + h$http + } + withr::with_options(list(shiny.mcp = TRUE), { + resp <- wait_for_result(make_handler()(mcp_req( + list(jsonrpc = "2.0", id = 1, method = "ping") + ))) + expect_equal(resp$status, 200L) + }) + withr::with_options(list(shiny.mcp = FALSE), { + expect_null(make_handler()(mcp_req( + list(jsonrpc = "2.0", id = 1, method = "ping") + ))) + }) +}) + +test_that("author-declared tools appear in tools/list and execute", { + tools <- list( + list( + name = "add_numbers", + description = "Add two numbers.", + inputSchema = list( + type = "object", + properties = list( + x = list(type = "number"), + y = list(type = "number") + ), + required = list("x", "y") + ), + handler = function(args) { + list(sum = args$x + args$y) + } + ), + list( + name = "get_motd", + description = "Get the message of the day.", + handler = function(args) "Hello from R" + ) + ) + withr::with_options(list(shiny.mcp.tools = tools), { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + + out <- mcp_post(h, "tools/list") + # tools must serialize as a JSON array, not an object + expect_null(names(out$result$tools)) + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true(all(c("add_numbers", "get_motd") %in% tool_names)) + add_tool <- out$result$tools[[which(tool_names == "add_numbers")]] + expect_equal(add_tool$inputSchema$properties$x$type, "number") + # Author tools are model-visible (no app-only visibility marker) + expect_null(add_tool$`_meta`$ui$visibility) + + res <- mcp_post(h, "tools/call", params = list( + name = "add_numbers", arguments = list(x = 2, y = 40) + )) + expect_equal(res$result$structuredContent$sum, 42) + expect_match(res$result$content[[1]]$text, "42") + + res <- mcp_post(h, "tools/call", params = list( + name = "get_motd", arguments = empty_named_list() + )) + expect_equal(res$result$content[[1]]$text, "Hello from R") + expect_null(res$result$structuredContent) + }) +}) + +test_that("author tool errors become isError results, not crashes", { + tools <- list(list( + name = "boom", + description = "Always fails.", + handler = function(args) stop("kaboom: ", args$why) + )) + withr::with_options(list(shiny.mcp.tools = tools), { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + res <- mcp_post(h, "tools/call", params = list( + name = "boom", arguments = list(why = "testing") + )) + expect_true(isTRUE(res$result$isError)) + expect_match(res$result$content[[1]]$text, "kaboom: testing") + }) +}) + +test_that("async author tools (promises) are supported", { + tools <- list(list( + name = "slow_answer", + description = "Answers later.", + handler = function(args) { + promises::promise(function(resolve, reject) { + later::later(function() resolve(list(answer = 42)), 0.1) + }) + } + )) + withr::with_options(list(shiny.mcp.tools = tools), { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + res <- mcp_post(h, "tools/call", params = list( + name = "slow_answer", arguments = empty_named_list() + )) + expect_equal(res$result$structuredContent$answer, 42) + }) +}) + +test_that("invalid or colliding author tools are skipped with a warning", { + tools <- list( + list(name = "_shiny_send", description = "collides", handler = function(args) 1), + list(name = "no_handler", description = "missing handler"), + list(name = "ok_tool", description = "fine", handler = function(args) "ok") + ) + withr::with_options(list(shiny.mcp.tools = tools), { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + warnings <- testthat::capture_warnings(out <- mcp_post(h, "tools/list")) + expect_length(warnings, 2) + expect_match(warnings, "_shiny_send|no_handler", all = TRUE) + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true("ok_tool" %in% tool_names) + expect_false("no_handler" %in% tool_names) + # the colliding name resolves to the built-in tunnel tool, not the author's + expect_equal(sum(tool_names == "_shiny_send"), 1) + }) +}) + +test_that("mcpDirectBase honors option > Connect headers > request origin", { + req <- new.env(parent = emptyenv()) + req$HTTP_HOST <- "connect.example.com" + req$HTTP_X_FORWARDED_PROTO <- "https" + + # Request-derived origin (no path information) + expect_equal(mcpDirectBase(req), "https://connect.example.com") + + # shinyapps.io sends external host + path (schemeless) in + # X-Redx-Frontend-Name + req$HTTP_X_REDX_FRONTEND_NAME <- "barret.shinyapps.io/my-app/" + expect_equal(mcpDirectBase(req), "https://barret.shinyapps.io/my-app") + + # Connect forwards the full external URL of the request (API content) + req$HTTP_X_RSC_REQUEST <- "https://connect.example.com/content/abc123/mcp" + expect_equal(mcpDirectBase(req), "https://connect.example.com/content/abc123") + + # Connect sends the app's base URL with every request to Shiny content; + # it wins over everything but the option (needs no path surgery) + req$HTTP_RSTUDIO_CONNECT_APP_BASE_URL <- + "https://connect.example.com/content/def456/" + expect_equal(mcpDirectBase(req), "https://connect.example.com/content/def456") + + # Explicit option wins over everything, trailing slash normalized + withr::with_options( + list(shiny.mcp.origin = "https://other.example.com/apps/dash/"), + expect_equal(mcpDirectBase(req), "https://other.example.com/apps/dash") + ) +}) + +test_that("shiny.mcp.appId namespaces internal tools and the resource", { + withr::local_options(list(shiny.mcp.appId = "sales")) + + expect_equal(mcpResourceUri(), "ui://shiny/sales") + expect_equal(mcpTunnelToolName("_shiny_connect"), "sales_shiny_connect") + expect_equal(mcpTunnelLocalName("sales_shiny_http"), "_shiny_http") + # names that don't carry the prefix pass through unchanged + expect_equal(mcpTunnelLocalName("_shiny_http"), "_shiny_http") + expect_equal(mcpTunnelLocalName("sales_tool"), "sales_tool") + + tool_names <- vapply(mcpToolsList(), function(t) t$name, character(1)) + expect_true("sales_shiny_connect" %in% tool_names) + expect_false("_shiny_connect" %in% tool_names) + # the app tool advertises the namespaced resource + app_tool <- mcpToolsList()[[1]] + expect_equal(app_tool$`_meta`$ui$resourceUri, "ui://shiny/sales") + expect_equal(mcpResourcesList()[[1]]$uri, "ui://shiny/sales") +}) + +test_that("invalid shiny.mcp.appId is ignored", { + .globals$mcpAppIdWarned <- NULL + withr::defer(.globals$mcpAppIdWarned <- NULL) + withr::local_options(list(shiny.mcp.appId = "not ok!")) + expect_warning(id <- mcpAppId(), "shiny.mcp.appId") + expect_null(id) + # warns only once + expect_silent(expect_null(mcpAppId())) + expect_equal(mcpResourceUri(), "ui://shiny/app") +}) + +test_that("mcpDirectBase ignores empty headers and prefers X-Forwarded-Host", { + req <- new.env(parent = emptyenv()) + req$HTTP_HOST <- "127.0.0.1:34599" + req$HTTP_X_FORWARDED_PROTO <- "https" + # shinyapps.io sends this header with an empty value to Shiny content + req$HTTP_RSTUDIO_CONNECT_APP_BASE_URL <- "" + + # the internal Host is replaced by the forwarded external host + req$HTTP_X_FORWARDED_HOST <- "barret.shinyapps.io" + expect_equal(mcpDirectBase(req), "https://barret.shinyapps.io") +}) + +test_that("mcpDeployedUrl finds a host-matched rsconnect deployment record", { + dir <- withr::local_tempdir() + rec <- file.path(dir, "rsconnect", "connect.example.com", "barret") + dir.create(rec, recursive = TRUE) + write.dcf( + data.frame( + name = "myapp", + server = "connect.example.com", + url = "https://connect.example.com/content/abc123/" + ), + file.path(rec, "myapp.dcf") + ) + rec2 <- file.path(dir, "rsconnect", "shinyapps.io", "barret") + dir.create(rec2, recursive = TRUE) + write.dcf( + data.frame( + name = "myapp", + server = "shinyapps.io", + url = "https://barret.shinyapps.io/myapp/" + ), + file.path(rec2, "myapp.dcf") + ) + + # Host match picks the right record and strips the trailing slash + expect_equal( + mcpDeployedUrl(dir, "connect.example.com"), + "https://connect.example.com/content/abc123" + ) + expect_equal( + mcpDeployedUrl(dir, "barret.shinyapps.io"), + "https://barret.shinyapps.io/myapp" + ) + # No match (e.g. running locally): never use a deployment record + expect_null(mcpDeployedUrl(dir, "127.0.0.1:7788")) + expect_null(mcpDeployedUrl(dir, NULL)) + # No records at all + expect_null(mcpDeployedUrl(withr::local_tempdir(), "connect.example.com")) +}) + +test_that("resources/read uses the path-aware base: origin-only CSP, full directBase", { + ui <- fluidPage("hi") + app <- shinyApp(ui, function(input, output) {}) + withr::with_options( + list( + shiny.mcp = TRUE, + shiny.mcp.origin = "https://connect.example.com/content/abc123/" + ), + { + handlers <- createAppHandlers( + app$httpHandler, + function() function(input, output) {} + ) + req <- mcp_req(list( + jsonrpc = "2.0", id = 1, method = "resources/read", + params = list(uri = "ui://shiny/app") + )) + out <- jsonlite::parse_json(rawToChar(as_bytes( + wait_for_result(handlers$http(req))$content + ))) + csp <- unlist(out$result$contents[[1]]$`_meta`$ui$csp$connectDomains) + # CSP entries are origins only (host CSP sanitizers reject paths) + expect_setequal( + csp, + c("https://connect.example.com", "wss://connect.example.com") + ) + # ...but the bridge gets the full base including the path + expect_match( + out$result$contents[[1]]$text, + '"directBase":"https://connect.example.com/content/abc123"', + fixed = TRUE + ) + } + ) +}) + +test_that("mcpDeployedUrl reads Posit Publisher deployment records", { + dir <- withr::local_tempdir() + rec_dir <- file.path(dir, ".posit", "publish", "deployments") + dir.create(rec_dir, recursive = TRUE) + writeLines( + c( + "$schema = 'https://cdn.posit.co/publisher/schemas/posit-publishing-record-schema-v3.json'", + "server_type = 'connect'", + "server_url = 'https://connect.example.com'", + "id = 'abc-123'", + "dashboard_url = 'https://connect.example.com/connect/#/apps/abc-123'", + "direct_url = 'https://connect.example.com/content/abc-123/'" + ), + file.path(rec_dir, "deployment-A1B2.toml") + ) + expect_equal( + mcpDeployedUrl(dir, "connect.example.com"), + "https://connect.example.com/content/abc-123" + ) + expect_null(mcpDeployedUrl(dir, "other.example.com")) +}) diff --git a/tests/testthat/test-mcp-session.R b/tests/testthat/test-mcp-session.R new file mode 100644 index 0000000000..c6e58ef8bc --- /dev/null +++ b/tests/testthat/test-mcp-session.R @@ -0,0 +1,180 @@ +# Helper: create a tunneled session running `serverFunc` and return the +# connection id + ws handlers for driving it. +mcp_start_session <- function(ui, serverFunc, initData = list()) { + app <- shinyApp(ui, serverFunc) + handlers <- createAppHandlers(app$httpHandler, function() serverFunc) + con_res <- mcpTunnelToolCall("_shiny_connect", empty_named_list(), 1, handlers$ws) + cid <- con_res$result$structuredContent$connectionId + + init <- as.character(jsonlite::toJSON( + list(method = "init", data = c(list(.clientdata_url_search = ""), initData)), + auto_unbox = TRUE + )) + mcpTunnelToolCall( + "_shiny_send", + list(connectionId = cid, frames = list(list(data = init, binary = FALSE))), + 2, handlers$ws + ) + list(cid = cid, handlers = handlers) +} + +mcp_send_update <- function(sess, data) { + msg <- as.character(jsonlite::toJSON( + list(method = "update", data = data), + auto_unbox = TRUE + )) + mcpTunnelToolCall( + "_shiny_send", + list(connectionId = sess$cid, frames = list(list(data = msg, binary = FALSE))), + 3, sess$handlers$ws + ) +} + +mcp_drain_frames <- function(sess, timeout = 5) { + frames <- character(0) + end <- Sys.time() + timeout + while (Sys.time() < end) { + pump_shiny(0.05) + rec <- wait_for_result(mcpTunnelToolCall( + "_shiny_receive", list(connectionId = sess$cid, timeoutSecs = 0.1), + 4, sess$handlers$ws + )) + got <- vapply( + rec$result$structuredContent$frames, + function(f) f$data, character(1) + ) + frames <- c(frames, got) + if (length(got) == 0 && length(frames) > 0) break + } + frames +} + +test_that("isMcpSession distinguishes tunnel sessions from others", { + seen <- NULL + sess <- mcp_start_session( + fluidPage(), + function(input, output, session) { + seen <<- isMcpSession(session) + } + ) + pump_shiny(0.1) + expect_true(seen) + expect_false(isMcpSession(MockShinySession$new())) + mcpTunnelToolCall("_shiny_close", list(connectionId = sess$cid), 9, sess$handlers$ws) +}) + +test_that("mcpToolInput returns parsed tool arguments reactively", { + observed <- list() + sess <- mcp_start_session( + fluidPage(), + function(input, output, session) { + observe({ + val <- mcpToolInput() + if (!is.null(val)) observed[[length(observed) + 1]] <<- val + }) + } + ) + pump_shiny(0.2) + expect_length(observed, 0) + + mcp_send_update(sess, list( + .clientdata_mcp_tool_input = '{"note":"hello","n":3}' + )) + pump_shiny(0.3) + expect_gt(length(observed), 0) + latest <- observed[[length(observed)]] + expect_equal(latest$note, "hello") + expect_equal(latest$n, 3) + mcpTunnelToolCall("_shiny_close", list(connectionId = sess$cid), 9, sess$handlers$ws) +}) + +test_that("mcpHostContext returns parsed host context", { + ctx <- NULL + sess <- mcp_start_session( + fluidPage(), + function(input, output, session) { + observe({ + ctx <<- mcpHostContext() + }) + } + ) + mcp_send_update(sess, list( + .clientdata_mcp_host_context = '{"theme":"dark","locale":"en-US"}' + )) + pump_shiny(0.3) + expect_equal(ctx$theme, "dark") + mcpTunnelToolCall("_shiny_close", list(connectionId = sess$cid), 9, sess$handlers$ws) +}) + +test_that("mcpUpdateModelContext and mcpSendMessage send bridge messages", { + sess <- mcp_start_session( + fluidPage(), + function(input, output, session) { + observeEvent(input$go, { + mcpUpdateModelContext( + text = "n is 42", + data = list(n = 42) + ) + mcpSendMessage("What does this mean?") + }) + }, + initData = list(go = 0) + ) + mcp_drain_frames(sess) # flush startup frames + mcp_send_update(sess, list(go = 1)) + frames <- paste(mcp_drain_frames(sess), collapse = "\n") + + expect_match(frames, "shiny.mcp.updateModelContext", fixed = TRUE) + expect_match(frames, "n is 42", fixed = TRUE) + expect_match(frames, "structuredContent", fixed = TRUE) + expect_match(frames, "shiny.mcp.sendMessage", fixed = TRUE) + expect_match(frames, "What does this mean?", fixed = TRUE) + mcpTunnelToolCall("_shiny_close", list(connectionId = sess$cid), 9, sess$handlers$ws) +}) + +test_that("mcpUpdateModelContext validates input and no-ops outside MCP", { + mock <- MockShinySession$new() + expect_false(mcpUpdateModelContext(text = "x", session = mock)) + expect_false(mcpSendMessage("x", session = mock)) + expect_error(mcpUpdateModelContext(session = mock), "text.*data|data.*text") +}) + +test_that("tool inputSchema is configurable via options", { + schema <- list( + type = "object", + properties = list(note = list(type = "string", description = "A note")), + required = list("note") + ) + withr::with_options( + list(shiny.mcp.tool = list(inputSchema = schema)), + { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + out <- mcp_post(h, "tools/list") + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + app_tool <- out$result$tools[[which(tool_names == "open_shiny_app")]] + expect_equal(app_tool$inputSchema$properties$note$type, "string") + expect_equal(unlist(app_tool$inputSchema$required), "note") + } + ) +}) + +test_that("mcpRequestDisplayMode sends the bridge message", { + sess <- mcp_start_session( + fluidPage(), + function(input, output, session) { + observeEvent(input$go, { + mcpRequestDisplayMode("fullscreen") + }) + }, + initData = list(go = 0) + ) + mcp_drain_frames(sess) + mcp_send_update(sess, list(go = 1)) + frames <- paste(mcp_drain_frames(sess), collapse = "\n") + expect_match(frames, "shiny.mcp.requestDisplayMode", fixed = TRUE) + expect_match(frames, "fullscreen", fixed = TRUE) + mcpTunnelToolCall("_shiny_close", list(connectionId = sess$cid), 9, sess$handlers$ws) + + expect_false(mcpRequestDisplayMode("pip", session = MockShinySession$new())) + expect_error(mcpRequestDisplayMode("cinema", session = MockShinySession$new())) +}) diff --git a/tests/testthat/test-mcp-stdio.R b/tests/testthat/test-mcp-stdio.R new file mode 100644 index 0000000000..3c02e467e3 --- /dev/null +++ b/tests/testthat/test-mcp-stdio.R @@ -0,0 +1,153 @@ +make_dispatch <- function() { + ui <- fluidPage(textOutput("out")) + server <- function(input, output) {} + app <- shinyApp(ui, server) + handlers <- createAppHandlers(app$httpHandler, function() server) + uiHandler <- joinHandlers(app$httpHandler) + function(body) mcpDispatch(body, uiHandler, handlers$ws) +} + +test_that("mcpStdioHandleLine dispatches requests and writes responses", { + written <- character(0) + write <- function(x) written <<- c(written, x) + dispatch <- make_dispatch() + + mcpStdioHandleLine( + '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}', + dispatch, write + ) + expect_length(written, 1) + out <- jsonlite::parse_json(written[1]) + expect_equal(out$result$protocolVersion, "2025-06-18") + expect_equal(out$result$serverInfo$name, "shiny") + # single line, no embedded newlines + expect_false(grepl("\n", written[1], fixed = TRUE)) + + mcpStdioHandleLine( + '{"jsonrpc":"2.0","id":2,"method":"tools/list"}', + dispatch, write + ) + out <- jsonlite::parse_json(written[2]) + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true("open_shiny_app" %in% tool_names) +}) + +test_that("mcpStdioHandleLine ignores notifications and blank lines", { + written <- character(0) + write <- function(x) written <<- c(written, x) + dispatch <- make_dispatch() + + mcpStdioHandleLine("", dispatch, write) + mcpStdioHandleLine( + '{"jsonrpc":"2.0","method":"notifications/initialized"}', + dispatch, write + ) + expect_length(written, 0) +}) + +test_that("mcpStdioHandleLine reports parse errors and dispatch errors", { + written <- character(0) + write <- function(x) written <<- c(written, x) + + mcpStdioHandleLine("not json", make_dispatch(), write) + out <- jsonlite::parse_json(written[1]) + expect_equal(out$error$code, -32700L) + + boom <- function(body) stop("dispatch exploded") + mcpStdioHandleLine('{"jsonrpc":"2.0","id":5,"method":"ping"}', boom, write) + out <- jsonlite::parse_json(written[2]) + expect_equal(out$error$code, -32603L) + expect_equal(out$id, 5L) +}) + +test_that("mcpStdioHandleLine resolves promise results asynchronously", { + written <- character(0) + write <- function(x) written <<- c(written, x) + dispatch <- make_dispatch() + + # _shiny_receive long-polls: returns a promise that resolves on timeout + con_line <- '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"_shiny_connect","arguments":{}}}' + mcpStdioHandleLine(con_line, dispatch, write) + cid <- jsonlite::parse_json(written[1])$result$structuredContent$connectionId + + rec_line <- sprintf( + '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"_shiny_receive","arguments":{"connectionId":"%s","timeoutSecs":0.2}}}', + cid + ) + mcpStdioHandleLine(rec_line, dispatch, write) + expect_length(written, 1) # not resolved yet + + end <- Sys.time() + 5 + while (length(written) < 2 && Sys.time() < end) later::run_now(0.05) + expect_length(written, 2) + out <- jsonlite::parse_json(written[2]) + expect_false(is.null(out$result$structuredContent)) +}) + +test_that("stdio transport works end to end in a real subprocess", { + skip_on_cran() + skip_if_not_installed("processx") + skip_if(.Platform$OS.type == "windows") + + app_dir <- withr::local_tempdir() + writeLines( + c( + 'library(shiny)', + 'options(shiny.mcp = TRUE, shiny.mcp.stdio = TRUE)', + 'shinyApp(fluidPage("hi"), function(input, output) {})' + ), + file.path(app_dir, "app.R") + ) + + # The subprocess must run THIS version of shiny. Under R CMD check the + # installed package is the one being checked, so library(shiny) suffices; + # under devtools::test() the sources must be load_all()'d instead. + pkg_dir <- normalizePath(testthat::test_path("../.."), winslash = "/") + bootstrap <- if (file.exists(file.path(pkg_dir, "DESCRIPTION")) && + requireNamespace("pkgload", quietly = TRUE)) { + sprintf("suppressMessages(pkgload::load_all('%s', quiet = TRUE))", pkg_dir) + } else { + "library(shiny)" + } + px <- processx::process$new( + file.path(R.home("bin"), "Rscript"), + args = c("-e", sprintf( + "%s; shiny::runApp('%s', launch.browser = FALSE)", + bootstrap, app_dir + )), + stdin = "|", stdout = "|", stderr = "|" + ) + withr::defer(px$kill()) + + read_response <- function(timeout = 20) { + end <- Sys.time() + timeout + while (Sys.time() < end) { + px$poll_io(500) + line <- px$read_output_lines(1) + if (length(line) > 0 && nzchar(line)) return(jsonlite::parse_json(line)) + if (!px$is_alive()) { + stop("subprocess died: ", paste(px$read_all_error_lines(), collapse = "\n")) + } + } + stop("timed out waiting for stdio response; stderr: ", + paste(px$read_error_lines(), collapse = "\n")) + } + + px$write_input( + '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}\n' + ) + out <- read_response() + expect_equal(out$id, 1L) + expect_equal(out$result$serverInfo$name, "shiny") + + px$write_input('{"jsonrpc":"2.0","id":2,"method":"tools/list"}\n') + out <- read_response() + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true("open_shiny_app" %in% tool_names) + + px$write_input( + '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"ui://shiny/app"}}\n' + ) + out <- read_response() + expect_match(out$result$contents[[1]]$text, "shiny-mcp-bridge", fixed = TRUE) +}) diff --git a/tests/testthat/test-mcp-tunnel.R b/tests/testthat/test-mcp-tunnel.R new file mode 100644 index 0000000000..e2c3bcd0fa --- /dev/null +++ b/tests/testthat/test-mcp-tunnel.R @@ -0,0 +1,261 @@ +test_that("McpConnection satisfies the ws duck type and queues frames", { + conn <- McpConnection$new() + got <- list() + conn$onMessage(function(binary, msg) got[[length(got) + 1]] <<- list(binary, msg)) + conn$dispatchFrames(list(list(data = '{"method":"init"}', binary = FALSE))) + expect_length(got, 1) + expect_false(got[[1]][[1]]) + expect_equal(got[[1]][[2]], '{"method":"init"}') + + conn$send('{"values":{}}') + res <- wait_for_result(conn$receiveFrames()) + expect_length(res$frames, 1) + expect_equal(res$frames[[1]]$data, '{"values":{}}') + expect_false(res$closed) +}) + +test_that("binary messages are base64 round-tripped", { + conn <- McpConnection$new() + got <- list() + conn$onMessage(function(binary, msg) got[[length(got) + 1]] <<- list(binary, msg)) + + payload <- as.raw(c(1, 2, 2, 2, 255, 0, 128)) + conn$dispatchFrames(list(list( + data = jsonlite::base64_enc(payload), binary = TRUE + ))) + expect_true(got[[1]][[1]]) + expect_equal(got[[1]][[2]], payload) + + conn$send(payload) + res <- wait_for_result(conn$receiveFrames()) + expect_true(res$frames[[1]]$binary) + expect_equal(jsonlite::base64_dec(res$frames[[1]]$data), payload) +}) + +test_that("receiveFrames long-polls until send resolves it", { + conn <- McpConnection$new() + p <- conn$receiveFrames(timeoutSecs = 5) + later::later(function() conn$send("late"), 0.2) + res <- wait_for_result(p) + expect_equal(res$frames[[1]]$data, "late") +}) + +test_that("receiveFrames times out with empty frames", { + conn <- McpConnection$new() + res <- wait_for_result(conn$receiveFrames(timeoutSecs = 0.2)) + expect_length(res$frames, 0) + expect_false(res$closed) +}) + +test_that("server-initiated close resolves pending receive and fires onClose", { + conn <- McpConnection$new() + closed <- FALSE + conn$onClose(function() closed <<- TRUE) + p <- conn$receiveFrames(timeoutSecs = 5) + later::later(function() conn$close(), 0.1) + res <- wait_for_result(p) + expect_true(res$closed) + expect_true(closed) +}) + +test_that("full tunnel: connect/send init/receive config from a real session", { + ui <- fluidPage(textOutput("out")) + server <- function(input, output) { + output$out <- renderText(paste0("n=", input$n)) + } + app <- shinyApp(ui, server) + handlers <- createAppHandlers(app$httpHandler, function() server) + + con_res <- mcpTunnelToolCall("_shiny_connect", empty_named_list(), 1, handlers$ws) + cid <- con_res$result$structuredContent$connectionId + expect_true(is.character(cid) && nzchar(cid)) + + init <- as.character(jsonlite::toJSON( + list( + method = "init", + data = list( + n = 5, + .clientdata_url_search = "", + # Outputs are suspended-when-hidden; the real client reports + # visibility in the init message. + .clientdata_output_out_hidden = FALSE + ) + ), + auto_unbox = TRUE + )) + send_res <- mcpTunnelToolCall( + "_shiny_send", + list(connectionId = cid, frames = list(list(data = init, binary = FALSE))), + 2, handlers$ws + ) + expect_false(isTRUE(send_res$result$isError)) + + rec <- wait_for_result( + mcpTunnelToolCall("_shiny_receive", list(connectionId = cid), 3, handlers$ws), + timeout = 10 + ) + all_data <- vapply( + rec$result$structuredContent$frames, + function(f) f$data, character(1) + ) + # First outbound message is the config message + expect_true(any(grepl("workerId", all_data))) + + # Reactive output should flush; pump until we see it + seen_value <- FALSE + end <- Sys.time() + 10 + while (!seen_value && Sys.time() < end) { + pump_shiny(0.1) + rec <- wait_for_result( + mcpTunnelToolCall( + "_shiny_receive", list(connectionId = cid, timeoutSecs = 0.2), + 4, handlers$ws + ), + timeout = 10 + ) + frames <- rec$result$structuredContent$frames + if (length(frames) > 0) { + datas <- vapply(frames, function(f) f$data, character(1)) + if (any(grepl("n=5", datas, fixed = TRUE))) seen_value <- TRUE + } + } + expect_true(seen_value) + + close_res <- mcpTunnelToolCall( + "_shiny_close", list(connectionId = cid), 5, handlers$ws + ) + expect_false(isTRUE(close_res$result$isError)) + + err <- mcpTunnelToolCall( + "_shiny_send", list(connectionId = cid, frames = list()), 6, handlers$ws + ) + expect_true(isTRUE(err$result$isError)) +}) + +test_that("tools/list over the endpoint includes tunnel tools marked app-only", { + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + out <- mcp_post(h, "tools/list") + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true(all( + c("_shiny_connect", "_shiny_send", "_shiny_receive", "_shiny_close") %in% + tool_names + )) + connect_tool <- out$result$tools[[which(tool_names == "_shiny_connect")]] + expect_equal(unlist(connect_tool$`_meta`$ui$visibility), "app") +}) + +test_that("mcpRookInput consumes bytes in chunks", { + input <- mcpRookInput(as.raw(1:10)) + expect_equal(input$read(4), as.raw(1:4)) + expect_equal(input$read(4), as.raw(5:8)) + expect_equal(input$read(4), as.raw(9:10)) + expect_equal(input$read(4), raw(0)) + input$rewind() + expect_equal(input$read(), as.raw(1:10)) + expect_equal(input$read(), raw(0)) +}) + +test_that("_shiny_http serves static assets and 404s through the app chain", { + ui <- fluidPage(textOutput("out")) + server <- function(input, output) {} + app <- shinyApp(ui, server) + handlers <- createAppHandlers(app$httpHandler, function() server) + + con_res <- mcpTunnelToolCall("_shiny_connect", empty_named_list(), 1, handlers$ws) + cid <- con_res$result$structuredContent$connectionId + + res <- wait_for_result(mcpHttpToolCall( + list(connectionId = cid, method = "GET", path = "/shared/shiny.min.js"), + 2 + )) + sc <- res$result$structuredContent + expect_equal(sc$status, 200L) + body <- jsonlite::base64_dec(sc$body) + expect_gt(length(body), 10000) + + res404 <- wait_for_result(mcpHttpToolCall( + list(connectionId = cid, method = "GET", path = "/nope/missing.js"), + 3 + )) + expect_equal(res404$result$structuredContent$status, 404L) + + bad <- mcpHttpToolCall(list(connectionId = "bogus", method = "GET", path = "/x"), 4) + expect_true(isTRUE(bad$result$isError)) +}) + +test_that("_shiny_http serves session downloads with headers", { + # registerDownload() builds URLs with workerId(), which is only set by + # runApp()-style startup; give it the standard empty value for this test. + suppressWarnings(workerId("")) + ui <- fluidPage(downloadButton("dl", "Get CSV")) + server <- function(input, output, session) { + output$dl <- downloadHandler( + filename = "data.csv", + # writeBin, not writeLines: the latter opens `file` in text mode, so + # on Windows every \n becomes \r\n and the body assertion below fails. + content = function(file) writeBin(charToRaw("a,b\n1,2\n"), file), + contentType = "text/csv" + ) + } + app <- shinyApp(ui, server) + handlers <- createAppHandlers(app$httpHandler, function() server) + + con_res <- mcpTunnelToolCall("_shiny_connect", empty_named_list(), 1, handlers$ws) + cid <- con_res$result$structuredContent$connectionId + + init <- as.character(jsonlite::toJSON( + list(method = "init", data = list( + .clientdata_url_search = "", + .clientdata_output_dl_hidden = FALSE + )), + auto_unbox = TRUE + )) + mcpTunnelToolCall( + "_shiny_send", + list(connectionId = cid, frames = list(list(data = init, binary = FALSE))), + 2, handlers$ws + ) + + # Wait for the download href (sent as a value for output dl) + href <- NULL + end <- Sys.time() + 10 + while (is.null(href) && Sys.time() < end) { + pump_shiny(0.1) + rec <- wait_for_result(mcpTunnelToolCall( + "_shiny_receive", list(connectionId = cid, timeoutSecs = 0.2), 3, handlers$ws + )) + for (f in rec$result$structuredContent$frames) { + m <- regmatches(f$data, regexpr("session/[^\"]+/download/[^\"]+", f$data)) + if (length(m) > 0) href <- m[[1]] + } + } + expect_false(is.null(href)) + + res <- wait_for_result(mcpHttpToolCall( + list(connectionId = cid, method = "GET", path = paste0("/", href)), + 4 + )) + sc <- res$result$structuredContent + expect_equal(sc$status, 200L) + expect_equal(rawToChar(jsonlite::base64_dec(sc$body)), "a,b\n1,2\n") + hdrs <- sc$headers + expect_match(hdrs[["Content-Disposition"]], "data.csv") +}) + +test_that("_shiny_http works without a connectionId (direct-connect sessions)", { + res <- wait_for_result(mcpTunnelToolCall( + "_shiny_http", + list(method = "GET", path = "/shared/shiny.min.css"), + 1, + function(ws) TRUE + )) + expect_equal(res$result$structuredContent$status, 200L) + + bad <- mcpTunnelToolCall( + "_shiny_http", + list(connectionId = "nope", method = "GET", path = "/x"), + 2, + function(ws) TRUE + ) + expect_true(isTRUE(bad$result$isError)) +}) diff --git a/tests/testthat/test-reactlog.R b/tests/testthat/test-reactlog.R index 3a9799af5f..7b8a892b20 100644 --- a/tests/testthat/test-reactlog.R +++ b/tests/testthat/test-reactlog.R @@ -131,7 +131,11 @@ test_that("message logger appears", { test_that("reactlog_version is as expected", { expect_match( packageDescription("shiny")$Suggests, - # The space between reactlog and the version number can include \n - sprintf("\\breactlog\\s+\\Q(>= %s)\\E", reactlog_min_version) + # R rewraps the installed DESCRIPTION, so any of the spaces (including + # the one inside the version requirement) can be a newline + indent + sprintf( + "\\breactlog\\s+\\(>=\\s+%s\\)", + gsub(".", "\\.", reactlog_min_version, fixed = TRUE) + ) ) }) diff --git a/tools/documentation/pkgdown.yml b/tools/documentation/pkgdown.yml index ddc1c34869..7e2be0d6cd 100644 --- a/tools/documentation/pkgdown.yml +++ b/tools/documentation/pkgdown.yml @@ -164,6 +164,10 @@ reference: - registerInputHandler - removeInputHandler - markRenderFunction + - title: MCP Apps + desc: Serve Shiny apps as MCP Apps and interact with the MCP host (experimental). + contents: + - mcp-session - title: Utility functions desc: Miscellaneous utilities that may be useful to advanced users or when extending Shiny. contents: From 57a7485cbf3f1a384e59e065df568cc1d0b53279 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 15 Jul 2026 15:36:27 -0400 Subject: [PATCH 2/2] feat: register MCP author tools with registerMcpTool() + ellmer::tool() (#4412) Replace options(shiny.mcp.tools=) with registerMcpTool(), accepting ellmer::tool() objects; convert to MCP tools/list schema via the mcptools as_json() path and invoke on tools/call with rlang::exec(). ellmer -> Suggests. ToolDef props read via S7::prop() for R < 4.3. Docs, demos, and mcp/ architecture updated. --- DESCRIPTION | 3 + NAMESPACE | 1 + NEWS.md | 5 +- R/globals.R | 1 + R/mcp-server.R | 70 +- R/mcp-session.R | 28 +- R/mcp-tools.R | 67 ++ man/mcp-session.Rd | 27 +- man/registerMcpTool.Rd | 51 ++ mcp/QUESTIONS.md | 4 +- mcp/README.md | 15 +- mcp/architecture.md | 16 +- mcp/comparison-shinymcp.md | 11 +- mcp/demo-app/app.R | 24 +- .../barret/shiny-mcp-demo.dcf | 2 +- .../shinyapps.io/barret/shiny-mcp-demo.dcf | 2 +- .../shinyapps.io/barret/shiny-mcp-cars.dcf | 2 +- mcp/design-register-mcp-tool.md | 230 +++++++ mcp/implementation-plan-register-mcp-tool.md | 638 ++++++++++++++++++ tests/testthat/helper-mcp.R | 8 + tests/testthat/test-mcp-server.R | 169 +++-- tests/testthat/test-mcp-tools.R | 51 ++ tools/documentation/pkgdown.yml | 1 + 23 files changed, 1205 insertions(+), 221 deletions(-) create mode 100644 R/mcp-tools.R create mode 100644 man/registerMcpTool.Rd create mode 100644 mcp/design-register-mcp-tool.md create mode 100644 mcp/implementation-plan-register-mcp-tool.md create mode 100644 tests/testthat/test-mcp-tools.R diff --git a/DESCRIPTION b/DESCRIPTION index 38ccf7fce7..8f1d893b95 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -106,6 +106,7 @@ Suggests: datasets, DT, dygraphs, + ellmer (>= 0.4.0), future, ggplot2, knitr (>= 1.6), @@ -118,6 +119,7 @@ Suggests: ragg, reactlog (>= 1.0.0), rmarkdown, + S7, sass, shinytest2, showtext, @@ -183,6 +185,7 @@ Collate: 'mcp-server.R' 'mcp-session.R' 'mcp-stdio.R' + 'mcp-tools.R' 'mcp-tunnel.R' 'middleware-shiny.R' 'middleware.R' diff --git a/NAMESPACE b/NAMESPACE index 711b377b54..601a9dc208 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -227,6 +227,7 @@ export(reactlogAddMark) export(reactlogReset) export(reactlogShow) export(registerInputHandler) +export(registerMcpTool) export(registerThemeDependency) export(register_devmode_option) export(removeInputHandler) diff --git a/NEWS.md b/NEWS.md index c1dcfefd9c..40dbc7563c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -17,9 +17,8 @@ `mcpHostContext()`, `mcpUpdateModelContext()`, and `mcpSendMessage()` let apps react to the model's tool arguments and host theme, keep the model's context up to date, and send messages to the conversation. Apps can also - expose additional model-callable R functions with - `options(shiny.mcp.tools = list(list(name=, description=, inputSchema=, - handler=)))`. Adding `options(shiny.mcp.stdio = TRUE)` also speaks MCP + expose additional model-callable tools with `registerMcpTool()`, using + `ellmer::tool()` definitions. Adding `options(shiny.mcp.stdio = TRUE)` also speaks MCP over stdin/stdout, so local desktop hosts can launch the app process directly, e.g. `claude mcp add my-app -- Rscript -e "options(shiny.mcp=TRUE, shiny.mcp.stdio=TRUE); diff --git a/R/globals.R b/R/globals.R index fb26afa46e..a78e528b99 100644 --- a/R/globals.R +++ b/R/globals.R @@ -1,5 +1,6 @@ # A scope where we can put mutable global state .globals <- new.env(parent = emptyenv()) +.globals$mcpAuthorTools <- list() .onLoad <- function(libname, pkgname) { # R's lazy-loading package scheme causes the private seed to be cached in the diff --git a/R/mcp-server.R b/R/mcp-server.R index c66ffacfd9..f394761110 100644 --- a/R/mcp-server.R +++ b/R/mcp-server.R @@ -367,52 +367,42 @@ mcpToolsList <- function() { `_meta` = list(ui = list(resourceUri = mcpResourceUri())) )), mcpTunnelToolsList(), - lapply(mcpAuthorTools(warn = TRUE), function(tool) { - list( - name = tool$name, - description = tool$description, - inputSchema = tool$inputSchema %||% - list(type = "object", properties = empty_named_list()) - ) + lapply(mcpAuthorTools(), function(tool) { + dropNulls(list( + name = S7::prop(tool, "name"), + title = S7::prop(tool, "annotations")$title, + description = S7::prop(tool, "description"), + inputSchema = mcpToolInputSchema(tool) + )) }) )) } -# Author-declared tools from options(shiny.mcp.tools = list(...)). Each spec -# is a list with `name`, `description`, optional `inputSchema`, and a -# `handler` function taking the (parsed) arguments as a named list. Handlers -# run in the server R process without a session and may return a promise. -# Invalid specs are skipped (reported once, from tools/list). -mcpAuthorTools <- function(warn = FALSE) { - specs <- getOption("shiny.mcp.tools", list()) - reserved <- c( +mcpReservedToolNames <- function() { + c( mcpToolInfo()$name, vapply(mcpTunnelToolsList(), function(t) t$name, character(1)) ) - out <- list() - for (spec in specs) { - problem <- if (!is.list(spec) || !is.character(spec$name %||% NULL)) { - "it has no `name`" - } else if (spec$name %in% reserved) { - sprintf("the name '%s' is reserved", spec$name) - } else if (!is.function(spec$handler %||% NULL)) { - "its `handler` is not a function" - } else if (!is.character(spec$description %||% NULL)) { - "it has no `description`" - } - if (!is.null(problem)) { - if (warn) { - warning( - "Ignoring a tool in options(shiny.mcp.tools) because ", problem, - if (is.character(spec$name %||% NULL)) sprintf(" ('%s')", spec$name), - call. = FALSE - ) - } - next - } - out[[spec$name]] <- spec +} + +# Author-declared tools registered via registerMcpTool(). Named list of +# ellmer::ToolDef objects, keyed by tool name; validation happens eagerly at +# registration time. +mcpAuthorTools <- function() { + .globals$mcpAuthorTools %||% list() +} + +# Convert an ellmer ToolDef's typed @arguments into a JSON Schema list for +# tools/list. Mirrors mcptools::tool_as_json() so the two stay aligned: a +# dummy provider drives ellmer's provider-agnostic base as_json() method. +mcpToolInputSchema <- function(tool) { + as_json <- getNamespace("ellmer")[["as_json"]] + schema <- as_json(ellmer::Provider("dummy", "dummy", "dummy"), S7::prop(tool, "arguments")) + schema$description <- NULL + if (is.null(schema$properties)) { + schema$properties <- empty_named_list() } - out + dropNulls(schema) } # Convert a handler's return value into an MCP CallToolResult. @@ -449,9 +439,9 @@ mcpAuthorToolResult <- function(id, value) { } mcpAuthorToolCall <- function(tool, params, id) { - args <- params$arguments %||% empty_named_list() + args <- params$arguments %||% list() hybrid_chain( - tryCatch(tool$handler(args), error = function(e) e), + tryCatch(rlang::exec(tool, !!!args), error = function(e) e), function(value) { if (inherits(value, "condition")) { return(mcpToolErrorResult(id, conditionMessage(value))) diff --git a/R/mcp-session.R b/R/mcp-session.R index d890bbb4b0..8270a05911 100644 --- a/R/mcp-session.R +++ b/R/mcp-session.R @@ -52,32 +52,8 @@ #' #' @section Additional tools: #' Beyond the tool that opens the app, authors can expose plain R functions -#' as MCP tools the model may call directly, via -#' `options(shiny.mcp.tools = list(...))`. Each tool is a list with a -#' `name`, a `description`, an optional `inputSchema` (JSON Schema as a -#' nested list), and a `handler` function that receives the parsed -#' arguments as a named list. Handlers run in the server R process outside -#' of any Shiny session and may return a character vector (sent as text), a -#' list (sent as JSON `structuredContent`), or a promise. Errors are -#' reported to the model as tool errors. -#' -#' ```r -#' options(shiny.mcp.tools = list( -#' list( -#' name = "get_sample_stats", -#' description = "Summary statistics for a normal sample of size n.", -#' inputSchema = list( -#' type = "object", -#' properties = list(n = list(type = "integer")), -#' required = list("n") -#' ), -#' handler = function(args) { -#' x <- rnorm(args$n) -#' list(n = args$n, mean = mean(x), sd = stats::sd(x)) -#' } -#' ) -#' )) -#' ``` +#' as MCP tools the model may call directly, with [registerMcpTool()] and +#' [ellmer::tool()]. See `?registerMcpTool` for details. #' #' @param text A character string. For `mcpUpdateModelContext()`, the #' human/model-readable context text; for `mcpSendMessage()`, the message diff --git a/R/mcp-tools.R b/R/mcp-tools.R new file mode 100644 index 0000000000..9f0b512093 --- /dev/null +++ b/R/mcp-tools.R @@ -0,0 +1,67 @@ +#' Register an MCP tool the model can call directly +#' +#' @description +#' `r lifecycle::badge("experimental")` +#' +#' When a Shiny app is served as an MCP App (`options(shiny.mcp = TRUE)`), +#' `registerMcpTool()` exposes plain R functions as MCP tools the model may +#' call directly, in addition to the tool that opens the app. Define each +#' tool with [ellmer::tool()] and register it at the top level of your +#' `app.R`, before the app starts: +#' +#' ```r +#' library(shiny) +#' options(shiny.mcp = TRUE) +#' +#' registerMcpTool( +#' ellmer::tool( +#' function(n) { +#' x <- rnorm(n) +#' list(n = n, mean = mean(x), sd = stats::sd(x)) +#' }, +#' name = "get_sample_stats", +#' description = "Summary statistics for a normal sample of size n.", +#' arguments = list(n = ellmer::type_integer("Sample size", required = TRUE)) +#' ) +#' ) +#' ``` +#' +#' Handlers run in the server R process, outside of any Shiny session, and +#' may return a character vector (sent as text), a list (sent as JSON +#' `structuredContent`), or a promise. Errors are reported to the model as +#' tool errors. +#' +#' Tools are keyed by their `name`; registering a tool whose name is already +#' registered replaces it. A tool may not use a name reserved by Shiny's MCP +#' server (the app-opening tool or the internal `_shiny_*` tunnel tools). +#' +#' @param ... One or more tools created with [ellmer::tool()]. +#' +#' @return Invisibly, `NULL`. +#' +#' @seealso [mcpToolInput()] and the other `mcp*` session helpers. +#' @export +registerMcpTool <- function(...) { + rlang::check_installed("ellmer", "to define MCP tools with `ellmer::tool()`.") + tools <- list(...) + reserved <- mcpReservedToolNames() + for (tool in tools) { + if (!inherits(tool, "ellmer::ToolDef")) { + stop( + "`registerMcpTool()` accepts tools created with `ellmer::tool()`; ", + "received an object of class '", class(tool)[1], "'.", + call. = FALSE + ) + } + name <- S7::prop(tool, "name") + if (name %in% reserved) { + stop( + "Cannot register an MCP tool named '", name, "': that name is ", + "reserved by Shiny's MCP server.", + call. = FALSE + ) + } + .globals$mcpAuthorTools[[name]] <- tool + } + invisible() +} diff --git a/man/mcp-session.Rd b/man/mcp-session.Rd index 0601ee306e..4d0046ee7a 100644 --- a/man/mcp-session.Rd +++ b/man/mcp-session.Rd @@ -110,31 +110,8 @@ tool names must also be unique across the merged apps. \section{Additional tools}{ Beyond the tool that opens the app, authors can expose plain R functions -as MCP tools the model may call directly, via -\code{options(shiny.mcp.tools = list(...))}. Each tool is a list with a -\code{name}, a \code{description}, an optional \code{inputSchema} (JSON Schema as a -nested list), and a \code{handler} function that receives the parsed -arguments as a named list. Handlers run in the server R process outside -of any Shiny session and may return a character vector (sent as text), a -list (sent as JSON \code{structuredContent}), or a promise. Errors are -reported to the model as tool errors. - -\if{html}{\out{
}}\preformatted{options(shiny.mcp.tools = list( - list( - name = "get_sample_stats", - description = "Summary statistics for a normal sample of size n.", - inputSchema = list( - type = "object", - properties = list(n = list(type = "integer")), - required = list("n") - ), - handler = function(args) \{ - x <- rnorm(args$n) - list(n = args$n, mean = mean(x), sd = stats::sd(x)) - \} - ) -)) -}\if{html}{\out{
}} +as MCP tools the model may call directly, with \code{\link[=registerMcpTool]{registerMcpTool()}} and +\code{\link[ellmer:tool]{ellmer::tool()}}. See \code{?registerMcpTool} for details. } \examples{ diff --git a/man/registerMcpTool.Rd b/man/registerMcpTool.Rd new file mode 100644 index 0000000000..822fe95573 --- /dev/null +++ b/man/registerMcpTool.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mcp-tools.R +\name{registerMcpTool} +\alias{registerMcpTool} +\title{Register an MCP tool the model can call directly} +\usage{ +registerMcpTool(...) +} +\arguments{ +\item{...}{One or more tools created with \code{\link[ellmer:tool]{ellmer::tool()}}.} +} +\value{ +Invisibly, \code{NULL}. +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} + +When a Shiny app is served as an MCP App (\code{options(shiny.mcp = TRUE)}), +\code{registerMcpTool()} exposes plain R functions as MCP tools the model may +call directly, in addition to the tool that opens the app. Define each +tool with \code{\link[ellmer:tool]{ellmer::tool()}} and register it at the top level of your +\code{app.R}, before the app starts: + +\if{html}{\out{
}}\preformatted{library(shiny) +options(shiny.mcp = TRUE) + +registerMcpTool( + ellmer::tool( + function(n) \{ + x <- rnorm(n) + list(n = n, mean = mean(x), sd = stats::sd(x)) + \}, + name = "get_sample_stats", + description = "Summary statistics for a normal sample of size n.", + arguments = list(n = ellmer::type_integer("Sample size", required = TRUE)) + ) +) +}\if{html}{\out{
}} + +Handlers run in the server R process, outside of any Shiny session, and +may return a character vector (sent as text), a list (sent as JSON +\code{structuredContent}), or a promise. Errors are reported to the model as +tool errors. + +Tools are keyed by their \code{name}; registering a tool whose name is already +registered replaces it. A tool may not use a name reserved by Shiny's MCP +server (the app-opening tool or the internal \verb{_shiny_*} tunnel tools). +} +\seealso{ +\code{\link[=mcpToolInput]{mcpToolInput()}} and the other \verb{mcp*} session helpers. +} diff --git a/mcp/QUESTIONS.md b/mcp/QUESTIONS.md index 851a529a14..5704994e74 100644 --- a/mcp/QUESTIONS.md +++ b/mcp/QUESTIONS.md @@ -6,8 +6,8 @@ each item. ## 1. Naming (`mcp*` functions, `shiny.mcp.*` options) — ✅ leave as is No renames. Surface: options `shiny.mcp`, `shiny.mcp.stdio`, -`shiny.mcp.direct`, `shiny.mcp.tool`, `shiny.mcp.tools`, -`shiny.mcp.displayModes`; exports `isMcpSession()`, `mcpToolInput()`, +`shiny.mcp.direct`, `shiny.mcp.tool`, `shiny.mcp.displayModes`; +function `registerMcpTool()`; exports `isMcpSession()`, `mcpToolInput()`, `mcpHostContext()`, `mcpUpdateModelContext()`, `mcpSendMessage()`, `mcpRequestDisplayMode()`. diff --git a/mcp/README.md b/mcp/README.md index 7c02ce5e9d..3119454bcb 100644 --- a/mcp/README.md +++ b/mcp/README.md @@ -70,13 +70,14 @@ traffic tunneled over postMessage → `tools/call`). pip) and can call `mcpRequestDisplayMode("fullscreen")`; the resulting mode arrives via `mcpHostContext()$displayMode`. Unit-tested; basic-host doesn't implement display modes, so not yet E2E-verified on a real host. -- **Author-declared tools:** `options(shiny.mcp.tools = list(list(name=, - description=, inputSchema=, handler=)))` exposes plain R functions as - model-callable MCP tools alongside the app tool. Handlers run in the - server R process (no session), may return character/list/promise, and - errors surface as MCP tool errors. Invalid or name-colliding specs are - skipped with a warning. Verified E2E in basic-host (`get_sample_stats` - in the demo app). +- **Author-declared tools:** `registerMcpTool(ellmer::tool(...))` exposes + plain R functions as model-callable MCP tools alongside the app tool. + Handlers run in the server R process (no session), may return + character/list/promise, and errors surface as MCP tool errors. + `registerMcpTool()` validates eagerly — a reserved/colliding name or a + non-`ellmer::tool()` argument causes a hard `stop()` at registration + time. ellmer (>= 0.4.0) is a Suggests dependency required for author + tools. Verified E2E in basic-host (`get_sample_stats` in the demo app). - **Multi-app gateway (one connector, many apps):** each app sets a unique `options(shiny.mcp.appId = "")`, which namespaces its internal `_shiny_*` tools (`demo_shiny_connect`, ...) and publishes its resource diff --git a/mcp/architecture.md b/mcp/architecture.md index 12e1318901..f6294cb0b6 100644 --- a/mcp/architecture.md +++ b/mcp/architecture.md @@ -71,11 +71,13 @@ the closure `createAppHandlers()` stashes in `.globals$mcpDispatch`. - five *internal tunnel tools* `_shiny_connect/_send/_receive/_close/ _http`, marked `_meta.ui.visibility = ["app"]` so only the iframe (not the model) can call them; - - *author tools* from `options(shiny.mcp.tools = list(...))` — plain R - functions exposed to the model, run sessionless in the server process - (character → text content, list → structuredContent, promises - supported, errors → `isError`). Reserved/colliding names are skipped - with a one-time warning. + - *author tools* registered via `registerMcpTool(ellmer::tool(...))` — + plain R functions exposed to the model, run sessionless in the server + process (character → text content, list → structuredContent, promises + supported, errors → `isError`). The ellmer→JSON-Schema conversion + mirrors `mcptools::tool_as_json()`. `registerMcpTool()` validates + eagerly — a reserved/colliding name or a non-`ellmer::tool()` argument + causes a hard `stop()` at registration time. - **One resource**: `ui://shiny/app` (or `ui://shiny/`, see gateway section), mime `text/html;profile=mcp-app`. @@ -217,12 +219,14 @@ A single MCP connector can front several Shiny apps: | `shiny.mcp` | mount `/mcp` (master switch) | | `shiny.mcp.stdio` | also speak JSON-RPC on stdin/stdout | | `shiny.mcp.tool` | name/description/inputSchema of the app tool | -| `shiny.mcp.tools` | author-declared model-callable tools | | `shiny.mcp.appId` | namespace internal tools + resource URI (gateway) | | `shiny.mcp.direct` | direct-connect fast path (default TRUE) | | `shiny.mcp.origin` | explicit external base URL (proxy override) | | `shiny.mcp.displayModes` | subset of inline/fullscreen/pip | +Author tools are registered via `registerMcpTool(ellmer::tool(...))`, not +through an option. + ## File map | Path | Role | diff --git a/mcp/comparison-shinymcp.md b/mcp/comparison-shinymcp.md index 38b9c547d8..1ccf4ba44b 100644 --- a/mcp/comparison-shinymcp.md +++ b/mcp/comparison-shinymcp.md @@ -36,7 +36,7 @@ Compared versions (2026-07-13): | App↔server channel | Tunneled websocket over `tools/call` long-poll, or direct WebSocket fast path | One `tools/call` per (debounced) input change | | State | Server-side reactive session per viewer | Stateless between calls (state lives in input values) | | Outputs | Everything Shiny can render (plots, htmlwidgets, dynamic UI, uploads, downloads, server-side selectize/DT) | What a tool returns: text, base64 PNG, HTML/table components | -| Tool definitions | `options(shiny.mcp.tool/tools)` (plain lists) | ellmer `tool()` objects (typed arguments) | +| Tool definitions | app tool: `options(shiny.mcp.tool)` (plain list); author tools: `registerMcpTool(ellmer::tool())` (see `design-register-mcp-tool.md`) | ellmer `tool()` objects (typed arguments) | | Model-callable tools | The app tool + author-declared extras; the *session* is not model-drivable | Every tool is model-callable by design; same tools drive the UI | | Non-Apps MCP clients | Author tools + app tool work as text; UI needs an Apps host | **Degrades gracefully everywhere** — tools work as ordinary text tools | | Model context updates | `mcpUpdateModelContext()` — author opt-in, arbitrary content | Bridge auto-reports current input state on interaction | @@ -93,9 +93,12 @@ Neither bet dominates. They're answers to different questions: their host could in principle render our apps too, since both follow the ext-apps postMessage spec. 4. **ellmer `tool()` reuse** gives typed schemas for free and matches the - ecosystem direction (mcptools is also ellmer-based). Our - `options(shiny.mcp.tools=)` lists are deliberately dependency-free but - could accept ellmer tools as an alternative input. + ecosystem direction (mcptools is also ellmer-based). **Adopted** for + author tools: `options(shiny.mcp.tools=)` is being replaced by + `registerMcpTool(ellmer::tool())`, using the same ellmer→JSON-Schema + conversion as `mcptools::tool_as_json()` — see + `design-register-mcp-tool.md`. The app-opening tool + (`options(shiny.mcp.tool)`) stays a plain list for now. 5. **Apps-spec version**: their bridge targets the `2026-01-26` revision; our bundled `@modelcontextprotocol/ext-apps` SDK should be checked against the same revision before CRAN. diff --git a/mcp/demo-app/app.R b/mcp/demo-app/app.R index 6ada37bdb3..18ddbb5230 100644 --- a/mcp/demo-app/app.R +++ b/mcp/demo-app/app.R @@ -19,28 +19,22 @@ options(shiny.mcp.tool = list( )) # Additional model-callable tools that run in the server R process -options(shiny.mcp.tools = list( - list( - name = "get_sample_stats", - description = "Summary statistics for a fresh normal sample of size n.", - inputSchema = list( - type = "object", - properties = list( - n = list(type = "integer", description = "Sample size (>= 2)") - ), - required = list("n") - ), - handler = function(args) { - x <- rnorm(max(2, args$n)) +registerMcpTool( + ellmer::tool( + function(n) { + x <- rnorm(max(2, n)) list( n = length(x), mean = round(mean(x), 4), sd = round(stats::sd(x), 4), range = round(range(x), 4) ) - } + }, + name = "get_sample_stats", + description = "Summary statistics for a fresh normal sample of size n.", + arguments = list(n = ellmer::type_integer("Sample size (>= 2)", required = TRUE)) ) -)) +) shinyApp( ui = fluidPage( diff --git a/mcp/demo-app/rsconnect/connect.posit.it/barret/shiny-mcp-demo.dcf b/mcp/demo-app/rsconnect/connect.posit.it/barret/shiny-mcp-demo.dcf index 45615efbef..e67f3adc7a 100644 --- a/mcp/demo-app/rsconnect/connect.posit.it/barret/shiny-mcp-demo.dcf +++ b/mcp/demo-app/rsconnect/connect.posit.it/barret/shiny-mcp-demo.dcf @@ -5,6 +5,6 @@ account: barret server: connect.posit.it hostUrl: https://connect.posit.it/__api__ appId: 18705 -bundleId: 1218234 +bundleId: 1221644 url: https://connect.posit.it/content/49fa26ca-53cf-491d-a9ee-ab0b5c29673b/ version: 1 diff --git a/mcp/demo-app/rsconnect/shinyapps.io/barret/shiny-mcp-demo.dcf b/mcp/demo-app/rsconnect/shinyapps.io/barret/shiny-mcp-demo.dcf index baa0b6f9ba..cf0534356d 100644 --- a/mcp/demo-app/rsconnect/shinyapps.io/barret/shiny-mcp-demo.dcf +++ b/mcp/demo-app/rsconnect/shinyapps.io/barret/shiny-mcp-demo.dcf @@ -5,6 +5,6 @@ account: barret server: shinyapps.io hostUrl: https://api.shinyapps.io/v1 appId: 17606832 -bundleId: 12261506 +bundleId: 12272703 url: https://barret.shinyapps.io/shiny-mcp-demo/ version: 1 diff --git a/mcp/demo-app2/rsconnect/shinyapps.io/barret/shiny-mcp-cars.dcf b/mcp/demo-app2/rsconnect/shinyapps.io/barret/shiny-mcp-cars.dcf index 6cdd22859e..00b7537205 100644 --- a/mcp/demo-app2/rsconnect/shinyapps.io/barret/shiny-mcp-cars.dcf +++ b/mcp/demo-app2/rsconnect/shinyapps.io/barret/shiny-mcp-cars.dcf @@ -5,6 +5,6 @@ account: barret server: shinyapps.io hostUrl: https://api.shinyapps.io/v1 appId: 17606973 -bundleId: 12261515 +bundleId: 12272715 url: https://barret.shinyapps.io/shiny-mcp-cars/ version: 1 diff --git a/mcp/design-register-mcp-tool.md b/mcp/design-register-mcp-tool.md new file mode 100644 index 0000000000..c43d48e7ec --- /dev/null +++ b/mcp/design-register-mcp-tool.md @@ -0,0 +1,230 @@ +# Design: `registerMcpTool()` — ellmer-native author tools + +**Date:** 2026-07-15 +**Branch:** `schloerke/shinymcp-tool-registration` (targets `mcp`) +**Status:** Approved for planning + +## Problem + +Shiny's MCP author tools — plain R functions the model may call directly — +are currently declared by setting a process option: + +```r +options(shiny.mcp.tools = list( + list( + name = "get_sample_stats", + description = "Summary statistics for a normal sample of size n.", + inputSchema = list( + type = "object", + properties = list(n = list(type = "integer")), + required = list("n") + ), + handler = function(args) { + x <- rnorm(args$n) + list(n = args$n, mean = mean(x), sd = stats::sd(x)) + } + ) +)) +``` + +Two problems: + +1. **Hand-written JSON Schema.** Authors write nested `inputSchema` lists by + hand — verbose and error-prone. +2. **Configuration via `options()`.** The adjacent R MCP ecosystem + (`mcptools`, James Wade's `shinymcp`) has converged on `ellmer::tool()` as + the tool-definition type and passes tools to a function, not an option. + +This feature shipped as experimental in #4407 and has **not** reached `main`, +so the API can change with no deprecation burden. + +## Scope + +**In scope (this PR):** author tools only — replace +`options(shiny.mcp.tools = ...)` with a function that accepts +`ellmer::tool()` objects. + +**Out of scope (another day):** the app-opening tool +(`options(shiny.mcp.tool = ...)`) and every other `shiny.mcp.*` option +(`shiny.mcp`, `appId`, `direct`, `displayModes`, `stdio`, `origin`) stay +exactly as they are. + +## Prior art + +The entire R MCP-authoring neighborhood already standardized on +`ellmer::tool()`: + +| Package | Author API | Tool def | +|---|---|---| +| `mcptools` | `mcp_server(tools = list(...))` | `ellmer::tool()` | +| `shinymcp` | `mcp_app(ui, tools)` | `ellmer::tool()` | +| **this design** | `registerMcpTool(...)` | `ellmer::tool()` | + +The MCP Apps SDK (`modelcontextprotocol/ext-apps`) is TypeScript and has no +cross-language tool-def abstraction — on the wire everything is plain JSON +Schema. `ellmer::tool()` is purely the R ergonomics layer above that wire +format, so adopting it does not diverge from MCP Apps. + +The registration *verb* (`registerMcpTool()`) rather than a `tools=` +constructor arg is the deliberate Scope-A choice: the on/off and transport +knobs stay as options this PR, so there is no constructor to hang `tools=` +off yet. + +## Public API + +One new exported function: + +```r +registerMcpTool( + ellmer::tool( + function(n) { + x <- rnorm(n) + list(n = n, mean = mean(x), sd = stats::sd(x)) + }, + name = "get_sample_stats", + description = "Summary statistics for a normal sample of size n.", + arguments = list(n = ellmer::type_integer("Sample size", required = TRUE)) + ) +) +``` + +- Accepts one or more `ellmer::ToolDef` objects via `...`. +- Called at the top level of `app.R`, before the app starts — the same + process-global, sessionless model author tools already use. +- Returns invisibly (`NULL`). + +### Name rationale + +Matches `registerInputHandler(type, fun)` — Shiny's existing string-keyed, +callable-holding registry — almost exactly (one callable per name). Leaves +room for a future `removeMcpTool(name)` if ever wanted. Chosen over the +`mcp`-prefixed `mcpTools()` because the `register*` precedent is the closer +structural analogue. + +### Registration semantics + +- Tools accumulate in `.globals$mcpAuthorTools`, a named list keyed by + `tool@name`. +- **Last-write-wins by name** (not an error). Re-sourcing `app.R` or + re-running `runApp()` during development re-registers cleanly. No `force` + argument (YAGNI). + +### Validation — eager, fail-fast + +Because registration is now an explicit call rather than a lazily-read +option, each argument is validated *at registration time*: + +- Must be an `ellmer::ToolDef` (checked with + `inherits(x, "ellmer::ToolDef")`) → else `stop()`. +- `tool@name` must not collide with reserved names: the app-opening tool's + name and the `_shiny_*` tunnel tool names → else `stop()`. + +This **deletes** the old "skip invalid spec + warn from `tools/list`" code +path in `mcpAuthorTools()`, which only existed because options are read +lazily. `mcpAuthorTools()` becomes a plain reader of validated state; its +`warn` parameter is removed. + +## Schema conversion + +Reuse the `mcptools::tool_as_json()` pattern verbatim so the conversion +stays byte-aligned for future upstreaming: + +```r +as_json <- getNamespace("ellmer")[["as_json"]] +inputSchema <- compact(as_json(ellmer::Provider("dummy", "dummy", "dummy"), tool@arguments)) +inputSchema$description <- NULL +if (is.null(inputSchema$properties)) { + inputSchema$properties <- structure(list(), names = character()) +} +``` + +- The dummy `ellmer::Provider()` needs no API key; `as_json()` dispatches to + the provider-agnostic base method for `Type` objects and emits standard + JSON Schema. +- `ellmer::as_json` is not exported; access it via + `getNamespace("ellmer")[["as_json"]]` exactly as `mcptools` does. Guard by + pinning a minimum `ellmer` version in `Suggests` (the version providing the + S7 `ToolDef`/`Provider`/`as_json` surface used here). Pin `>= 0.4.0` to + match the version verified against during implementation; relax only if a + lower bound is confirmed to expose the same surface. +- Tool `title` and `annotations` pass through into the `tools/list` entry if + present (cheap fidelity, mirrors `tool_as_json`). + +The resulting `tools/list` entry for an author tool is unchanged in shape +from today (`name`, `description`, `inputSchema`, optional `title`/ +`annotations`) — only its *source* changes from a hand-written list to an +ellmer conversion. + +## Handler invocation + +An `ellmer::ToolDef` *is* the underlying function, so `mcpAuthorToolCall()` +changes its call convention: + +```r +# before +tryCatch(tool$handler(args), error = function(e) e) +# after +tryCatch(rlang::exec(tool, !!!args), error = function(e) e) +``` + +Arguments are spread as named parameters directly, rather than passed as a +single `args` list. **Return-value handling is unchanged:** + +- character / numeric / logical → text content +- list → `structuredContent` + JSON text +- promises → resolved via `hybrid_chain` +- errors → `isError` result + +(`ellmer::ContentToolResult` return handling is out of scope; author tools +return plain values as today.) + +## Dependency + +`ellmer` moves to `Suggests`. `registerMcpTool()` calls +`rlang::check_installed("ellmer")` (rlang is already imported) with an +actionable message. Nothing in the core MCP request path touches ellmer +unless a tool has been registered — the conversion runs lazily from +`tools/list`, and if a tool is registered ellmer is by definition present. + +## Files touched + +- `R/mcp-server.R` — `mcpAuthorTools()` reads `.globals$mcpAuthorTools` + (drop the `warn` path and the `getOption` read); new schema-conversion + helper; `mcpAuthorToolCall()` uses `rlang::exec()`. +- **New `R/mcp-tools.R`** — `registerMcpTool()` + roxygen. Rewrite the + "Additional tools" `@section` in `R/mcp-session.R` to point at it. +- `R/globals.R` (or wherever `.globals` fields are initialised) — default + `mcpAuthorTools` to an empty named list if needed. +- `DESCRIPTION` — add `ellmer (>= 0.4.0)` to `Suggests`. +- `NAMESPACE` — export `registerMcpTool` (via roxygen / `devtools::document()`). +- `man/` — regenerate; add the new topic to + `tools/documentation/pkgdown.yml` under the "MCP Apps" section. +- `NEWS.md` — note the author-tool API is `registerMcpTool()` + + `ellmer::tool()` (fold into the #4407 entry). +- `mcp/demo-app`, `mcp/demo-app2` — migrate `options(shiny.mcp.tools = ...)` + to `registerMcpTool()`. +- `mcp/architecture.md` and the `./mcp` mirrors — update the author-tools + section (standing preference: keep repo-root `mcp/` docs current). + +## Testing + +All MCP author-tool tests gated with `skip_if_not_installed("ellmer")`. + +- `tools/list` emits the correct JSON Schema for an `ellmer::tool()` with + typed arguments (raw-JSON assertion, since R-side list parsing hides the + named-list-serializes-as-object trap noted in project history). +- A `tools/call` against a registered `ellmer::tool()` invokes the function + with spread named args and returns text / `structuredContent` correctly. +- Registering two tools with the same name → last wins. +- Registering a tool whose name is reserved (app tool, `_shiny_*`) → error. +- `registerMcpTool()` errors clearly when passed a non-`ToolDef`. +- (If feasible in CI) `registerMcpTool()` errors when ellmer is not + installed — otherwise covered by the `check_installed` call path. + +## Non-goals / explicit exclusions + +- No `force` argument, no `removeMcpTool()` (can be added later). +- No `options(shiny.mcp.tools = ...)` fallback — the function is the only + path. +- No changes to the app-opening tool or any other `shiny.mcp.*` option. +- No `ellmer::ContentToolResult` return-value handling. diff --git a/mcp/implementation-plan-register-mcp-tool.md b/mcp/implementation-plan-register-mcp-tool.md new file mode 100644 index 0000000000..9603b688c5 --- /dev/null +++ b/mcp/implementation-plan-register-mcp-tool.md @@ -0,0 +1,638 @@ +# registerMcpTool() Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace `options(shiny.mcp.tools = list(...))` with an exported `registerMcpTool()` function that accepts `ellmer::tool()` objects as MCP author-tool definitions. + +**Architecture:** Author tools are stored in process-global `.globals$mcpAuthorTools` (named list keyed by tool name). `registerMcpTool()` validates and registers `ellmer::ToolDef` objects eagerly. `tools/list` converts each ToolDef's typed `@arguments` to JSON Schema via the same dummy-provider `as_json()` path `mcptools` uses; `tools/call` invokes the ToolDef with `rlang::exec()`. Return-value handling is unchanged. + +**Tech Stack:** R, ellmer (Suggests), rlang (Imports, already present), testthat 3e, withr. + +## Global Constraints + +- Scope is **author tools only**. The app-opening tool (`options(shiny.mcp.tool)`, read by `mcpToolInfo()`) and every other `shiny.mcp.*` option stay unchanged. +- `options(shiny.mcp.tools = ...)` is **removed entirely** — no fallback. `registerMcpTool()` is the only path. +- `ellmer` is a **Suggests** dependency, pinned `>= 0.4.0`. Gate use with `rlang::check_installed("ellmer")`. +- Reuse the `mcptools::tool_as_json()` conversion verbatim (`getNamespace("ellmer")[["as_json"]]` + a dummy `ellmer::Provider()`) to stay upstream-aligned. +- Registration is **last-write-wins by name** (no error on duplicate, no `force` arg). +- All new/changed MCP author-tool tests are gated with `skip_if_not_installed("ellmer")`. +- Reference the design at `mcp/design-register-mcp-tool.md`. + +--- + +### Task 1: `registerMcpTool()` — registration + eager validation + +**Files:** +- Create: `R/mcp-tools.R` +- Modify: `R/globals.R` (initialise `.globals$mcpAuthorTools`) +- Modify: `R/mcp-server.R` (add `mcpReservedToolNames()` helper) +- Modify: `DESCRIPTION` (add `ellmer` to Suggests) +- Test: `tests/testthat/test-mcp-tools.R` (new) +- Test: `tests/testthat/helper-mcp.R` (add `local_mcp_tools()`) + +**Interfaces:** +- Produces: `registerMcpTool(...)` — exported; accepts one or more `ellmer::ToolDef` objects; writes each to `.globals$mcpAuthorTools[[tool@name]]`; returns `invisible()`. +- Produces: `mcpReservedToolNames()` — internal; returns `character()` of names an author tool may not use (`mcpToolInfo()$name` plus the `_shiny_*` tunnel tool names). +- Produces: `.globals$mcpAuthorTools` — named list of `ellmer::ToolDef`, keyed by name. + +- [ ] **Step 1: Add the test-isolation helper** + +In `tests/testthat/helper-mcp.R`, append: + +```r +# Reset registered MCP author tools around a test (registerMcpTool() writes +# to process-global .globals$mcpAuthorTools). +local_mcp_tools <- function(env = parent.frame()) { + old <- .globals$mcpAuthorTools + withr::defer(.globals$mcpAuthorTools <- old, envir = env) + .globals$mcpAuthorTools <- list() +} +``` + +- [ ] **Step 2: Write the failing tests** + +Create `tests/testthat/test-mcp-tools.R`: + +```r +test_that("registerMcpTool() stores ellmer tools by name (last-write-wins)", { + skip_if_not_installed("ellmer") + local_mcp_tools() + + registerMcpTool( + ellmer::tool(function(n) n, name = "echo_n", + description = "Echo n.", + arguments = list(n = ellmer::type_integer("n", required = TRUE))) + ) + expect_named(mcpAuthorTools(), "echo_n") + expect_true(inherits(mcpAuthorTools()[["echo_n"]], "ellmer::ToolDef")) + + # Re-registering the same name replaces, does not error or duplicate. + registerMcpTool( + ellmer::tool(function(n) n * 2, name = "echo_n", + description = "Echo 2n.", + arguments = list(n = ellmer::type_integer("n", required = TRUE))) + ) + expect_length(mcpAuthorTools(), 1) + expect_equal(mcpAuthorTools()[["echo_n"]]@description, "Echo 2n.") +}) + +test_that("registerMcpTool() accepts multiple tools in one call", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool(function() 1, name = "a", description = "a"), + ellmer::tool(function() 2, name = "b", description = "b") + ) + expect_setequal(names(mcpAuthorTools()), c("a", "b")) +}) + +test_that("registerMcpTool() rejects non-ToolDef arguments", { + skip_if_not_installed("ellmer") + local_mcp_tools() + expect_error( + registerMcpTool(list(name = "x", handler = function(args) 1)), + "ellmer::tool" + ) +}) + +test_that("registerMcpTool() rejects reserved tool names", { + skip_if_not_installed("ellmer") + local_mcp_tools() + expect_error( + registerMcpTool( + ellmer::tool(function() 1, name = "_shiny_send", description = "no") + ), + "reserved" + ) +}) +``` + +- [ ] **Step 3: Run tests to verify they fail** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_file("tests/testthat/test-mcp-tools.R")'` +Expected: FAIL — `could not find function "registerMcpTool"`. + +- [ ] **Step 4: Initialise the global state** + +In `R/globals.R`, immediately after `.globals <- new.env(parent = emptyenv())`, add: + +```r +.globals$mcpAuthorTools <- list() +``` + +- [ ] **Step 5: Add the reserved-names helper** + +In `R/mcp-server.R`, add (near `mcpToolInfo()`): + +```r +# Tool names an author may not reuse: the app-opening tool and the internal +# _shiny_* tunnel tools. +mcpReservedToolNames <- function() { + c( + mcpToolInfo()$name, + vapply(mcpTunnelToolsList(), function(t) t$name, character(1)) + ) +} +``` + +- [ ] **Step 6: Write `registerMcpTool()`** + +Create `R/mcp-tools.R`: + +```r +#' Register an MCP tool the model can call directly +#' +#' @description +#' `r lifecycle::badge("experimental")` +#' +#' When a Shiny app is served as an MCP App (`options(shiny.mcp = TRUE)`), +#' `registerMcpTool()` exposes plain R functions as MCP tools the model may +#' call directly, in addition to the tool that opens the app. Define each +#' tool with [ellmer::tool()] and register it at the top level of your +#' `app.R`, before the app starts: +#' +#' ```r +#' library(shiny) +#' options(shiny.mcp = TRUE) +#' +#' registerMcpTool( +#' ellmer::tool( +#' function(n) { +#' x <- rnorm(n) +#' list(n = n, mean = mean(x), sd = stats::sd(x)) +#' }, +#' name = "get_sample_stats", +#' description = "Summary statistics for a normal sample of size n.", +#' arguments = list(n = ellmer::type_integer("Sample size", required = TRUE)) +#' ) +#' ) +#' ``` +#' +#' Handlers run in the server R process, outside of any Shiny session, and +#' may return a character vector (sent as text), a list (sent as JSON +#' `structuredContent`), or a promise. Errors are reported to the model as +#' tool errors. +#' +#' Tools are keyed by their `name`; registering a tool whose name is already +#' registered replaces it. A tool may not use a name reserved by Shiny's MCP +#' server (the app-opening tool or the internal `_shiny_*` tunnel tools). +#' +#' @param ... One or more tools created with [ellmer::tool()]. +#' +#' @return Invisibly, `NULL`. +#' +#' @seealso [mcpToolInput()] and the other `mcp*` session helpers. +#' @export +registerMcpTool <- function(...) { + rlang::check_installed("ellmer", "to define MCP tools with `ellmer::tool()`.") + tools <- list(...) + reserved <- mcpReservedToolNames() + for (tool in tools) { + if (!inherits(tool, "ellmer::ToolDef")) { + stop( + "`registerMcpTool()` accepts tools created with `ellmer::tool()`; ", + "received an object of class '", class(tool)[1], "'.", + call. = FALSE + ) + } + name <- tool@name + if (name %in% reserved) { + stop( + "Cannot register an MCP tool named '", name, "': that name is ", + "reserved by Shiny's MCP server.", + call. = FALSE + ) + } + .globals$mcpAuthorTools[[name]] <- tool + } + invisible() +} +``` + +- [ ] **Step 7: Add ellmer to Suggests** + +In `DESCRIPTION`, add to the `Suggests:` list (keep alphabetical order): + +``` + ellmer (>= 0.4.0), +``` + +- [ ] **Step 8: Regenerate docs** + +Run: `R -q -e 'devtools::document()'` +Expected: `NAMESPACE` gains `export(registerMcpTool)`; `man/registerMcpTool.Rd` created. + +- [ ] **Step 9: Run tests to verify they pass** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_file("tests/testthat/test-mcp-tools.R")'` +Expected: PASS (4 tests). `mcpAuthorTools()` is exercised as a reader here; Task 2 changes its body. + +- [ ] **Step 10: Commit** + +```bash +git add R/mcp-tools.R R/globals.R R/mcp-server.R DESCRIPTION NAMESPACE man/registerMcpTool.Rd tests/testthat/test-mcp-tools.R tests/testthat/helper-mcp.R +git commit -m "feat: registerMcpTool() registers ellmer tools as MCP author tools" +``` + +--- + +### Task 2: Convert registered ellmer tools into `tools/list` JSON Schema + +**Files:** +- Modify: `R/mcp-server.R` (`mcpAuthorTools()`, `mcpToolsList` author-tool block; add `mcpToolInputSchema()`) +- Modify: `tests/testthat/test-mcp-server.R` (replace the option-based `tools/list` test) + +**Interfaces:** +- Consumes: `.globals$mcpAuthorTools` and `mcpReservedToolNames()` from Task 1. +- Produces: `mcpAuthorTools()` — internal; now returns `.globals$mcpAuthorTools %||% list()` (no `warn` parameter). +- Produces: `mcpToolInputSchema(tool)` — internal; returns a JSON Schema list for an `ellmer::ToolDef`'s `@arguments`. + +- [ ] **Step 1: Write the failing test** + +In `tests/testthat/test-mcp-server.R`, **replace** the test `"author-declared tools appear in tools/list and execute"` (the `tools/list` half) with: + +```r +test_that("registered author tools appear in tools/list with JSON schema", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool( + function(x, y) list(sum = x + y), + name = "add_numbers", + description = "Add two numbers.", + arguments = list( + x = ellmer::type_number("x", required = TRUE), + y = ellmer::type_number("y", required = TRUE) + ) + ), + ellmer::tool(function() "Hello from R", name = "get_motd", + description = "Get the message of the day.") + ) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + out <- mcp_post(h, "tools/list") + + # tools must serialize as a JSON array, not an object + expect_null(names(out$result$tools)) + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true(all(c("add_numbers", "get_motd") %in% tool_names)) + + add_tool <- out$result$tools[[which(tool_names == "add_numbers")]] + expect_equal(add_tool$inputSchema$type, "object") + expect_equal(add_tool$inputSchema$properties$x$type, "number") + # required must be a JSON array even when derived from ellmer + expect_equal(add_tool$inputSchema$required, list("x", "y")) + expect_null(add_tool$inputSchema$description) + + # a tool with no arguments still advertises an object schema with properties + motd <- out$result$tools[[which(tool_names == "get_motd")]] + expect_equal(motd$inputSchema$type %||% "object", "object") +}) +``` + +Note: `mcp_post()` returns parsed-from-JSON structures, so `required` arrives as a `list`. This is the raw-JSON assertion that catches the named-list-serializes-as-object trap. + +- [ ] **Step 2: Run test to verify it fails** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_file("tests/testthat/test-mcp-server.R", desc = "registered author tools appear in tools/list with JSON schema")'` +Expected: FAIL — old `mcpAuthorTools()` still reads the removed option / no conversion, so `add_numbers` is absent. + +- [ ] **Step 3: Add the schema-conversion helper** + +In `R/mcp-server.R`, add near `mcpAuthorTools()`: + +```r +# Convert an ellmer ToolDef's typed @arguments into a JSON Schema list for +# tools/list. Mirrors mcptools::tool_as_json() so the two stay aligned: a +# dummy provider drives ellmer's provider-agnostic base as_json() method. +mcpToolInputSchema <- function(tool) { + as_json <- getNamespace("ellmer")[["as_json"]] + schema <- as_json(ellmer::Provider("dummy", "dummy", "dummy"), tool@arguments) + schema$description <- NULL + if (is.null(schema$properties)) { + schema$properties <- empty_named_list() + } + dropNulls(schema) +} +``` + +- [ ] **Step 4: Simplify `mcpAuthorTools()` to read the global** + +In `R/mcp-server.R`, **replace** the entire `mcpAuthorTools <- function(warn = FALSE) { ... }` definition (and its comment block) with: + +```r +# Author-declared tools registered via registerMcpTool(). Named list of +# ellmer::ToolDef objects, keyed by tool name; validation happens eagerly at +# registration time. +mcpAuthorTools <- function() { + .globals$mcpAuthorTools %||% list() +} +``` + +- [ ] **Step 5: Update the `tools/list` author-tool block** + +In `R/mcp-server.R` `mcpToolsList` (the `unname(c(...))` builder), **replace** the author-tool `lapply`: + +```r + lapply(mcpAuthorTools(warn = TRUE), function(tool) { + list( + name = tool$name, + description = tool$description, + inputSchema = tool$inputSchema %||% + list(type = "object", properties = empty_named_list()) + ) + }) +``` + +with: + +```r + lapply(mcpAuthorTools(), function(tool) { + dropNulls(list( + name = tool@name, + title = tool@annotations$title, + description = tool@description, + inputSchema = mcpToolInputSchema(tool) + )) + }) +``` + +- [ ] **Step 6: Run test to verify it passes** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_file("tests/testthat/test-mcp-server.R", desc = "registered author tools appear in tools/list with JSON schema")'` +Expected: PASS. + +- [ ] **Step 7: Commit** + +```bash +git add R/mcp-server.R tests/testthat/test-mcp-server.R +git commit -m "feat: convert registered ellmer tools to MCP tools/list schema" +``` + +--- + +### Task 3: Invoke registered tools on `tools/call` + +**Files:** +- Modify: `R/mcp-server.R` (`mcpAuthorToolCall()`) +- Modify: `tests/testthat/test-mcp-server.R` (replace the remaining option-based execute/error/async/collision tests) + +**Interfaces:** +- Consumes: `mcpAuthorTools()` (returns ToolDefs) and `mcpToolCall()`'s existing lookup `mcpAuthorTools()[[name]]`. +- Produces: `mcpAuthorToolCall(tool, params, id)` — now calls the ToolDef via `rlang::exec()`. + +- [ ] **Step 1: Write the failing tests** + +In `tests/testthat/test-mcp-server.R`, **add** the execute half back and **replace** the error/async/collision tests: + +```r +test_that("registered author tools execute via tools/call", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool(function(x, y) list(sum = x + y), name = "add_numbers", + description = "Add two numbers.", + arguments = list( + x = ellmer::type_number("x", required = TRUE), + y = ellmer::type_number("y", required = TRUE) + )), + ellmer::tool(function() "Hello from R", name = "get_motd", + description = "Get the message of the day.") + ) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + + res <- mcp_post(h, "tools/call", + params = list(name = "add_numbers", arguments = list(x = 2, y = 40))) + expect_equal(res$result$structuredContent$sum, 42) + expect_match(res$result$content[[1]]$text, "42") + + res <- mcp_post(h, "tools/call", + params = list(name = "get_motd", arguments = empty_named_list())) + expect_equal(res$result$content[[1]]$text, "Hello from R") + expect_null(res$result$structuredContent) +}) + +test_that("author tool errors become isError results, not crashes", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool(function(why) stop("kaboom: ", why), name = "boom", + description = "Always fails.", + arguments = list(why = ellmer::type_string("why", required = TRUE))) + ) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + res <- mcp_post(h, "tools/call", + params = list(name = "boom", arguments = list(why = "testing"))) + expect_true(isTRUE(res$result$isError)) + expect_match(res$result$content[[1]]$text, "kaboom: testing") +}) + +test_that("async author tools (promises) are supported", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool( + function() promises::promise(function(resolve, reject) { + later::later(function() resolve(list(answer = 42)), 0.1) + }), + name = "slow_answer", description = "Answers later.") + ) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + res <- mcp_post(h, "tools/call", + params = list(name = "slow_answer", arguments = empty_named_list())) + expect_equal(res$result$structuredContent$answer, 42) +}) +``` + +Then **delete** the old test `"invalid or colliding author tools are skipped with a warning"` — collision/validation is now eager and covered by Task 1's `test-mcp-tools.R`. + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_file("tests/testthat/test-mcp-server.R")'` +Expected: FAIL on the execute/error/async tests — `mcpAuthorToolCall()` still calls `tool$handler(args)`, which is `NULL` for a ToolDef. + +- [ ] **Step 3: Update `mcpAuthorToolCall()`** + +In `R/mcp-server.R`, **replace** the `hybrid_chain(...)` seed line in `mcpAuthorToolCall()`: + +```r +mcpAuthorToolCall <- function(tool, params, id) { + args <- params$arguments %||% empty_named_list() + hybrid_chain( + tryCatch(tool$handler(args), error = function(e) e), +``` + +with: + +```r +mcpAuthorToolCall <- function(tool, params, id) { + args <- params$arguments %||% list() + hybrid_chain( + tryCatch(rlang::exec(tool, !!!args), error = function(e) e), +``` + +(The rest of the function — result/error handling — is unchanged.) + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_file("tests/testthat/test-mcp-server.R")'` +Expected: PASS (all remaining tests in the file). + +- [ ] **Step 5: Full MCP test sweep** + +Run: `R -q -e 'pkgload::load_all(); testthat::test_dir("tests/testthat", filter = "mcp")'` +Expected: PASS — confirms no other MCP test referenced `shiny.mcp.tools`. + +- [ ] **Step 6: Commit** + +```bash +git add R/mcp-server.R tests/testthat/test-mcp-server.R +git commit -m "feat: invoke registered ellmer tools on MCP tools/call" +``` + +--- + +### Task 4: Documentation — session help, pkgdown, NEWS + +**Files:** +- Modify: `R/mcp-session.R` (rewrite the "Additional tools" `@section`) +- Modify: `tools/documentation/pkgdown.yml` (add `registerMcpTool` to the MCP Apps section) +- Modify: `NEWS.md` +- Regenerate: `man/` + +**Interfaces:** none (docs only). + +- [ ] **Step 1: Rewrite the "Additional tools" section** + +In `R/mcp-session.R`, **replace** the `@section Additional tools:` block (currently describing `options(shiny.mcp.tools = list(...))` and its `list(name, description, inputSchema, handler)` example, lines ~53-80) with: + +```r +#' @section Additional tools: +#' Beyond the tool that opens the app, authors can expose plain R functions +#' as MCP tools the model may call directly, with [registerMcpTool()] and +#' [ellmer::tool()]. See `?registerMcpTool` for details. +``` + +- [ ] **Step 2: Add the pkgdown reference entry** + +In `tools/documentation/pkgdown.yml`, under the existing "MCP Apps" section's `contents:`, add: + +```yaml + - registerMcpTool +``` + +- [ ] **Step 3: Update NEWS** + +In `NEWS.md`, locate the bullet added for the MCP Apps feature (referencing `#4407`) and ensure it names the author-tool API. If a distinct bullet is warranted, add under the current development version: + +``` +* Shiny apps served as MCP Apps can expose additional model-callable tools + with `registerMcpTool()`, using `ellmer::tool()` definitions (#4407). +``` + +- [ ] **Step 4: Regenerate docs** + +Run: `R -q -e 'devtools::document()'` +Expected: `man/mcp-session.Rd` and `man/registerMcpTool.Rd` updated with cross-links; no errors. + +- [ ] **Step 5: Verify examples/links resolve** + +Run: `R -q -e 'pkgload::load_all(); tools::checkRd("man/registerMcpTool.Rd"); tools::checkRd("man/mcp-session.Rd")'` +Expected: no `checkRd` warnings. + +- [ ] **Step 6: Commit** + +```bash +git add R/mcp-session.R tools/documentation/pkgdown.yml NEWS.md man/ +git commit -m "docs: document registerMcpTool() and drop shiny.mcp.tools option" +``` + +--- + +### Task 5: Migrate demo apps and architecture notes + +**Files:** +- Modify: `mcp/demo-app/app.R` (and any file setting `options(shiny.mcp.tools = ...)`) +- Modify: `mcp/demo-app2/app.R` (same) +- Modify: `mcp/architecture.md` (author-tools description) + +**Interfaces:** none (docs/demos). + +- [ ] **Step 1: Find the option usages in the demos** + +Run: `grep -rn "shiny.mcp.tools" mcp/` +Expected: hits in `mcp/demo-app` and/or `mcp/demo-app2`. Record each block. + +- [ ] **Step 2: Rewrite each `options(shiny.mcp.tools = ...)` as `registerMcpTool()`** + +For each demo, convert the option's `list(name=, description=, inputSchema=, handler=)` spec into `registerMcpTool(ellmer::tool(, name=, description=, arguments=))`. Example (get_sample_stats), replacing: + +```r +options(shiny.mcp.tools = list(list( + name = "get_sample_stats", + description = "Summary statistics for a normal sample of size n.", + inputSchema = list(type = "object", + properties = list(n = list(type = "integer")), required = list("n")), + handler = function(args) { + x <- rnorm(args$n); list(n = args$n, mean = mean(x), sd = stats::sd(x)) + } +))) +``` + +with: + +```r +registerMcpTool( + ellmer::tool( + function(n) { x <- rnorm(n); list(n = n, mean = mean(x), sd = stats::sd(x)) }, + name = "get_sample_stats", + description = "Summary statistics for a normal sample of size n.", + arguments = list(n = ellmer::type_integer("Sample size", required = TRUE)) + ) +) +``` + +Convert `demo-app2`'s tool(s) the same way (map each `inputSchema` property to the matching `ellmer::type_*()`, and change the handler signature from `function(args)` reading `args$foo` to named parameters `function(foo, ...)`). + +- [ ] **Step 3: Smoke-test one demo boots and lists the tool** + +Run: `grep -rn "shiny.mcp.tools" mcp/` +Expected: no matches remaining. + +Run (from repo root, adjust app path): +```bash +R -q -e 'pkgload::load_all(); options(shiny.mcp = TRUE); source("mcp/demo-app/app.R", local = new.env()); cat(vapply(shiny:::mcpAuthorTools(), function(t) t@name, character(1)), "\n")' +``` +Expected: prints the demo's tool name(s) (e.g. `get_sample_stats`), confirming `registerMcpTool()` ran at source time. + +- [ ] **Step 4: Update `mcp/architecture.md`** + +In `mcp/architecture.md`, update the two author-tool references (the bullet near line 74 and the table row near line 220) from `options(shiny.mcp.tools = list(...))` to `registerMcpTool(ellmer::tool(...))`, noting the ellmer→JSON-Schema conversion mirrors `mcptools::tool_as_json()`. + +- [ ] **Step 5: Commit** + +```bash +git add mcp/demo-app mcp/demo-app2 mcp/architecture.md +git commit -m "docs(mcp): migrate demo apps and architecture to registerMcpTool()" +``` + +--- + +## Self-Review + +**Spec coverage:** +- Public API `registerMcpTool(...)`, `...` of ToolDefs, invisible return → Task 1. +- Name rationale (mirrors registerInputHandler) → documented in spec; name used throughout. +- `.globals$mcpAuthorTools`, last-write-wins → Task 1 (Steps 4, 6; test in Step 2). +- Eager fail-fast validation (non-ToolDef, reserved name) → Task 1 (Step 6; tests Step 2). +- Drop lazy warn path → Task 2 Step 4 (mcpAuthorTools simplified); old warn test deleted Task 3 Step 1. +- Schema conversion via dummy-provider `as_json` → Task 2 Step 3, matching `mcptools::tool_as_json()`. +- `title` pass-through → Task 2 Step 5. +- Handler via `rlang::exec` + unchanged return handling → Task 3 Step 3. +- ellmer → Suggests (>= 0.4.0), `rlang::check_installed` → Task 1 Steps 6-7. +- Files touched (mcp-server, new mcp-tools, mcp-session section, DESCRIPTION, NAMESPACE, man, pkgdown, NEWS, demos, architecture) → Tasks 1-5. +- Tests gated with skip_if_not_installed → every author-tool test. +- Non-goals (no force/removeMcpTool, no option fallback, app tool untouched, no ContentToolResult) → respected; app tool via `mcpToolInfo()` left alone. + +**Placeholder scan:** none — all code and commands are concrete. + +**Type consistency:** `registerMcpTool` / `mcpAuthorTools()` (no args) / `mcpReservedToolNames()` / `mcpToolInputSchema(tool)` / `mcpAuthorToolCall(tool, params, id)` used consistently. ToolDefs accessed with `@name`, `@description`, `@arguments`, `@annotations$title` throughout. diff --git a/tests/testthat/helper-mcp.R b/tests/testthat/helper-mcp.R index 35a00c2f4f..8ee5c881d3 100644 --- a/tests/testthat/helper-mcp.R +++ b/tests/testthat/helper-mcp.R @@ -1,5 +1,13 @@ # Helpers for MCP Apps tests (test-mcp-*.R) +# Reset registered MCP author tools around a test (registerMcpTool() writes +# to process-global .globals$mcpAuthorTools). +local_mcp_tools <- function(env = parent.frame()) { + old <- .globals$mcpAuthorTools + withr::defer(.globals$mcpAuthorTools <- old, envir = env) + .globals$mcpAuthorTools <- list() +} + fakeRookInput <- function(bytes) { list(read = function(...) bytes, rewind = function() NULL) } diff --git a/tests/testthat/test-mcp-server.R b/tests/testthat/test-mcp-server.R index 1e6499c14a..6a70482ab7 100644 --- a/tests/testthat/test-mcp-server.R +++ b/tests/testthat/test-mcp-server.R @@ -99,108 +99,97 @@ test_that("createAppHandlers mounts /mcp only when enabled", { }) }) -test_that("author-declared tools appear in tools/list and execute", { - tools <- list( - list( +test_that("registered author tools appear in tools/list with JSON schema", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool( + function(x, y) list(sum = x + y), name = "add_numbers", description = "Add two numbers.", - inputSchema = list( - type = "object", - properties = list( - x = list(type = "number"), - y = list(type = "number") - ), - required = list("x", "y") - ), - handler = function(args) { - list(sum = args$x + args$y) - } + arguments = list( + x = ellmer::type_number("x", required = TRUE), + y = ellmer::type_number("y", required = TRUE) + ) ), - list( - name = "get_motd", - description = "Get the message of the day.", - handler = function(args) "Hello from R" - ) + ellmer::tool(function() "Hello from R", name = "get_motd", + description = "Get the message of the day.") ) - withr::with_options(list(shiny.mcp.tools = tools), { - h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) - - out <- mcp_post(h, "tools/list") - # tools must serialize as a JSON array, not an object - expect_null(names(out$result$tools)) - tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) - expect_true(all(c("add_numbers", "get_motd") %in% tool_names)) - add_tool <- out$result$tools[[which(tool_names == "add_numbers")]] - expect_equal(add_tool$inputSchema$properties$x$type, "number") - # Author tools are model-visible (no app-only visibility marker) - expect_null(add_tool$`_meta`$ui$visibility) - - res <- mcp_post(h, "tools/call", params = list( - name = "add_numbers", arguments = list(x = 2, y = 40) - )) - expect_equal(res$result$structuredContent$sum, 42) - expect_match(res$result$content[[1]]$text, "42") - - res <- mcp_post(h, "tools/call", params = list( - name = "get_motd", arguments = empty_named_list() - )) - expect_equal(res$result$content[[1]]$text, "Hello from R") - expect_null(res$result$structuredContent) - }) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + out <- mcp_post(h, "tools/list") + + # tools must serialize as a JSON array, not an object + expect_null(names(out$result$tools)) + tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) + expect_true(all(c("add_numbers", "get_motd") %in% tool_names)) + + add_tool <- out$result$tools[[which(tool_names == "add_numbers")]] + expect_equal(add_tool$inputSchema$type, "object") + expect_equal(add_tool$inputSchema$properties$x$type, "number") + # required must be a JSON array even when derived from ellmer + expect_equal(add_tool$inputSchema$required, list("x", "y")) + expect_null(add_tool$inputSchema$description) + + # a tool with no arguments still advertises an object schema with properties + motd <- out$result$tools[[which(tool_names == "get_motd")]] + expect_equal(motd$inputSchema$type %||% "object", "object") +}) + +test_that("registered author tools execute via tools/call", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool(function(x, y) list(sum = x + y), name = "add_numbers", + description = "Add two numbers.", + arguments = list( + x = ellmer::type_number("x", required = TRUE), + y = ellmer::type_number("y", required = TRUE) + )), + ellmer::tool(function() "Hello from R", name = "get_motd", + description = "Get the message of the day.") + ) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + + res <- mcp_post(h, "tools/call", + params = list(name = "add_numbers", arguments = list(x = 2, y = 40))) + expect_equal(res$result$structuredContent$sum, 42) + expect_match(res$result$content[[1]]$text, "42") + + res <- mcp_post(h, "tools/call", + params = list(name = "get_motd", arguments = empty_named_list())) + expect_equal(res$result$content[[1]]$text, "Hello from R") + expect_null(res$result$structuredContent) }) test_that("author tool errors become isError results, not crashes", { - tools <- list(list( - name = "boom", - description = "Always fails.", - handler = function(args) stop("kaboom: ", args$why) - )) - withr::with_options(list(shiny.mcp.tools = tools), { - h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) - res <- mcp_post(h, "tools/call", params = list( - name = "boom", arguments = list(why = "testing") - )) - expect_true(isTRUE(res$result$isError)) - expect_match(res$result$content[[1]]$text, "kaboom: testing") - }) + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool(function(why) stop("kaboom: ", why), name = "boom", + description = "Always fails.", + arguments = list(why = ellmer::type_string("why", required = TRUE))) + ) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + res <- mcp_post(h, "tools/call", + params = list(name = "boom", arguments = list(why = "testing"))) + expect_true(isTRUE(res$result$isError)) + expect_match(res$result$content[[1]]$text, "kaboom: testing") }) test_that("async author tools (promises) are supported", { - tools <- list(list( - name = "slow_answer", - description = "Answers later.", - handler = function(args) { - promises::promise(function(resolve, reject) { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool( + function() promises::promise(function(resolve, reject) { later::later(function() resolve(list(answer = 42)), 0.1) - }) - } - )) - withr::with_options(list(shiny.mcp.tools = tools), { - h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) - res <- mcp_post(h, "tools/call", params = list( - name = "slow_answer", arguments = empty_named_list() - )) - expect_equal(res$result$structuredContent$answer, 42) - }) -}) - -test_that("invalid or colliding author tools are skipped with a warning", { - tools <- list( - list(name = "_shiny_send", description = "collides", handler = function(args) 1), - list(name = "no_handler", description = "missing handler"), - list(name = "ok_tool", description = "fine", handler = function(args) "ok") + }), + name = "slow_answer", description = "Answers later.") ) - withr::with_options(list(shiny.mcp.tools = tools), { - h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) - warnings <- testthat::capture_warnings(out <- mcp_post(h, "tools/list")) - expect_length(warnings, 2) - expect_match(warnings, "_shiny_send|no_handler", all = TRUE) - tool_names <- vapply(out$result$tools, function(t) t$name, character(1)) - expect_true("ok_tool" %in% tool_names) - expect_false("no_handler" %in% tool_names) - # the colliding name resolves to the built-in tunnel tool, not the author's - expect_equal(sum(tool_names == "_shiny_send"), 1) - }) + h <- mcpHttpHandler(function(req) NULL, function(ws) TRUE) + res <- mcp_post(h, "tools/call", + params = list(name = "slow_answer", arguments = empty_named_list())) + expect_equal(res$result$structuredContent$answer, 42) }) test_that("mcpDirectBase honors option > Connect headers > request origin", { diff --git a/tests/testthat/test-mcp-tools.R b/tests/testthat/test-mcp-tools.R new file mode 100644 index 0000000000..d54881d3cb --- /dev/null +++ b/tests/testthat/test-mcp-tools.R @@ -0,0 +1,51 @@ +test_that("registerMcpTool() stores ellmer tools by name (last-write-wins)", { + skip_if_not_installed("ellmer") + local_mcp_tools() + + registerMcpTool( + ellmer::tool(function(n) n, name = "echo_n", + description = "Echo n.", + arguments = list(n = ellmer::type_integer("n", required = TRUE))) + ) + expect_named(mcpAuthorTools(), "echo_n") + expect_true(inherits(mcpAuthorTools()[["echo_n"]], "ellmer::ToolDef")) + + # Re-registering the same name replaces, does not error or duplicate. + registerMcpTool( + ellmer::tool(function(n) n * 2, name = "echo_n", + description = "Echo 2n.", + arguments = list(n = ellmer::type_integer("n", required = TRUE))) + ) + expect_length(mcpAuthorTools(), 1) + expect_equal(S7::prop(mcpAuthorTools()[["echo_n"]], "description"), "Echo 2n.") +}) + +test_that("registerMcpTool() accepts multiple tools in one call", { + skip_if_not_installed("ellmer") + local_mcp_tools() + registerMcpTool( + ellmer::tool(function() 1, name = "a", description = "a"), + ellmer::tool(function() 2, name = "b", description = "b") + ) + expect_setequal(names(mcpAuthorTools()), c("a", "b")) +}) + +test_that("registerMcpTool() rejects non-ToolDef arguments", { + skip_if_not_installed("ellmer") + local_mcp_tools() + expect_error( + registerMcpTool(list(name = "x", handler = function(args) 1)), + "ellmer::tool" + ) +}) + +test_that("registerMcpTool() rejects reserved tool names", { + skip_if_not_installed("ellmer") + local_mcp_tools() + expect_error( + registerMcpTool( + ellmer::tool(function() 1, name = "_shiny_send", description = "no") + ), + "reserved" + ) +}) diff --git a/tools/documentation/pkgdown.yml b/tools/documentation/pkgdown.yml index 7e2be0d6cd..74c37862bf 100644 --- a/tools/documentation/pkgdown.yml +++ b/tools/documentation/pkgdown.yml @@ -168,6 +168,7 @@ reference: desc: Serve Shiny apps as MCP Apps and interact with the MCP host (experimental). contents: - mcp-session + - registerMcpTool - title: Utility functions desc: Miscellaneous utilities that may be useful to advanced users or when extending Shiny. contents: