From f319b4ae33fb8c6dc586326dcfb27c0ad00f2f8b Mon Sep 17 00:00:00 2001 From: Ivan Miletic Date: Sun, 16 Aug 2026 21:01:43 +0200 Subject: [PATCH 1/3] feat: pull command --- CHANGELOG.md | 3 +- README.md | 244 +++++++++++++++++++++++++++++ actions/pull/action.yml | 139 ++++++++++++++++ package.json | 4 +- release-please-config.json | 3 +- src/api/client.ts | 158 +++++++++++++++++++ src/api/extract.ts | 208 ++++++++++++++++++++++++ src/api/zip.ts | 80 ++++++++++ src/commands/pull.ts | 186 ++++++++++++++++++++++ src/main.ts | 57 ++++++- templates/azure-pipelines-pull.yml | 138 ++++++++++++++++ templates/gitlab-ci-pull.yml | 68 ++++++++ 12 files changed, 1281 insertions(+), 7 deletions(-) create mode 100644 actions/pull/action.yml create mode 100644 src/api/client.ts create mode 100644 src/api/extract.ts create mode 100644 src/api/zip.ts create mode 100644 src/commands/pull.ts create mode 100644 templates/azure-pipelines-pull.yml create mode 100644 templates/gitlab-ci-pull.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 629ff7f..d904374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,9 @@ ## [0.2.1](https://github.com/gorules/cli/compare/cli-v0.2.0...cli-v0.2.1) (2026-03-20) - ### Bug Fixes -* improve mcp context size ([#3](https://github.com/gorules/cli/issues/3)) ([5044971](https://github.com/gorules/cli/commit/5044971f8a7cce38b1acbfbb0e27ab433297c321)) +- improve mcp context size ([#3](https://github.com/gorules/cli/issues/3)) ([5044971](https://github.com/gorules/cli/commit/5044971f8a7cce38b1acbfbb0e27ab433297c321)) ## [0.2.0](https://github.com/gorules/cli/compare/cli-v0.1.0...cli-v0.2.0) (2026-03-01) diff --git a/README.md b/README.md index fd41c8b..3bdff29 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,250 @@ Or run directly with npx (e.g. mcp start): npx @gorules/cli mcp start ``` +## Pulling rules into a pipeline + +`gorules pull` resolves a target in BRMS and downloads the matching rules artifact. It is the +building block for shipping rules from BRMS into your own infrastructure: a CI job pulls the +artifact and uploads it wherever your runtime reads it from. + +```bash +export GORULES_URL=https://acme.gorules.io +export GORULES_TOKEN=... # project access token, read scope is enough + +gorules pull --project pricing --target env:production --out ./dist +aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursive +``` + +### Targets + +| Target | Resolves to | +| ------------------- | ------------------------------------------------- | +| `main` (default) | latest commit on the default branch | +| `branch:` | latest commit on that branch | +| `commit:` | that exact commit, pinned | +| `release:` | that release, by semantic version or id | +| `env:` | whichever release is deployed to that environment | + +### Options + +| Flag | Env | Description | +| --------------- | ----------------- | ------------------------------------------------------------------------------------------------- | +| `-p, --project` | `GORULES_PROJECT` | Project key or id | +| `-t, --target` | `GORULES_TARGET` | Target to resolve (default `main`) | +| `-o, --out` | | Output directory (default `.`) | +| `--unpack` | | Extract the archive instead of writing it | +| `--delete` | | With `--unpack`: delete files not in the artifact so the directory mirrors the target exactly | +| `--name` | | Output file name (zip) or sub-directory name (dir); defaults to the project key with no extension | +| `--current` | | Release or commit id you already hold; exits `3` when unchanged | +| `-u, --url` | `GORULES_URL` | BRMS URL | +| `--token` | `GORULES_TOKEN` | Access token | +| `--json` | | Print the result as JSON on stdout | + +### Naming the output + +The default writes `` with **no** `.zip` suffix, because the agent's S3, GCS and Azure +Blob providers use the object name verbatim as the project key: upload `pricing.zip` and the agent +serves a project literally called `pricing.zip`. + +The agent's local `zip` provider is the opposite -- it reads `/.zip` and strips the +suffix itself -- so that destination needs it back: + +```bash +gorules pull --project pricing --name pricing.zip --out ./rules +``` + +With `--unpack`, `--name` is the sub-directory to extract into (default: the project key, which is +the layout the agent's `filesystem` provider expects). Pass `--name .` to extract straight into +`--out`, which is what you want when baking rules into a container image. + +Extraction behaves like `aws s3 sync`: byte-identical files are left untouched, changed files are +written atomically (temp file + rename, so a concurrent reader never sees a partial write), and +files the artifact does not carry are preserved. Add `--delete` for `s3 sync --delete` semantics: +the directory mirrors the target exactly, so rules deleted in BRMS are deleted on disk too. As a +guard against wiping a directory it does not own, `--delete` refuses a non-empty destination that +has no `.config/project.json` from a previous pull, and deletions only run after every new file has +been written. + +### Examples + +Object storage that the agent watches -- one archive per project, no extension: + +```bash +gorules pull --project pricing --target env:production --out ./dist +aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursive +``` + +A volume the agent reads with its `filesystem` provider -- unpacked, one directory per project: + +```bash +gorules pull --project pricing --target env:production --out /srv/rules --unpack +# /srv/rules/pricing/... +``` + +Baked into a container image, pinned to an exact release so the build is reproducible: + +```bash +gorules pull --project pricing --target release:1.4.2 --out ./rules --unpack --name . +# ./rules/*.json + ./rules/.config/project.json, ready for COPY +``` + +Scheduled job that does nothing when production has not moved: + +```bash +gorules pull --project pricing --target env:production --current "$LAST_RELEASE_ID" --out ./dist +case $? in + 0) aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursive ;; + 3) echo "unchanged" ;; + *) exit 1 ;; +esac +``` + +### Exit codes + +| Code | Meaning | +| ---- | ---------------------------------------------------- | +| `0` | Artifact downloaded | +| `1` | Error | +| `2` | Usage error (missing or invalid arguments) | +| `3` | Nothing to do (`--current` matched what is deployed) | +| `4` | No release is deployed to the target | + +Pin the version in a pipeline rather than tracking `latest`: + +```bash +npx @gorules/cli@0.2.1 pull --project pricing --target env:production +``` + +## GitHub Actions + +Composite actions live under `actions/`, in this repository, so the tag you pin is the CLI version +you get. + +```yaml +on: + workflow_dispatch: + inputs: + payload: + description: Set by BRMS when a webhook triggers the run; the action picks it up automatically + required: false + type: string + +jobs: + rules: + runs-on: ubuntu-latest + steps: + - uses: gorules/cli/actions/pull@cli-v0.2.1 + id: rules + with: + url: https://acme.gorules.io + token: ${{ secrets.GORULES_TOKEN }} + project: pricing + target: env:production + out: ./dist + + - run: aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursive + if: steps.rules.outputs.changed == 'true' +``` + +| Input | Required | Description | +| ------------- | -------- | -------------------------------------------------------------------------------- | +| `url` | yes | BRMS URL | +| `token` | yes | Access token; pass a secret | +| `project` | yes\* | Project key or id; optional when `payload` is set | +| `target` | | Target to resolve (default `main`) | +| `out` | | Output directory (default `.`) | +| `name` | | Output file or sub-directory name | +| `unpack` | | `true` to extract the archive | +| `delete` | | With `unpack`, mirror the target exactly (delete stale files) | +| `current` | | Release or commit id already held | +| `payload` | | BRMS event payload; auto-detected from `workflow_dispatch`, set only to override | +| `cli-version` | | Version of `@gorules/cli` to run | + +| Output | Description | +| -------------------------------- | --------------------------------------------------------------- | +| `changed` | `false` when `current` still matched, so nothing was downloaded | +| `release` / `version` / `commit` | What the target resolved to | +| `sha256` | Checksum of the downloaded artifact | +| `files` | JSON array of paths written | + +The token is passed to the CLI as an environment variable rather than an argument, and masked in the +log. `changed` exists so a scheduled workflow can skip the upload when production has not moved. + +## GitLab CI + +`templates/gitlab-ci-pull.yml` defines a hidden job you extend: + +```yaml +include: + - remote: 'https://raw.githubusercontent.com/gorules/cli/cli-v0.2.1/templates/gitlab-ci-pull.yml' + +pull:rules: + extends: .gorules-pull + variables: + GORULES_PROJECT: pricing + GORULES_TARGET: env:production + +publish:rules: + needs: ['pull:rules'] + rules: + - if: $RULES_CHANGED == "true" + script: + - aws s3 cp dist/ s3://my-bucket/rules/live/ --recursive +``` + +`GORULES_URL` and `GORULES_TOKEN` are CI/CD variables; mask and protect the token. GitLab puts them +in the environment automatically, so nothing else is needed to wire them up. Optional job variables: +`GORULES_OUT` (default `dist`), `GORULES_NAME`, `GORULES_CURRENT`, `GORULES_UNPACK` and +`GORULES_DELETE` (both `'false'` by default), and `GORULES_CLI_VERSION`. + +The job publishes `RULES_CHANGED`, `RULES_VERSION`, `RULES_RELEASE` and `RULES_SHA256` as a dotenv +report, so later jobs read them as ordinary variables. + +## Azure Pipelines + +`templates/azure-pipelines-pull.yml` is a job template you can reference directly: + +```yaml +resources: + repositories: + - repository: gorules + type: github + name: gorules/cli + ref: refs/tags/cli-v0.2.1 + endpoint: + +jobs: + - template: templates/azure-pipelines-pull.yml@gorules + parameters: + url: https://acme.gorules.io + project: pricing + target: env:production + azureSubscription: + storageAccount: acmerules + container: rules +``` + +`GORULES_TOKEN` must exist as a secret pipeline variable or in a linked variable group. Azure +DevOps does not map secret variables into the environment automatically, which the template handles +by declaring it explicitly under `env:`. + +The job sets `rulesChanged` and `rulesVersion` as pipeline variables for later stages to read. + +## Triggered by BRMS + +All three templates read `GRL_PAYLOAD` when it is present, which is what BRMS sends when a webhook +triggers the pipeline. The project and target then come from the event rather than from static +configuration, so one pipeline handles every project and environment: + +| System | How the payload arrives | +| --------------- | --------------------------------------- | +| GitHub Actions | `inputs.payload` on `workflow_dispatch` | +| GitLab CI | `GRL_PAYLOAD` pipeline variable | +| Azure Pipelines | `GRL_PAYLOAD` run variable | + +Without it, the configured `GORULES_PROJECT` and `GORULES_TARGET` are used, so the same file also +works for a manual or scheduled run. + ## MCP Bridge 2 diff --git a/actions/pull/action.yml b/actions/pull/action.yml new file mode 100644 index 0000000..72fe3bd --- /dev/null +++ b/actions/pull/action.yml @@ -0,0 +1,139 @@ +name: GoRules Pull +description: Download a rules artifact from GoRules BRMS so a pipeline can publish it to your own infrastructure +branding: + icon: download + color: blue + +inputs: + url: + description: BRMS URL, e.g. https://acme.gorules.io + required: true + token: + description: Access token. Pass a secret, never a literal + required: true + project: + description: Project key or id. Optional when payload is set + required: false + default: '' + target: + description: "'main', 'branch:', 'commit:', 'release:' or 'env:'" + required: false + default: main + out: + description: Output directory + required: false + default: . + name: + description: Output file name, or sub-directory name when unpack is true. Defaults to the project key with no extension + required: false + default: '' + unpack: + description: Extract the archive instead of writing it + required: false + default: 'false' + delete: + description: With unpack, delete files in the destination that are not in the artifact so it mirrors the target exactly + required: false + default: 'false' + current: + description: Release or commit id already held. When it still matches, nothing is downloaded and changed is false + required: false + default: '' + payload: + description: BRMS webhook payload. Auto-detected from the workflow_dispatch event; set explicitly only to override + required: false + default: '' + cli-version: + description: Version of @gorules/cli to run. Pin this in production + required: false + default: 0.2.1 # x-release-please-version + +outputs: + changed: + description: 'false when the target still matches the current input, true when an artifact was downloaded' + value: ${{ steps.pull.outputs.changed }} + release: + description: Release id, when the target resolved to a release + value: ${{ steps.pull.outputs.release }} + version: + description: Release version, when the target resolved to a release + value: ${{ steps.pull.outputs.version }} + commit: + description: Commit id, when the target resolved to a commit + value: ${{ steps.pull.outputs.commit }} + sha256: + description: Checksum of the downloaded artifact + value: ${{ steps.pull.outputs.sha256 }} + files: + description: JSON array of the paths written + value: ${{ steps.pull.outputs.files }} + +runs: + using: composite + steps: + - id: pull + shell: bash + env: + # Credentials travel as environment, never as arguments: anything on + # the command line is visible to other processes and lands in traces. + GORULES_URL: ${{ inputs.url }} + GORULES_TOKEN: ${{ inputs.token }} + GORULES_PROJECT: ${{ inputs.project }} + GORULES_TARGET: ${{ inputs.target }} + INPUT_OUT: ${{ inputs.out }} + INPUT_NAME: ${{ inputs.name }} + INPUT_UNPACK: ${{ inputs.unpack }} + INPUT_DELETE: ${{ inputs.delete }} + INPUT_CURRENT: ${{ inputs.current }} + INPUT_PAYLOAD: ${{ inputs.payload }} + CLI_VERSION: ${{ inputs['cli-version'] }} + run: | + set -euo pipefail + echo "::add-mask::$GORULES_TOKEN" + + # BRMS passes the event payload via workflow_dispatch; the project and + # target then come from the event rather than static configuration. + # The workflow only has to declare the `payload` input - the action + # reads it from the event itself, no pass-through needed. + if [ -z "$INPUT_PAYLOAD" ] && [ -f "${GITHUB_EVENT_PATH:-}" ]; then + INPUT_PAYLOAD=$(jq -r '.inputs.payload // empty' "$GITHUB_EVENT_PATH") + fi + if [ -n "$INPUT_PAYLOAD" ]; then + GORULES_PROJECT=$(jq -r '.project.key // .projectId // empty' <<<"$INPUT_PAYLOAD") + GORULES_TARGET=$(jq -r '.target // "main"' <<<"$INPUT_PAYLOAD") + export GORULES_PROJECT GORULES_TARGET + echo "Triggered by BRMS: $GORULES_PROJECT -> $GORULES_TARGET" + fi + + if [ -z "${GORULES_PROJECT:-}" ]; then + echo "Either the project input or a payload is required." >&2 + exit 2 + fi + + args=(pull --out "$INPUT_OUT" --json) + [ -n "$INPUT_NAME" ] && args+=(--name "$INPUT_NAME") + [ -n "$INPUT_CURRENT" ] && args+=(--current "$INPUT_CURRENT") + [ "$INPUT_UNPACK" = "true" ] && args+=(--unpack) + [ "$INPUT_DELETE" = "true" ] && args+=(--delete) + + result="$RUNNER_TEMP/gorules-pull.json" + + # Exit 3 means the target has not moved. That is a normal outcome for a + # scheduled job, so it becomes an output rather than a failed step. + set +e + npx --yes "@gorules/cli@${CLI_VERSION}" "${args[@]}" > "$result" + code=$? + set -e + + if [ "$code" -eq 3 ]; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "Target unchanged, nothing downloaded." + exit 0 + fi + [ "$code" -ne 0 ] && exit "$code" + + echo "changed=true" >> "$GITHUB_OUTPUT" + for key in release version commit sha256; do + echo "$key=$(jq -r --arg k "$key" '.[$k] // ""' "$result")" >> "$GITHUB_OUTPUT" + done + echo "files=$(jq -c '.files' "$result")" >> "$GITHUB_OUTPUT" diff --git a/package.json b/package.json index a596e96..8c47e24 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "files": [ "dist", "README.md", - "LICENSE" + "LICENSE", + "actions", + "templates" ], "main": "dist/index.js", "type": "module", diff --git a/release-please-config.json b/release-please-config.json index 882ac0c..2f44904 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -3,7 +3,8 @@ "packages": { ".": { "package-name": "@gorules/cli", - "release-type": "node" + "release-type": "node", + "extra-files": ["actions/pull/action.yml", "templates/gitlab-ci-pull.yml", "templates/azure-pipelines-pull.yml"] } } } diff --git a/src/api/client.ts b/src/api/client.ts new file mode 100644 index 0000000..8d93ec8 --- /dev/null +++ b/src/api/client.ts @@ -0,0 +1,158 @@ +export class CliError extends Error { + readonly exitCode: number; + + constructor(message: string, exitCode = 1) { + super(message); + this.name = 'CliError'; + this.exitCode = exitCode; + } +} + +export interface ApiOptions { + url: string; + token: string; +} + +export interface SyncDeploymentRequest { + project: string; + target?: string; + alias?: string; + current?: { commitId?: string | null; releaseId?: string | null }; +} + +export interface SyncArtifact { + url: string; + sha256?: string; + expiresAt?: string; +} + +export interface SyncDeploymentResult { + project: { id: string; key: string | null } | null; + target: string; + alias?: string; + action: 'no_change' | 'load' | 'no_release' | 'no_access' | 'error'; + commit?: { id: string; branchId: string | null; branchName: string | null }; + release?: { id: string; name?: string | null; version?: string | null; semanticVersion?: string | null }; + environment?: { id: string; key: string | null; name: string | null }; + artifact?: SyncArtifact; + code?: string; +} + +export interface SyncResponse { + nextPollAt: string | null; + deployments: SyncDeploymentResult[]; +} + +/** + * Trailing slashes and a trailing `/api` are both accepted so a copied browser + * URL and a documented API base behave the same. + */ +export const normalizeApiUrl = (url: string): string => { + const trimmed = url.trim().replace(/\/+$/, ''); + return trimmed.endsWith('/api') ? trimmed : `${trimmed}/api`; +}; + +export const resolveApiOptions = (args: { url?: string; token?: string }): ApiOptions => { + const url = args.url || process.env.GORULES_URL; + const token = args.token || process.env.GORULES_TOKEN; + + if (!url) { + throw new CliError('Missing server URL. Pass --url or set GORULES_URL.', 2); + } + if (!token) { + throw new CliError('Missing access token. Pass --token or set GORULES_TOKEN.', 2); + } + + return { url: normalizeApiUrl(url), token }; +}; + +/** Never interpolated into output: a token in a CI log is a leaked credential. */ +const authHeaders = (token: string): Record => ({ + Authorization: `Bearer ${token}`, +}); + +const describeHttpError = async (response: Response, context: string): Promise => { + const body = await response.text().catch(() => ''); + const detail = body.slice(0, 500); + + if (response.status === 401) { + return new CliError(`${context}: the access token was rejected (401). Check GORULES_TOKEN.`); + } + if (response.status === 403) { + return new CliError(`${context}: the access token is not permitted to do this (403). Check its project scope.`); + } + if (response.status === 404) { + return new CliError(`${context}: not found (404). Check the server URL and the project reference.`); + } + + return new CliError(`${context}: HTTP ${response.status}${detail ? ` ${detail}` : ''}`); +}; + +/** Retries transport failures and 5xx only; a 4xx is an answer, not a blip. */ +const RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]); +const MAX_ATTEMPTS = 3; + +const sleep = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)); + +const fetchWithRetry = async (url: string, init: RequestInit, context: string): Promise => { + let lastError: unknown; + + for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) { + try { + const response = await fetch(url, init); + if (!RETRYABLE_STATUS.has(response.status) || attempt === MAX_ATTEMPTS) { + return response; + } + } catch (error) { + lastError = error; + if (attempt === MAX_ATTEMPTS) { + break; + } + } + await sleep(2 ** (attempt - 1) * 500); + } + + throw new CliError(`${context}: ${lastError instanceof Error ? lastError.message : 'request failed'}`); +}; + +export const sync = async (options: ApiOptions, deployments: SyncDeploymentRequest[]): Promise => { + const response = await fetchWithRetry( + `${options.url}/rules-sync`, + { + method: 'POST', + headers: { ...authHeaders(options.token), 'Content-Type': 'application/json' }, + // No syncInterval: a one-shot sync answers with nextPollAt null + body: JSON.stringify({ deployments }), + }, + 'Failed to resolve the target', + ); + + if (!response.ok) { + throw await describeHttpError(response, 'Failed to resolve the target'); + } + + return (await response.json()) as SyncResponse; +}; + +/** + * The sync response returns either an absolute signed CDN URL, which must be + * fetched without the token, or a path relative to the API base, which must be + * fetched with it. Self-hosted installs without CDN configuration always take + * the second form. + */ +export const downloadArtifact = async (options: ApiOptions, artifact: SyncArtifact): Promise => { + const isRelative = artifact.url.startsWith('/'); + const url = isRelative ? `${options.url.replace(/\/api$/, '')}${artifact.url}` : artifact.url; + + const response = await fetchWithRetry( + url, + { headers: isRelative ? authHeaders(options.token) : {} }, + 'Failed to download the artifact', + ); + + if (!response.ok) { + throw await describeHttpError(response, 'Failed to download the artifact'); + } + + return Buffer.from(await response.arrayBuffer()); +}; diff --git a/src/api/extract.ts b/src/api/extract.ts new file mode 100644 index 0000000..127412e --- /dev/null +++ b/src/api/extract.ts @@ -0,0 +1,208 @@ +import { lstat, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from 'node:fs/promises'; +import { randomBytes } from 'node:crypto'; +import { dirname, join, resolve, sep } from 'node:path'; +import { CliError } from './client'; +import { readZip } from './zip'; + +/** Zip paths are untrusted input; never let one escape the output directory. */ +const safeJoin = (root: string, entryPath: string): string => { + const target = resolve(root, entryPath); + if (target !== root && !target.startsWith(root + sep)) { + throw new CliError(`Refusing to write outside the output directory: ${entryPath}`); + } + return target; +}; + +/** + * macOS and Windows filesystems are case-insensitive by default; comparing + * paths case-sensitively there would delete a file the extract just wrote + * under a different casing. + */ +const comparablePath = (path: string): string => + process.platform === 'darwin' || process.platform === 'win32' ? path.toLowerCase() : path; + +/** + * Symlinks are listed as files and never followed, so a link inside the + * output directory can never cause reads or deletions outside of it. + */ +const walkFiles = async (dir: string): Promise => { + const found: string[] = []; + for (const entry of await readdir(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + found.push(...(await walkFiles(path))); + } else { + found.push(path); + } + } + return found; +}; + +/** + * Delete mode removes files, so it refuses a directory it cannot prove was written by + * a previous pull: every artifact carries `.config/project.json`, so a + * non-empty directory without one belongs to something else. + */ +const listOwnedFiles = async (root: string): Promise => { + let entries: string[]; + try { + entries = await readdir(root); + } catch { + // Missing directory: nothing to delete + return []; + } + if (entries.length === 0) { + return []; + } + + const marker = join(root, '.config', 'project.json'); + const hasMarker = await stat(marker).then( + () => true, + () => false, + ); + if (!hasMarker) { + throw new CliError( + `--delete refuses to touch "${root}": it contains files but no .config/project.json from a previous pull. Empty the directory yourself or drop --delete.`, + ); + } + + return walkFiles(root); +}; + +/** Removes directories left empty by deletions; the root itself is kept. */ +const pruneEmptyDirs = async (dir: string, isRoot: boolean): Promise => { + let empty = true; + for (const entry of await readdir(dir, { withFileTypes: true })) { + if (entry.isDirectory()) { + const removed = await pruneEmptyDirs(join(dir, entry.name), false); + if (!removed) { + empty = false; + } + } else { + empty = false; + } + } + + if (empty && !isRoot) { + await rmdir(dir); + return true; + } + return false; +}; + +export interface ExtractResult { + /** Every artifact file now present on disk. */ + written: string[]; + /** The subset actually created or rewritten; byte-identical files are skipped. */ + updated: string[]; + deleted: string[]; +} + +/** + * Write-to-temp then rename, so a concurrent reader (the agent's filesystem + * provider, a running engine) sees either the old file or the new one, never a + * truncated write. Rename also replaces a symlink entry rather than writing + * through it. + */ +export const atomicWriteFile = async (file: string, content: Buffer): Promise => { + const tmp = join(dirname(file), `.${randomBytes(6).toString('hex')}.gorules-tmp`); + try { + await writeFile(tmp, content); + await rename(tmp, file); + } catch (error) { + await rm(tmp, { force: true }); + throw error; + } +}; + +/** + * Writes the archive 1:1 under `root`, preserving paths including `.config/`. + * `aws s3 sync` semantics: byte-identical files are left untouched (no mtime + * churn, no watcher wake-ups) and only changed content is written, atomically. + * + * Default mode leaves every file the archive does not carry alone. Delete mode + * (`s3 sync --delete`) makes the directory mirror the archive exactly: files + * not in the archive are deleted, but only after every write has succeeded, so + * a failure mid-extract leaves old and new side by side, never a hole. + */ +export const extractZipTo = async ( + buffer: Buffer, + root: string, + options: { delete?: boolean } = {}, +): Promise => { + // Fully parsed and decompressed before the first disk change: a corrupt + // archive fails here, not halfway through an extraction. + const entries = readZip(buffer); + + const existing = options.delete ? await listOwnedFiles(root) : []; + + const written: string[] = []; + const updated: string[] = []; + for (const entry of entries) { + const file = safeJoin(root, entry.path); + + const current = await lstat(file).catch(() => null); + if (current?.isDirectory()) { + if (!options.delete) { + throw new CliError(`Cannot write "${entry.path}": a directory is in the way. Remove it or use --delete.`); + } + await rm(file, { recursive: true, force: true }); + } else if (current?.isFile()) { + // Only a regular file is compared: a symlink's content lives elsewhere, + // so it must be replaced, not matched. + const onDisk = await readFile(file); + if (onDisk.equals(entry.content)) { + written.push(file); + continue; + } + } + + await mkdir(dirname(file), { recursive: true }); + await atomicWriteFile(file, entry.content); + written.push(file); + updated.push(file); + } + + const deleted: string[] = []; + if (options.delete) { + const keep = new Set(written.map(comparablePath)); + for (const file of existing) { + if (keep.has(comparablePath(file))) { + continue; + } + try { + await rm(file, { force: true }); + deleted.push(file); + } catch (error) { + // ENOTDIR: a directory on this path was replaced by a file during the + // write phase, so the snapshot entry is already gone. + if ((error as NodeJS.ErrnoException).code !== 'ENOTDIR') { + throw error; + } + } + } + await pruneEmptyDirs(root, true); + } + + return { written, updated, deleted }; +}; + +export interface ArtifactManifest { + project?: { key?: string | null; name?: string | null }; + release?: { version?: string | null } | null; + commit?: { id?: string | null } | null; +} + +/** The manifest the artifact carries at `.config/project.json`, when present. */ +export const readManifest = (buffer: Buffer): ArtifactManifest | null => { + const entry = readZip(buffer).find((item) => item.path === '.config/project.json'); + if (!entry) { + return null; + } + + try { + return JSON.parse(entry.content.toString('utf-8')) as ArtifactManifest; + } catch { + return null; + } +}; diff --git a/src/api/zip.ts b/src/api/zip.ts new file mode 100644 index 0000000..f56550a --- /dev/null +++ b/src/api/zip.ts @@ -0,0 +1,80 @@ +import { inflateRawSync } from 'node:zlib'; + +const EOCD_SIGNATURE = 0x06054b50; +const CENTRAL_SIGNATURE = 0x02014b50; +const LOCAL_SIGNATURE = 0x04034b50; +const EOCD_MIN_SIZE = 22; + +export interface ZipEntry { + path: string; + content: Buffer; +} + +/** + * Minimal zip reader over node's zlib. Artifacts are small, flat, deflate-only + * archives, so pulling in a zip dependency would be more surface than the + * format needs. Sizes always come from the central directory: streamed + * archives write zeroes in the local header and defer to a data descriptor. + */ +export const readZip = (buffer: Buffer): ZipEntry[] => { + const eocdOffset = findEocd(buffer); + if (eocdOffset === -1) { + throw new Error('Not a zip archive: end of central directory not found'); + } + + const entryCount = buffer.readUInt16LE(eocdOffset + 10); + let cursor = buffer.readUInt32LE(eocdOffset + 16); + + const entries: ZipEntry[] = []; + + for (let index = 0; index < entryCount; index += 1) { + if (buffer.readUInt32LE(cursor) !== CENTRAL_SIGNATURE) { + throw new Error('Corrupt zip archive: bad central directory entry'); + } + + const method = buffer.readUInt16LE(cursor + 10); + const compressedSize = buffer.readUInt32LE(cursor + 20); + const nameLength = buffer.readUInt16LE(cursor + 28); + const extraLength = buffer.readUInt16LE(cursor + 30); + const commentLength = buffer.readUInt16LE(cursor + 32); + const localOffset = buffer.readUInt32LE(cursor + 42); + const path = buffer.toString('utf-8', cursor + 46, cursor + 46 + nameLength); + + cursor += 46 + nameLength + extraLength + commentLength; + + // Directory entries carry no data + if (path.endsWith('/')) { + continue; + } + + if (buffer.readUInt32LE(localOffset) !== LOCAL_SIGNATURE) { + throw new Error(`Corrupt zip archive: bad local header for ${path}`); + } + + const localNameLength = buffer.readUInt16LE(localOffset + 26); + const localExtraLength = buffer.readUInt16LE(localOffset + 28); + const dataStart = localOffset + 30 + localNameLength + localExtraLength; + const data = buffer.subarray(dataStart, dataStart + compressedSize); + + if (method === 0) { + entries.push({ path, content: Buffer.from(data) }); + } else if (method === 8) { + entries.push({ path, content: inflateRawSync(data) }); + } else { + throw new Error(`Unsupported compression method ${method} for ${path}`); + } + } + + return entries; +}; + +/** The comment field is variable length, so the record is found by scanning back. */ +const findEocd = (buffer: Buffer): number => { + const start = Math.max(0, buffer.length - EOCD_MIN_SIZE - 0xffff); + for (let offset = buffer.length - EOCD_MIN_SIZE; offset >= start; offset -= 1) { + if (buffer.readUInt32LE(offset) === EOCD_SIGNATURE) { + return offset; + } + } + return -1; +}; diff --git a/src/commands/pull.ts b/src/commands/pull.ts new file mode 100644 index 0000000..2dee334 --- /dev/null +++ b/src/commands/pull.ts @@ -0,0 +1,186 @@ +import { defineCommand } from 'citty'; +import { createHash } from 'node:crypto'; +import { mkdir } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import pc from 'picocolors'; +import { CliError, downloadArtifact, resolveApiOptions, sync, type SyncDeploymentResult } from '../api/client'; +import { atomicWriteFile, extractZipTo } from '../api/extract'; + +/** + * Exit codes are part of the contract: pipelines branch on them. + * 0 downloaded 3 nothing to do 4 no release 1 error 2 usage + */ +const EXIT_NO_CHANGE = 3; +const EXIT_NO_RELEASE = 4; + +const describeFailure = (result: SyncDeploymentResult, project: string, target: string): CliError => { + switch (result.action) { + case 'no_access': + return new CliError( + `The access token cannot reach project "${project}". Check that the project exists and that the token's project scope includes it.`, + ); + case 'no_release': + return new CliError( + `Nothing is deployed to "${target}" in project "${project}". Deploy a release to it first.`, + EXIT_NO_RELEASE, + ); + case 'error': + return new CliError(`Could not resolve "${target}" in project "${project}": ${result.code ?? 'unknown error'}`); + default: + return new CliError(`Unexpected response for "${target}" in project "${project}": ${result.action}`); + } +}; + +export const pull = defineCommand({ + meta: { + name: 'pull', + description: 'Download the rules artifact for a project target', + }, + args: { + project: { + type: 'string', + description: 'Project key or id (env: GORULES_PROJECT)', + alias: 'p', + }, + target: { + type: 'string', + description: + "Target: 'main', 'branch:', 'commit:', 'release:' or 'env:' (env: GORULES_TARGET)", + alias: 't', + }, + out: { + type: 'string', + description: 'Output directory', + alias: 'o', + default: '.', + }, + unpack: { + type: 'boolean', + description: 'Extract the archive into a directory instead of writing the zip', + default: false, + }, + delete: { + type: 'boolean', + description: + 'With --unpack: delete files in the destination that are not in the artifact, so the directory mirrors the target exactly. Without it, files the artifact does not carry are preserved', + default: false, + }, + name: { + type: 'string', + description: + "Output file name, or sub-directory name with --unpack. Defaults to the project key with no extension, which is what the agent's object storage providers require. Pass '.' with --unpack to extract straight into --out", + }, + current: { + type: 'string', + description: 'Release or commit id already held; exits 3 when unchanged', + }, + url: { type: 'string', description: 'BRMS API URL (env: GORULES_URL)', alias: 'u' }, + token: { type: 'string', description: 'Access token (env: GORULES_TOKEN)' }, + json: { type: 'boolean', description: 'Print the result as JSON', default: false }, + }, + async run({ args }) { + const options = resolveApiOptions(args); + const project = args.project || process.env.GORULES_PROJECT; + const target = args.target || process.env.GORULES_TARGET || 'main'; + + if (!project) { + throw new CliError('Missing project. Pass --project or set GORULES_PROJECT.', 2); + } + if (args.delete && !args.unpack) { + throw new CliError('--delete only applies when extracting. Add --unpack.', 2); + } + + // A `current` id is echoed back to the server, which answers no_change + // rather than re-serving an artifact the caller already holds. + const current = args.current ? { commitId: args.current, releaseId: args.current } : undefined; + + const response = await sync(options, [{ project, target, ...(current && { current }) }]); + const result = response.deployments[0]; + + if (!result) { + throw new CliError('The server returned no result for this deployment.'); + } + + if (result.action === 'no_change') { + if (args.json) { + process.stdout.write(JSON.stringify({ action: 'no_change', project, target }) + '\n'); + } else { + process.stderr.write(pc.dim(`Already up to date (${target}).\n`)); + } + process.exitCode = EXIT_NO_CHANGE; + return; + } + + if (result.action !== 'load' || !result.artifact) { + throw describeFailure(result, project, target); + } + + const buffer = await downloadArtifact(options, result.artifact); + const digest = createHash('sha256').update(buffer).digest('hex'); + + // Verified only when the server supplied a digest: self-hosted installs + // without CDN configuration serve the artifact directly and send none. + if (result.artifact.sha256 && result.artifact.sha256.toLowerCase() !== digest) { + throw new CliError('Artifact checksum mismatch: the download does not match what the server published.'); + } + + // Default to the project key with no extension: the agent's object + // storage providers use the object name verbatim as the project key, so a + // `.zip` suffix would surface a project literally called "pricing.zip". + // The agent's local `zip` provider is the opposite and does strip it, so + // that destination wants an explicit `--name .zip`. + const projectKey = result.project?.key ?? result.project?.id ?? project; + const name = typeof args.name === 'string' && args.name.length > 0 ? args.name : projectKey; + const outDir = resolve(process.cwd(), args.out); + const written: string[] = []; + const updated: string[] = []; + const deleted: string[] = []; + + if (args.unpack) { + const extracted = await extractZipTo(buffer, resolve(outDir, name), { delete: args.delete }); + written.push(...extracted.written); + updated.push(...extracted.updated); + deleted.push(...extracted.deleted); + } else { + if (name === '.' || name.endsWith('/')) { + throw new CliError(`--name "${name}" is not a file name. Use --unpack to extract into a directory.`, 2); + } + const file = join(outDir, name); + await mkdir(dirname(file), { recursive: true }); + await atomicWriteFile(file, buffer); + written.push(file); + updated.push(file); + } + + const summary = { + action: 'load' as const, + project: result.project?.key ?? project, + target, + release: result.release?.id, + version: result.release?.semanticVersion ?? result.release?.version ?? undefined, + commit: result.commit?.id, + environment: result.environment?.key ?? undefined, + sha256: digest, + verified: Boolean(result.artifact.sha256), + files: written, + ...(args.unpack && { updated }), + ...(args.delete && { deleted }), + }; + + if (args.json) { + process.stdout.write(JSON.stringify(summary) + '\n'); + return; + } + + const label = summary.version ? `${summary.project}@${summary.version}` : `${summary.project} (${target})`; + const counts = [ + `${written.length} file(s)`, + ...(args.unpack ? [`${updated.length} updated`] : []), + ...(deleted.length > 0 ? [`${deleted.length} removed`] : []), + ].join(', '); + process.stderr.write(`${pc.green('Pulled')} ${pc.bold(label)} ${pc.dim(`-> ${counts}`)}\n`); + if (!summary.verified) { + process.stderr.write(pc.dim(' server sent no checksum; download integrity not verified\n')); + } + }, +}); diff --git a/src/main.ts b/src/main.ts index 891b615..80b4f9b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,16 +1,67 @@ #!/usr/bin/env node -import { defineCommand, runMain } from 'citty'; +import { defineCommand, runCommand, showUsage, type CommandDef } from 'citty'; import { mcp } from './commands/mcp'; +import { pull } from './commands/pull'; +import { CliError } from './api/client'; +import { version as VERSION } from '../package.json'; const main = defineCommand({ meta: { name: 'gorules', - version: '1.0.0', + version: VERSION, description: 'GoRules CLI', }, subCommands: { mcp, + pull, }, }); -void runMain(main); +/** Walks ` ` so `--help` lands on the command actually named. */ +const resolveCommand = (rawArgs: string[]): [CommandDef, CommandDef | undefined] => { + let command: CommandDef = main; + let parent: CommandDef | undefined; + + for (const arg of rawArgs) { + if (arg.startsWith('-')) { + break; + } + const subCommands = command.subCommands as Record | undefined; + const next = subCommands?.[arg]; + if (!next) { + break; + } + parent = command; + command = next; + } + + return [command, parent]; +}; + +const run = async (): Promise => { + const rawArgs = process.argv.slice(2); + + if (rawArgs.length === 0 || rawArgs.includes('--help') || rawArgs.includes('-h')) { + await showUsage(...resolveCommand(rawArgs)); + return; + } + + if (rawArgs.length === 1 && (rawArgs[0] === '--version' || rawArgs[0] === '-v')) { + process.stdout.write(`${VERSION}\n`); + return; + } + + await runCommand(main, { rawArgs }); +}; + +// Errors surface as one readable line plus a meaningful exit code, which is +// what a pipeline branches on; citty's own handler prints a stack and always +// exits 1. +void run().catch((error: unknown) => { + if (error instanceof CliError) { + process.stderr.write(`${error.message}\n`); + process.exit(error.exitCode); + } + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exit(1); +}); diff --git a/templates/azure-pipelines-pull.yml b/templates/azure-pipelines-pull.yml new file mode 100644 index 0000000..e889876 --- /dev/null +++ b/templates/azure-pipelines-pull.yml @@ -0,0 +1,138 @@ +# Azure Pipelines template: pull a rules artifact and publish it to Blob Storage. +# +# resources: +# repositories: +# - repository: gorules +# type: github +# name: gorules/cli +# ref: refs/tags/cli-v0.2.1 +# endpoint: +# +# jobs: +# - template: templates/azure-pipelines-pull.yml@gorules +# parameters: +# url: https://acme.gorules.io +# project: pricing +# target: env:production +# container: rules +# storageAccount: acmerules +# azureSubscription: +# +# GORULES_TOKEN must exist as a secret variable, either in the pipeline or in a +# linked variable group. +# +# For BRMS-triggered runs, the pipeline must accept the GRL_PAYLOAD variable at +# queue time: add a pipeline variable named GRL_PAYLOAD (any value) with "Let +# users override this value when running this pipeline" checked. Organizations +# with "Limit variables that can be set at queue time" enabled (the default on +# newer organizations) reject the queue request otherwise. + +parameters: + - name: url + type: string + - name: project + type: string + - name: target + type: string + default: main + - name: out + type: string + default: $(Build.ArtifactStagingDirectory)/rules + - name: name + type: string + default: '' + - name: unpack + type: boolean + default: false + # With unpack, deletes files in the destination that are not in the artifact + - name: delete + type: boolean + default: false + - name: cliVersion + type: string + default: 0.2.1 # x-release-please-version + - name: azureSubscription + type: string + default: '' + - name: storageAccount + type: string + default: '' + - name: container + type: string + default: '' + - name: prefix + type: string + default: rules/live + +jobs: + - job: gorules_pull + displayName: Pull rules from GoRules + pool: + vmImage: ubuntu-latest + steps: + # Microsoft-hosted images already ship Node; self-hosted agents may not. + - task: NodeTool@0 + displayName: Use Node 20 + inputs: + versionSpec: '20.x' + + - script: | + set -euo pipefail + + # BRMS passes GRL_PAYLOAD when it triggers the run, so the same + # template serves a manual run and a webhook-driven one. On a manual + # run the macro below does not resolve and Azure leaves the literal + # '$(GRL_PAYLOAD)' in place, so that exact string means "not set". + if [ -n "${GRL_PAYLOAD:-}" ] && [ "${GRL_PAYLOAD}" != '$(GRL_PAYLOAD)' ]; then + GORULES_PROJECT=$(node -e 'const p=JSON.parse(process.env.GRL_PAYLOAD);process.stdout.write(p.project?.key||p.projectId||"")') + GORULES_TARGET=$(node -e 'const p=JSON.parse(process.env.GRL_PAYLOAD);process.stdout.write(p.target||"main")') + export GORULES_PROJECT GORULES_TARGET + echo "Triggered by BRMS: $GORULES_PROJECT $GORULES_TARGET" + fi + + args=(pull --out "${{ parameters.out }}" --json) + if [ -n "${{ parameters.name }}" ]; then args+=(--name "${{ parameters.name }}"); fi + if [ "${{ lower(parameters.unpack) }}" = "true" ]; then args+=(--unpack); fi + if [ "${{ lower(parameters.delete) }}" = "true" ]; then args+=(--delete); fi + + # Exit 3 means the target has not moved: a normal outcome, not a failure + set +e + npx --yes "@gorules/cli@${{ parameters.cliVersion }}" "${args[@]}" > result.json + code=$? + set -e + + if [ "$code" -eq 3 ]; then + echo "##vso[task.setvariable variable=rulesChanged]false" + echo "Target unchanged, nothing downloaded." + exit 0 + fi + [ "$code" -ne 0 ] && exit "$code" + + echo "##vso[task.setvariable variable=rulesChanged]true" + echo "##vso[task.setvariable variable=rulesVersion]$(node -p "require('./result.json').version || ''")" + displayName: gorules pull + env: + GORULES_URL: ${{ parameters.url }} + GORULES_PROJECT: ${{ parameters.project }} + GORULES_TARGET: ${{ parameters.target }} + # Secret variables are NOT mapped into the environment automatically; + # without this line the token is simply absent. + GORULES_TOKEN: $(GORULES_TOKEN) + # Empty on a manual run; set by BRMS when it queues the pipeline + GRL_PAYLOAD: $(GRL_PAYLOAD) + + - task: AzureCLI@2 + displayName: Upload to Blob Storage + condition: and(succeeded(), eq(variables['rulesChanged'], 'true'), ne('${{ parameters.container }}', '')) + inputs: + azureSubscription: ${{ parameters.azureSubscription }} + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + set -euo pipefail + az storage blob upload-batch \ + --account-name "${{ parameters.storageAccount }}" \ + --destination "${{ parameters.container }}/${{ parameters.prefix }}" \ + --source "${{ parameters.out }}" \ + --auth-mode login \ + --overwrite diff --git a/templates/gitlab-ci-pull.yml b/templates/gitlab-ci-pull.yml new file mode 100644 index 0000000..68d22b5 --- /dev/null +++ b/templates/gitlab-ci-pull.yml @@ -0,0 +1,68 @@ +# GitLab CI template: pull a rules artifact and publish it to your own storage. +# +# include: +# - remote: 'https://raw.githubusercontent.com/gorules/cli/cli-v0.2.1/templates/gitlab-ci-pull.yml' +# +# pull:rules: +# extends: .gorules-pull +# variables: +# GORULES_PROJECT: pricing +# GORULES_TARGET: env:production +# +# GORULES_URL and GORULES_TOKEN come from CI/CD variables; mask and protect the +# token. GitLab puts CI/CD variables in the environment automatically, so the +# CLI picks them up with no further wiring. +# +# When BRMS triggers the pipeline it passes GRL_PAYLOAD, and the project and +# target are taken from that instead, so the same job serves both a manual run +# and a webhook-driven one. + +.gorules-pull: + image: node:20-alpine + variables: + GORULES_OUT: dist + GORULES_CLI_VERSION: '0.2.1' # x-release-please-version + GORULES_UNPACK: 'false' + # 'true' deletes files in the destination that are not in the artifact + GORULES_DELETE: 'false' + script: + - | + set -eu + + if [ -n "${GRL_PAYLOAD:-}" ]; then + GORULES_PROJECT=$(printf '%s' "$GRL_PAYLOAD" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const p=JSON.parse(s);process.stdout.write(p.project?.key||p.projectId||"")})') + GORULES_TARGET=$(printf '%s' "$GRL_PAYLOAD" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const p=JSON.parse(s);process.stdout.write(p.target||"main")})') + export GORULES_PROJECT GORULES_TARGET + echo "Triggered by BRMS: $GORULES_PROJECT $GORULES_TARGET" + fi + + set -- pull --out "$GORULES_OUT" --json + if [ -n "${GORULES_NAME:-}" ]; then set -- "$@" --name "$GORULES_NAME"; fi + if [ -n "${GORULES_CURRENT:-}" ]; then set -- "$@" --current "$GORULES_CURRENT"; fi + if [ "${GORULES_UNPACK}" = "true" ]; then set -- "$@" --unpack; fi + if [ "${GORULES_DELETE}" = "true" ]; then set -- "$@" --delete; fi + + # Exit 3 means the target has not moved: a normal outcome, not a failure + set +e + npx --yes "@gorules/cli@${GORULES_CLI_VERSION}" "$@" > result.json + code=$? + set -e + + if [ "$code" -eq 3 ]; then + echo "RULES_CHANGED=false" > gorules.env + echo "Target unchanged, nothing downloaded." + exit 0 + fi + if [ "$code" -ne 0 ]; then exit "$code"; fi + + { + echo "RULES_CHANGED=true" + node -e 'const r=require("./result.json");console.log("RULES_VERSION="+(r.version||""));console.log("RULES_RELEASE="+(r.release||""));console.log("RULES_SHA256="+(r.sha256||""))' + } > gorules.env + cat gorules.env + artifacts: + paths: + - $GORULES_OUT + # Downstream jobs read RULES_CHANGED / RULES_VERSION as ordinary variables + reports: + dotenv: gorules.env From e983ec81caacb01556cd9199187e5ae6b64e4228 Mon Sep 17 00:00:00 2001 From: Ivan Miletic Date: Sun, 16 Aug 2026 21:05:09 +0200 Subject: [PATCH 2/3] fix: vulnerabilities --- package.json | 24 +- pnpm-lock.yaml | 771 ++++++++++++++++++++++++++----------------------- 2 files changed, 423 insertions(+), 372 deletions(-) diff --git a/package.json b/package.json index 8c47e24..c3434a7 100644 --- a/package.json +++ b/package.json @@ -39,23 +39,23 @@ "gorules": "dist/main.js" }, "devDependencies": { - "@clack/prompts": "^1.0.1", + "@clack/prompts": "^1.7.0", "@eslint/js": "^10.0.1", - "@hono/node-server": "^1.19.9", - "@modelcontextprotocol/sdk": "^1.27.1", - "@types/node": "^25.3.2", + "@hono/node-server": "^1.19.17", + "@modelcontextprotocol/sdk": "^1.30.0", + "@types/node": "^25.9.5", "@types/ws": "^8.18.1", "boxen": "^8.0.1", - "citty": "^0.2.1", - "eslint": "^10.0.2", - "hono": "^4.12.3", - "nanoid": "^5.1.6", + "citty": "^0.2.2", + "eslint": "^10.8.1", + "hono": "^4.13.2", + "nanoid": "^5.1.16", "picocolors": "^1.1.1", - "prettier": "^3.8.1", + "prettier": "^3.9.6", "rolldown": "1.0.0-rc.6", "typescript": "^5.9.3", - "typescript-eslint": "^8.56.1", - "ws": "^8.19.0", - "zod": "^4.3.6" + "typescript-eslint": "^8.67.0", + "ws": "^8.21.3", + "zod": "^4.4.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13dfb0d..dac409e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,20 @@ importers: .: devDependencies: '@clack/prompts': - specifier: ^1.0.1 - version: 1.0.1 + specifier: ^1.7.0 + version: 1.7.0 '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.0.2) + version: 10.0.1(eslint@10.8.1) '@hono/node-server': - specifier: ^1.19.9 - version: 1.19.9(hono@4.12.3) + specifier: ^1.19.17 + version: 1.19.17(hono@4.13.2) '@modelcontextprotocol/sdk': - specifier: ^1.27.1 - version: 1.27.1(zod@4.3.6) + specifier: ^1.30.0 + version: 1.30.0(zod@4.4.3) '@types/node': - specifier: ^25.3.2 - version: 25.3.2 + specifier: ^25.9.5 + version: 25.9.5 '@types/ws': specifier: ^8.18.1 version: 8.18.1 @@ -30,46 +30,48 @@ importers: specifier: ^8.0.1 version: 8.0.1 citty: - specifier: ^0.2.1 - version: 0.2.1 + specifier: ^0.2.2 + version: 0.2.2 eslint: - specifier: ^10.0.2 - version: 10.0.2 + specifier: ^10.8.1 + version: 10.8.1 hono: - specifier: ^4.12.3 - version: 4.12.3 + specifier: ^4.13.2 + version: 4.13.2 nanoid: - specifier: ^5.1.6 - version: 5.1.6 + specifier: ^5.1.16 + version: 5.1.16 picocolors: specifier: ^1.1.1 version: 1.1.1 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.9.6 + version: 3.9.6 rolldown: specifier: 1.0.0-rc.6 - version: 1.0.0-rc.6 + version: 1.0.0-rc.6(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1) typescript: specifier: ^5.9.3 version: 5.9.3 typescript-eslint: - specifier: ^8.56.1 - version: 8.56.1(eslint@10.0.2)(typescript@5.9.3) + specifier: ^8.67.0 + version: 8.67.0(eslint@10.8.1)(typescript@5.9.3) ws: - specifier: ^8.19.0 - version: 8.19.0 + specifier: ^8.21.3 + version: 8.21.3 zod: - specifier: ^4.3.6 - version: 4.3.6 + specifier: ^4.4.3 + version: 4.4.3 packages: - '@clack/core@1.0.1': - resolution: {integrity: sha512-WKeyK3NOBwDOzagPR5H08rFk9D/WuN705yEbuZvKqlkmoLM2woKtXb10OO2k1NoSU4SFG947i2/SCYh+2u5e4g==} + '@clack/core@1.4.3': + resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} + engines: {node: '>= 20.12.0'} - '@clack/prompts@1.0.1': - resolution: {integrity: sha512-/42G73JkuYdyWZ6m8d/CJtBrGl1Hegyc7Fy78m5Ob+jF85TOUmLR5XLce/U3LxYAw0kJ8CT5aI99RIvPHcGp/Q==} + '@clack/prompts@1.7.0': + resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} + engines: {node: '>= 20.12.0'} '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -80,8 +82,8 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -90,16 +92,16 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.23.2': - resolution: {integrity: sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.2': - resolution: {integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==} + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@1.1.0': - resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/js@10.0.1': @@ -111,26 +113,30 @@ packages: eslint: optional: true - '@eslint/object-schema@3.0.2': - resolution: {integrity: sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.6.0': - resolution: {integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==} + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@hono/node-server@1.19.9': - resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + '@hono/node-server@1.19.17': + resolution: {integrity: sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -141,8 +147,8 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@modelcontextprotocol/sdk@1.27.1': - resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -151,8 +157,12 @@ packages: '@cfworker/json-schema': optional: true - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 '@oxc-project/types@0.115.0': resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==} @@ -237,81 +247,81 @@ packages: '@rolldown/pluginutils@1.0.0-rc.6': resolution: {integrity: sha512-Y0+JT8Mi1mmW08K6HieG315XNRu4L0rkfCpA364HtytjgiqYnMYRdFPcxRl+BQQqNXzecL2S9nii+RUpO93XIA==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@25.3.2': - resolution: {integrity: sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==} + '@types/node@25.9.5': + resolution: {integrity: sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==} '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.56.1': - resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + '@typescript-eslint/eslint-plugin@8.67.0': + resolution: {integrity: sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.56.1 + '@typescript-eslint/parser': ^8.67.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.56.1': - resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + '@typescript-eslint/parser@8.67.0': + resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.56.1': - resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + '@typescript-eslint/project-service@8.67.0': + resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.56.1': - resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + '@typescript-eslint/scope-manager@8.67.0': + resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.56.1': - resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + '@typescript-eslint/tsconfig-utils@8.67.0': + resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.56.1': - resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + '@typescript-eslint/type-utils@8.67.0': + resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.56.1': - resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + '@typescript-eslint/types@8.67.0': + resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.56.1': - resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + '@typescript-eslint/typescript-estree@8.67.0': + resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.56.1': - resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + '@typescript-eslint/utils@8.67.0': + resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.56.1': - resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + '@typescript-eslint/visitor-keys@8.67.0': + resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} accepts@2.0.0: @@ -323,8 +333,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} engines: {node: '>=0.4.0'} hasBin: true @@ -336,11 +346,11 @@ packages: ajv: optional: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -349,8 +359,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} engines: {node: '>=12'} ansi-styles@6.2.3: @@ -361,17 +371,17 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} boxen@8.0.1: resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} engines: {node: '>=18'} - brace-expansion@5.0.3: - resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} - engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} @@ -393,21 +403,25 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - citty@0.2.1: - resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} + engines: {node: '>=18'} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -465,8 +479,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} escape-html@1.0.3: @@ -476,8 +490,8 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-scope@9.1.1: - resolution: {integrity: sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: @@ -488,8 +502,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.0.2: - resolution: {integrity: sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==} + eslint@10.8.1: + resolution: {integrity: sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -498,8 +512,8 @@ packages: jiti: optional: true - espree@11.1.1: - resolution: {integrity: sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} esquery@1.7.0: @@ -522,16 +536,16 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} engines: {node: '>=18.0.0'} eventsource@3.0.7: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} - express-rate-limit@8.2.1: - resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} + express-rate-limit@8.6.2: + resolution: {integrity: sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -549,8 +563,17 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -577,8 +600,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} @@ -591,8 +614,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - get-east-asian-width@1.5.0: - resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -615,28 +638,28 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} - hono@4.12.3: - resolution: {integrity: sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==} + hono@4.13.2: + resolution: {integrity: sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA==} engines: {node: '>=16.9.0'} http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} engines: {node: '>= 4'} imurmurhash@0.1.4: @@ -646,8 +669,8 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -672,8 +695,8 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + jose@6.2.9: + resolution: {integrity: sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==} json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -705,8 +728,8 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} engines: {node: '>= 0.8'} merge-descriptors@2.0.0: @@ -721,15 +744,15 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@5.1.6: - resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + nanoid@5.1.16: + resolution: {integrity: sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==} engines: {node: ^18 || >=20} hasBin: true @@ -779,14 +802,14 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} pkce-challenge@5.0.1: @@ -797,8 +820,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} engines: {node: '>=14'} hasBin: true @@ -810,12 +833,12 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} engines: {node: '>=0.6'} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} engines: {node: '>= 0.6'} raw-body@3.0.2: @@ -838,8 +861,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true @@ -862,8 +885,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: @@ -874,8 +897,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} sisteransi@1.0.5: @@ -901,16 +924,16 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -926,24 +949,24 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} - typescript-eslint@8.56.1: - resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} + typescript-eslint@8.67.0: + resolution: {integrity: sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} @@ -976,8 +999,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -992,25 +1015,26 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod-to-json-schema@3.25.1: - resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: - zod: ^3.25 || ^4 + zod: ^3.25.28 || ^4 - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} snapshots: - '@clack/core@1.0.1': + '@clack/core@1.4.3': dependencies: - picocolors: 1.1.1 + fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 - '@clack/prompts@1.0.1': + '@clack/prompts@1.7.0': dependencies: - '@clack/core': 1.0.1 - picocolors: 1.1.1 + '@clack/core': 1.4.3 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 '@emnapi/core@1.8.1': @@ -1029,82 +1053,87 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.2)': + '@eslint-community/eslint-utils@4.10.1(eslint@10.8.1)': dependencies: - eslint: 10.0.2 + eslint: 10.8.1 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.2': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 3.0.2 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.6 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.2': + '@eslint/config-helpers@0.7.0': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.2.1 - '@eslint/core@1.1.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.0.2)': + '@eslint/js@10.0.1(eslint@10.8.1)': optionalDependencies: - eslint: 10.0.2 + eslint: 10.8.1 - '@eslint/object-schema@3.0.2': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.6.0': + '@eslint/plugin-kit@0.7.2': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.2.1 levn: 0.4.1 - '@hono/node-server@1.19.9(hono@4.12.3)': + '@hono/node-server@1.19.17(hono@4.13.2)': dependencies: - hono: 4.12.3 + hono: 4.13.2 - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} - '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': + '@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)': dependencies: - '@hono/node-server': 1.19.9(hono@4.12.3) - ajv: 8.18.0 - ajv-formats: 3.0.1(ajv@8.18.0) + '@hono/node-server': 1.19.17(hono@4.13.2) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 - eventsource-parser: 3.0.6 + eventsource-parser: 3.1.1 express: 5.2.1 - express-rate-limit: 8.2.1(express@5.2.1) - hono: 4.12.3 - jose: 6.1.3 + express-rate-limit: 8.6.2(express@5.2.1) + hono: 4.13.2 + jose: 6.2.9 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 - zod: 4.3.6 - zod-to-json-schema: 3.25.1(zod@4.3.6) + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) transitivePeerDependencies: - supports-color - '@napi-rs/wasm-runtime@1.1.1': + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)': dependencies: '@emnapi/core': 1.8.1 '@emnapi/runtime': 1.8.1 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.3 optional: true '@oxc-project/types@0.115.0': {} @@ -1139,9 +1168,12 @@ snapshots: '@rolldown/binding-openharmony-arm64@1.0.0-rc.6': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.6': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.6(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' optional: true '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.6': @@ -1152,114 +1184,114 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.6': {} - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 optional: true '@types/esrecurse@4.3.1': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} - '@types/node@25.3.2': + '@types/node@25.9.5': dependencies: - undici-types: 7.18.2 + undici-types: 7.24.6 '@types/ws@8.18.1': dependencies: - '@types/node': 25.3.2 + '@types/node': 25.9.5 - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2)(typescript@5.9.3))(eslint@10.0.2)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1)(typescript@5.9.3))(eslint@10.8.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@10.0.2)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@10.0.2)(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 - eslint: 10.0.2 - ignore: 7.0.5 + '@typescript-eslint/parser': 8.67.0(eslint@10.8.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/type-utils': 8.67.0(eslint@10.8.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.67.0 + eslint: 10.8.1 + ignore: 7.0.6 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@10.0.2)(typescript@5.9.3)': + '@typescript-eslint/parser@8.67.0(eslint@10.8.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.67.0 debug: 4.4.3 - eslint: 10.0.2 + eslint: 10.8.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.67.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@5.9.3) + '@typescript-eslint/types': 8.67.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.56.1': + '@typescript-eslint/scope-manager@8.67.0': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 - '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.67.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.56.1(eslint@10.0.2)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.67.0(eslint@10.8.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2)(typescript@5.9.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.1)(typescript@5.9.3) debug: 4.4.3 - eslint: 10.0.2 - ts-api-utils: 2.4.0(typescript@5.9.3) + eslint: 10.8.1 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.67.0': {} - '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.67.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/project-service': 8.67.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@5.9.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 debug: 4.4.3 - minimatch: 10.2.4 - semver: 7.7.3 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@10.0.2)(typescript@5.9.3)': + '@typescript-eslint/utils@8.67.0(eslint@10.8.1)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - eslint: 10.0.2 + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + eslint: 10.8.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.56.1': + '@typescript-eslint/visitor-keys@8.67.0': dependencies: - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/types': 8.67.0 eslint-visitor-keys: 5.0.1 accepts@2.0.0: @@ -1267,27 +1299,27 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.16.0): + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: - acorn: 8.16.0 + acorn: 8.18.0 - acorn@8.16.0: {} + acorn@8.18.0: {} - ajv-formats@3.0.1(ajv@8.18.0): + ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: - ajv: 8.18.0 + ajv: 8.20.0 - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.18.0: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -1297,23 +1329,23 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.2.2: {} + ansi-regex@6.3.0: {} ansi-styles@6.2.3: {} balanced-match@4.0.4: {} - body-parser@2.2.2: + body-parser@2.3.0: dependencies: bytes: 3.1.2 - content-type: 1.0.5 + content-type: 2.1.0 debug: 4.4.3 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.15.3 raw-body: 3.0.2 - type-is: 2.0.1 + type-is: 2.1.0 transitivePeerDependencies: - supports-color @@ -1328,7 +1360,7 @@ snapshots: widest-line: 5.0.0 wrap-ansi: 9.0.2 - brace-expansion@5.0.3: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -1348,14 +1380,16 @@ snapshots: chalk@5.6.2: {} - citty@0.2.1: {} + citty@0.2.2: {} cli-boxes@3.0.0: {} - content-disposition@1.0.1: {} + content-disposition@1.1.0: {} content-type@1.0.5: {} + content-type@2.1.0: {} + cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -1397,7 +1431,7 @@ snapshots: es-errors@1.3.0: {} - es-object-atoms@1.1.1: + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -1405,10 +1439,10 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-scope@9.1.1: + eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -1416,25 +1450,25 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.0.2: + eslint@10.8.1: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.2 - '@eslint/config-helpers': 0.5.2 - '@eslint/core': 1.1.0 - '@eslint/plugin-kit': 0.6.0 - '@humanfs/node': 0.16.7 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 + '@types/estree': 1.0.9 + ajv: 6.15.0 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 9.1.1 + eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 - espree: 11.1.1 + espree: 11.2.0 esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -1445,16 +1479,16 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 + minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 transitivePeerDependencies: - supports-color - espree@11.1.1: + espree@11.2.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 5.0.1 esquery@1.7.0: @@ -1471,22 +1505,25 @@ snapshots: etag@1.8.1: {} - eventsource-parser@3.0.6: {} + eventsource-parser@3.1.1: {} eventsource@3.0.7: dependencies: - eventsource-parser: 3.0.6 + eventsource-parser: 3.1.1 - express-rate-limit@8.2.1(express@5.2.1): + express-rate-limit@8.6.2(express@5.2.1): dependencies: + debug: 4.4.3 express: 5.2.1 - ip-address: 10.0.1 + ip-address: 10.5.0 + transitivePeerDependencies: + - supports-color express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.0.1 + body-parser: 2.3.0 + content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 @@ -1504,13 +1541,13 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.15.0 - range-parser: 1.2.1 + qs: 6.15.3 + range-parser: 1.3.0 router: 2.2.0 send: 1.2.1 serve-static: 2.2.1 statuses: 2.0.2 - type-is: 2.0.1 + type-is: 2.1.0 vary: 1.1.2 transitivePeerDependencies: - supports-color @@ -1521,11 +1558,21 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-uri@3.1.5: {} + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: @@ -1549,10 +1596,10 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.4 keyv: 4.5.4 - flatted@3.3.3: {} + flatted@3.4.4: {} forwarded@0.2.0: {} @@ -1560,25 +1607,25 @@ snapshots: function-bind@1.1.2: {} - get-east-asian-width@1.5.0: {} + get-east-asian-width@1.6.0: {} get-intrinsic@1.3.0: 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 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.4 math-intrinsics: 1.1.0 get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 glob-parent@6.0.2: dependencies: @@ -1588,11 +1635,11 @@ snapshots: has-symbols@1.1.0: {} - hasown@2.0.2: + hasown@2.0.4: dependencies: function-bind: 1.1.2 - hono@4.12.3: {} + hono@4.13.2: {} http-errors@2.0.1: dependencies: @@ -1602,19 +1649,19 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.6: {} imurmurhash@0.1.4: {} inherits@2.0.4: {} - ip-address@10.0.1: {} + ip-address@10.5.0: {} ipaddr.js@1.9.1: {} @@ -1630,7 +1677,7 @@ snapshots: isexe@2.0.0: {} - jose@6.1.3: {} + jose@6.2.9: {} json-buffer@3.0.1: {} @@ -1657,7 +1704,7 @@ snapshots: math-intrinsics@1.1.0: {} - media-typer@1.1.0: {} + media-typer@1.1.1: {} merge-descriptors@2.0.0: {} @@ -1667,13 +1714,13 @@ snapshots: dependencies: mime-db: 1.54.0 - minimatch@10.2.4: + minimatch@10.2.6: dependencies: - brace-expansion: 5.0.3 + brace-expansion: 5.0.9 ms@2.1.3: {} - nanoid@5.1.6: {} + nanoid@5.1.16: {} natural-compare@1.4.0: {} @@ -1714,17 +1761,17 @@ snapshots: path-key@3.1.1: {} - path-to-regexp@8.3.0: {} + path-to-regexp@8.4.2: {} picocolors@1.1.1: {} - picomatch@4.0.3: {} + picomatch@4.0.5: {} pkce-challenge@5.0.1: {} prelude-ls@1.2.1: {} - prettier@3.8.1: {} + prettier@3.9.6: {} proxy-addr@2.0.7: dependencies: @@ -1733,22 +1780,23 @@ snapshots: punycode@2.3.1: {} - qs@6.15.0: + qs@6.15.3: dependencies: - side-channel: 1.1.0 + es-define-property: 1.0.1 + side-channel: 1.1.1 - range-parser@1.2.1: {} + range-parser@1.3.0: {} raw-body@3.0.2: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 unpipe: 1.0.0 require-from-string@2.0.2: {} - rolldown@1.0.0-rc.6: + rolldown@1.0.0-rc.6(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1): dependencies: '@oxc-project/types': 0.115.0 '@rolldown/pluginutils': 1.0.0-rc.6 @@ -1763,9 +1811,12 @@ snapshots: '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.6 '@rolldown/binding-linux-x64-musl': 1.0.0-rc.6 '@rolldown/binding-openharmony-arm64': 1.0.0-rc.6 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.6 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.6(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1) '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.6 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.6 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' router@2.2.0: dependencies: @@ -1773,13 +1824,13 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.2 transitivePeerDependencies: - supports-color safer-buffer@2.1.2: {} - semver@7.7.3: {} + semver@7.8.5: {} send@1.2.1: dependencies: @@ -1792,7 +1843,7 @@ snapshots: mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 - range-parser: 1.2.1 + range-parser: 1.3.0 statuses: 2.0.2 transitivePeerDependencies: - supports-color @@ -1814,7 +1865,7 @@ snapshots: shebang-regex@3.0.0: {} - side-channel-list@1.0.0: + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -1834,11 +1885,11 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 - side-channel-list: 1.0.0 + side-channel-list: 1.0.1 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -1855,7 +1906,7 @@ snapshots: string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 strip-ansi@6.0.1: @@ -1864,16 +1915,16 @@ snapshots: strip-ansi@7.2.0: dependencies: - ansi-regex: 6.2.2 + ansi-regex: 6.3.0 - tinyglobby@0.2.15: + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 toidentifier@1.0.1: {} - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -1886,26 +1937,26 @@ snapshots: type-fest@4.41.0: {} - type-is@2.0.1: + type-is@2.1.0: dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 + content-type: 2.1.0 + media-typer: 1.1.1 mime-types: 3.0.2 - typescript-eslint@8.56.1(eslint@10.0.2)(typescript@5.9.3): + typescript-eslint@8.67.0(eslint@10.8.1)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2)(typescript@5.9.3))(eslint@10.0.2)(typescript@5.9.3) - '@typescript-eslint/parser': 8.56.1(eslint@10.0.2)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2)(typescript@5.9.3) - eslint: 10.0.2 + '@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1)(typescript@5.9.3))(eslint@10.8.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.67.0(eslint@10.8.1)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.1)(typescript@5.9.3) + eslint: 10.8.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.9.3: {} - undici-types@7.18.2: {} + undici-types@7.24.6: {} unpipe@1.0.0: {} @@ -1933,12 +1984,12 @@ snapshots: wrappy@1.0.2: {} - ws@8.19.0: {} + ws@8.21.3: {} yocto-queue@0.1.0: {} - zod-to-json-schema@3.25.1(zod@4.3.6): + zod-to-json-schema@3.25.2(zod@4.4.3): dependencies: - zod: 4.3.6 + zod: 4.4.3 - zod@4.3.6: {} + zod@4.4.3: {} From fc3a3ee4ee8afded8116fe2828ab92ba991210ce Mon Sep 17 00:00:00 2001 From: Ivan Miletic Date: Sun, 16 Aug 2026 21:09:27 +0200 Subject: [PATCH 3/3] fix: cleanup --- README.md | 6 +++--- actions/pull/action.yml | 2 +- templates/azure-pipelines-pull.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3bdff29..6afaf1b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ building block for shipping rules from BRMS into your own infrastructure: a CI j artifact and uploads it wherever your runtime reads it from. ```bash -export GORULES_URL=https://acme.gorules.io +export GORULES_URL=https://acme.us1.gorules.io export GORULES_TOKEN=... # project access token, read scope is enough gorules pull --project pricing --target env:production --out ./dist @@ -149,7 +149,7 @@ jobs: - uses: gorules/cli/actions/pull@cli-v0.2.1 id: rules with: - url: https://acme.gorules.io + url: https://acme.us1.gorules.io token: ${{ secrets.GORULES_TOKEN }} project: pricing target: env:production @@ -229,7 +229,7 @@ resources: jobs: - template: templates/azure-pipelines-pull.yml@gorules parameters: - url: https://acme.gorules.io + url: https://acme.us1.gorules.io project: pricing target: env:production azureSubscription: diff --git a/actions/pull/action.yml b/actions/pull/action.yml index 72fe3bd..4c22aa4 100644 --- a/actions/pull/action.yml +++ b/actions/pull/action.yml @@ -6,7 +6,7 @@ branding: inputs: url: - description: BRMS URL, e.g. https://acme.gorules.io + description: BRMS URL, e.g. https://acme.us1.gorules.io required: true token: description: Access token. Pass a secret, never a literal diff --git a/templates/azure-pipelines-pull.yml b/templates/azure-pipelines-pull.yml index e889876..f56d33b 100644 --- a/templates/azure-pipelines-pull.yml +++ b/templates/azure-pipelines-pull.yml @@ -11,7 +11,7 @@ # jobs: # - template: templates/azure-pipelines-pull.yml@gorules # parameters: -# url: https://acme.gorules.io +# url: https://acme.us1.gorules.io # project: pricing # target: env:production # container: rules