From 18c3e36dc9a5c9611659c0ec0634c6a4f0d20b5c Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 17 Jun 2026 06:02:36 +0000 Subject: [PATCH] feat(api): configure helmet and strict cors Adds `@fastify/helmet` to enforce essential security headers and configures `@fastify/cors` securely by reading `VSPEC_ALLOWED_ORIGINS` to prevent overly permissive access. --- .jules/sentinel.md | 4 ++ apps/api/package.json | 2 + apps/api/src/http/server.ts | 12 +++++ apps/api/src/http/signup-types.ts | 1 + apps/api/src/index.ts | 6 +++ ...ify-returns-opaque-output-with-no-pass-.md | 6 +-- ...w-human-format-omits-the-extensions-sec.md | 4 +- ...ify-produces-opaque-output-with-no-pass.md | 6 +-- ...ate-title-validator-title-not-verb-phra.md | 2 +- ...ify-produces-no-usable-output-so-the-ag.md | 1 - ...ify-returns-opaque-output-with-no-pass-.md | 4 +- ...s-unlinked-steps-demands-implements-ref.md | 2 +- ...se-verify-produces-no-meaningful-output.md | 2 +- ...phrase-validator-false-positives-on-leg.md | 6 +-- ...-show-name-leaks-raw-apierror-api-reque.md | 2 +- ...d-does-not-surface-the-new-scenario-id-.md | 6 +-- ...self-conflicts-on-local-markdown-the-ag.md | 6 +-- ...se-verify-with-no-key-leaks-raw-apierro.md | 2 +- ...rrors-emit-a-misleading-default-vspec-l.md | 4 +- pnpm-lock.yaml | 46 +++++++++++++++++++ 20 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..e9bbe93b --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-05-24 - [Overly Permissive CORS Default] +**Vulnerability:** Fastify API lacked any CORS configuration or security headers, meaning if deployed, it might have been open or prone to basic attacks without Helmet protection. +**Learning:** Default fastify instances do not ship with basic security protections like CORS origin validation or essential HTTP headers. +**Prevention:** Always enforce strict `allowedOrigins` via environment variables (like `VSPEC_ALLOWED_ORIGINS`) and include `@fastify/helmet` as a foundational security measure for any exposed API. diff --git a/apps/api/package.json b/apps/api/package.json index f30d34c2..150f1154 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -9,6 +9,8 @@ "typecheck": "cd ../.. && tsc -p tsconfig.json --noEmit" }, "dependencies": { + "@fastify/cors": "~8.5.0", + "@fastify/helmet": "~11.1.1", "@vooster/contracts": "workspace:*" } } diff --git a/apps/api/src/http/server.ts b/apps/api/src/http/server.ts index c04e47f9..925442c0 100644 --- a/apps/api/src/http/server.ts +++ b/apps/api/src/http/server.ts @@ -1,4 +1,6 @@ import Fastify, { type FastifyInstance } from "fastify"; +import fastifyCors from "@fastify/cors"; +import fastifyHelmet from "@fastify/helmet"; import { healthResponseSchema } from "@vooster/contracts"; import { createMemoryApiKeyStore } from "../infrastructure/memory-api-key-store.js"; import { createMemoryActorStore } from "../infrastructure/memory-actor-store.js"; @@ -88,6 +90,16 @@ export async function createServer(options: ServerOptions): Promise = {}) { const authStub = env.VSPEC_AUTH_STUB === "1"; const forceMemoryStore = env.VSPEC_FORCE_MEMORY_STORE === "1"; const port = portFrom(env.PORT); + const allowedOrigins = + env.VSPEC_ALLOWED_ORIGINS !== undefined + ? env.VSPEC_ALLOWED_ORIGINS.split(",") + : undefined; + const app = await (runtime.createServer ?? createServer)({ + allowedOrigins, authStub, githubOAuth: githubOAuthFromEnv(authStub, env), signupStore: diff --git a/goals/43-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md b/goals/43-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md index 8063a9e6..72ae8aed 100644 --- a/goals/43-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md +++ b/goals/43-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md @@ -53,8 +53,8 @@ got connected. - `json` -- the structured `VerifyResult` with a top-level `status`. - `agent` -- the agent envelope whose `data.status` and `data.drift` an agent can branch on. - The exit code follows the verdict exactly as `vspec verify` already does - (`0` pass, `7` unlinked steps, `1` otherwise). + The exit code follows the verdict exactly as `vspec verify` already does + (`0` pass, `7` unlinked steps, `1` otherwise). 3. No duplicated verdict logic: there is exactly **one** `runVerify` definition under `apps/cli/src`, and **every** `apps/cli/src` file that references it (other than the file that defines it) imports the shared producer rather than @@ -76,7 +76,7 @@ The set of accepted formats is the whitelist in `verifyFormat` (`apps/cli/src/commands/verify.ts`): `human`, `json`, `agent`. The set of `apps/cli/src` files that reference the verdict producer is enumerated from source with `grep -rln 'runVerify' apps/cli/src`; exactly one of them may -*define* `runVerify`, and the gate loops over the rest to confirm each imports +_define_ `runVerify`, and the gate loops over the rest to confirm each imports the shared definition rather than re-declaring it. ## Verification diff --git a/goals/44-dogfood-usecase-show-human-format-omits-the-extensions-sec.md b/goals/44-dogfood-usecase-show-human-format-omits-the-extensions-sec.md index b4ccfc87..0a3e4026 100644 --- a/goals/44-dogfood-usecase-show-human-format-omits-the-extensions-sec.md +++ b/goals/44-dogfood-usecase-show-human-format-omits-the-extensions-sec.md @@ -59,8 +59,8 @@ So the human view silently diverges from the agent / json / markdown views. - its **extension point** (e.g. `2a`), - its **condition** (e.g. `Title is empty`), and - its **outcome** when present (one of `FAILURE` / `PARTIAL` / `SUCCESS`). - Recovery **steps** continue to render, exactly as before, when present. No - extension is silently dropped. + Recovery **steps** continue to render, exactly as before, when present. No + extension is silently dropped. 3. Format parity holds: for **every** output format `usecase show` accepts (`human`, `json`, `agent`), the extension data is present in the rendered output. `json` and `agent` already serialize the raw scenarios; `human` now diff --git a/goals/48-dogfood-usecase-verify-produces-opaque-output-with-no-pass.md b/goals/48-dogfood-usecase-verify-produces-opaque-output-with-no-pass.md index 15f9c7a1..e145fc36 100644 --- a/goals/48-dogfood-usecase-verify-produces-opaque-output-with-no-pass.md +++ b/goals/48-dogfood-usecase-verify-produces-opaque-output-with-no-pass.md @@ -47,8 +47,8 @@ no pass/fail summary, no findings. The agent could not rely on `verify` and fell back to reading `usecase show` ("The spec reads correctly") to validate correctness by eye, making the verify step dead weight before push. -Goal 43 closed the *routing* half of this symptom (verify no longer dead-ends on -a banner). DF-001 is the *substance* half: even when verify runs, it only checks +Goal 43 closed the _routing_ half of this symptom (verify no longer dead-ends on +a banner). DF-001 is the _substance_ half: even when verify runs, it only checks link drift, so a structurally broken spec (missing actor, empty scenario, dangling extension point, missing Cockburn field) still verifies clean. This goal makes verify actually inspect the spec and emit a per-check verdict an agent @@ -96,7 +96,7 @@ stays single-source, and `usecase.ts` still routes the `verify` action into it). The set of `apps/cli/src` files that reference the spec-check producer is enumerated from source with `grep -rln 'runSpecChecks' apps/cli/src`; exactly one -of them may *define* `runSpecChecks` (enumerated with +of them may _define_ `runSpecChecks` (enumerated with `grep -rln 'function runSpecChecks' apps/cli/src`), and the gate loops over the rest to confirm each imports the shared definition rather than re-declaring it. diff --git a/goals/52-dogfood-usecase-create-title-validator-title-not-verb-phra.md b/goals/52-dogfood-usecase-create-title-validator-title-not-verb-phra.md index 89b0079a..0033628d 100644 --- a/goals/52-dogfood-usecase-create-title-validator-title-not-verb-phra.md +++ b/goals/52-dogfood-usecase-create-title-validator-title-not-verb-phra.md @@ -18,7 +18,7 @@ Two things must become true: 1. The guide must stop shipping self-contradicting create examples: every `vspec usecase create` example command the guide emits must carry a title the validator accepts, and none of those create examples may pass `--force`. A - self-teaching example must demonstrate a title that *works*, not one that has + self-teaching example must demonstrate a title that _works_, not one that has to be forced. 2. When `usecase create` genuinely rejects a title, the `TITLE_NOT_VERB_PHRASE` response must teach the fix end to end: it must surface at least one concrete diff --git a/goals/54-dogfood-usecase-verify-produces-no-usable-output-so-the-ag.md b/goals/54-dogfood-usecase-verify-produces-no-usable-output-so-the-ag.md index d0c3e5ff..e54143ad 100644 --- a/goals/54-dogfood-usecase-verify-produces-no-usable-output-so-the-ag.md +++ b/goals/54-dogfood-usecase-verify-produces-no-usable-output-so-the-ag.md @@ -70,4 +70,3 @@ do next (`docs/06-api-contract.md`). `unlinked_steps`, `failing_tests`) beyond folding structural gaps into the shared `status` / `exit_code` rollup. - No prior goal gate may be weakened to pass this goal. - diff --git a/goals/55-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md b/goals/55-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md index 0c03901d..82d0f358 100644 --- a/goals/55-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md +++ b/goals/55-dogfood-usecase-verify-returns-opaque-output-with-no-pass-.md @@ -10,7 +10,7 @@ When an agent runs `vspec usecase verify ` (or the equivalent `vspec verify clean, the command must tell the agent what to do about it -- not just that something failed. Goal 43 already made `verify` route into `runVerify` and emit a stable `status` in every format; that closed the "opaque banner" symptom for the -*pass* case. But the finding behind this goal is the *fail* case: when verify +_pass_ case. But the finding behind this goal is the _fail_ case: when verify reports drift the agent still has to reverse-engineer the remedy by hand. A verification command whose failure output cannot be acted on programmatically forced the dogfood agent to abandon `verify` and validate by eye. @@ -93,7 +93,7 @@ stays single-source, and `usecase.ts` still routes the `verify` action into it). The set of `apps/cli/src` files that reference the remediation producer is enumerated from source with `grep -rln 'suggestVerifyActions' apps/cli/src`; -exactly one of them may *define* `suggestVerifyActions` (enumerated with +exactly one of them may _define_ `suggestVerifyActions` (enumerated with `grep -rln 'function suggestVerifyActions' apps/cli/src`), and the gate loops over the rest to confirm each imports the shared definition rather than re-declaring it. diff --git a/goals/65-dogfood-verify-flags-unlinked-steps-demands-implements-ref.md b/goals/65-dogfood-verify-flags-unlinked-steps-demands-implements-ref.md index 91a37813..7685f68d 100644 --- a/goals/65-dogfood-verify-flags-unlinked-steps-demands-implements-ref.md +++ b/goals/65-dogfood-verify-flags-unlinked-steps-demands-implements-ref.md @@ -25,7 +25,7 @@ and the use cases are still at `DRAFT`. ## Source finding A task asked the agent to act on what `verify` reported. For POCKET-001..005, -`verify` flagged *every* step as `unlinked` and suggested adding `implements` +`verify` flagged _every_ step as `unlinked` and suggested adding `implements` refs — while `verify` itself reported `Tests not run`, the repo contained no implementation code, and all five use cases were still at `DRAFT`. Meanwhile every real spec gate was green (`actors_registered`, `scenario_completeness`, diff --git a/goals/67-dogfood-vspec-usecase-verify-produces-no-meaningful-output.md b/goals/67-dogfood-vspec-usecase-verify-produces-no-meaningful-output.md index 316f1f0d..92907ffd 100644 --- a/goals/67-dogfood-vspec-usecase-verify-produces-no-meaningful-output.md +++ b/goals/67-dogfood-vspec-usecase-verify-produces-no-meaningful-output.md @@ -41,7 +41,7 @@ This resolves purpose remains unclear"). The agent could not determine what verify checks or whether its spec passed. -Goals 43/54/55 made the *verdict* rich and actionable but operated on +Goals 43/54/55 made the _verdict_ rich and actionable but operated on `runUsecase`/`runVerify` internals; they were verified through direct calls and a frozen route snapshot, neither of which enumerates the `runUsecase` action set against the live route table. So the missing `usecase verify` route slipped diff --git a/goals/70-dogfood-title-verb-phrase-validator-false-positives-on-leg.md b/goals/70-dogfood-title-verb-phrase-validator-false-positives-on-leg.md index 1d0fbac3..d01bc2b8 100644 --- a/goals/70-dogfood-title-verb-phrase-validator-false-positives-on-leg.md +++ b/goals/70-dogfood-title-verb-phrase-validator-false-positives-on-leg.md @@ -15,7 +15,7 @@ A closed whitelist of English verbs is a correctness liability: it silently degrades valid specs, it is impossible to keep complete, and it cuts against the language-aware / Korean-first design principle. The dogfood agent could not recover from the rejection on its own — the message ("Use case title should be a -verb phrase") never named *which* word it disliked, so the agent built the wrong +verb phrase") never named _which_ word it disliked, so the agent built the wrong mental model ("the validator only accepts a leading subject like `User`") and fell back to `--force`. @@ -25,7 +25,7 @@ Two things must become true: the fix is a more permissive heuristic or a meaningfully broadened verb set, the dogfood-discovered title and a representative spread of common finite verbs the old closed set omitted must all be accepted. -2. When a title *is* genuinely rejected, the `TITLE_NOT_VERB_PHRASE` response +2. When a title _is_ genuinely rejected, the `TITLE_NOT_VERB_PHRASE` response must name the offending word so an agent can reason about the fix rather than guess. `--force` stays a real escape hatch; it must not be the only way past a legitimate verb phrase. @@ -53,7 +53,7 @@ and 52 — it does not weaken either prior gate. `titleLooksLikeVerbPhrase`.** The corpus is a source-of-truth fixture, `apps/api/tests/fixtures/legitimate-verb-phrase-titles.txt` (one title per line; `#` comment and blank lines ignored). This is a universal claim: the - gate enumerates every non-comment line from that file and loops the *real* + gate enumerates every non-comment line from that file and loops the _real_ validator over each one — no single-case cheat. The corpus must encode the dogfood regression anchor (`Partner accepts a shared-budget invitation`) and a representative spread of common finite verbs the prior closed set omitted, so diff --git a/goals/71-dogfood-vspec-actor-show-name-leaks-raw-apierror-api-reque.md b/goals/71-dogfood-vspec-actor-show-name-leaks-raw-apierror-api-reque.md index ba540e4d..3ab7747b 100644 --- a/goals/71-dogfood-vspec-actor-show-name-leaks-raw-apierror-api-reque.md +++ b/goals/71-dogfood-vspec-actor-show-name-leaks-raw-apierror-api-reque.md @@ -71,7 +71,7 @@ gate. It extends the same envelope discipline to the `actor` read/by-id commands cannot resolve the supplied actor, the emitted envelope names the lookup key the agent passed and its `suggested_next_actions` points at `vspec actor list` (so the agent can retry with the listed id). Behaviour — in both `--format - agent` and the default human output — is locked by unit tests in +agent` and the default human output — is locked by unit tests in `apps/cli/tests/unit/actor-command.test.ts`. 3. **The actor read/write happy paths stay green.** `actor list`/`show`/`edit`/ `archive` success output is unchanged, and the success cases still emit no diff --git a/goals/72-dogfood-scenario-add-does-not-surface-the-new-scenario-id-.md b/goals/72-dogfood-scenario-add-does-not-surface-the-new-scenario-id-.md index 8da2925e..c1d4f29e 100644 --- a/goals/72-dogfood-scenario-add-does-not-surface-the-new-scenario-id-.md +++ b/goals/72-dogfood-scenario-add-does-not-surface-the-new-scenario-id-.md @@ -14,9 +14,9 @@ guide's examples used the literal placeholder ``. The dogfood agent could not template the command, so it fell back to grepping `vspec usecase show TODO-001 --format=agent | python3 … data['scenarios'][].id` — running `vspec usecase show` six times to dig the id back out of JSON. Its own -narration: *"Step adds need a scenario id, not the use-case key. … neither +narration: _"Step adds need a scenario id, not the use-case key. … neither usecase create nor scenario add's tail output surfaced that id clearly. … echoing -the new scenario id prominently on scenario add would close that gap."* +the new scenario id prominently on scenario add would close that gap."_ The root cause is the API success path. `sendCreateScenarioResult`'s `CREATED` branch in `apps/api/src/http/scenario-results.ts` sends `scenario`/`revision`/ @@ -67,7 +67,7 @@ lists in `scenario-results.ts`). It extends that discipline to the scenario 1. **Every scenario type the contracts enum declares yields a real-id step-add next action on create.** The source of truth is `scenarioTypeSchema = - z.enum([...])` in `packages/contracts/src/scenario.ts`. This is a universal +z.enum([...])` in `packages/contracts/src/scenario.ts`. This is a universal claim: the gate enumerates every enum member from that line and, for each, drives the **real** `sendCreateScenarioResult` (from `apps/api/src/http/scenario-results.ts`) over a `CREATED` result whose diff --git a/goals/73-dogfood-first-push-self-conflicts-on-local-markdown-the-ag.md b/goals/73-dogfood-first-push-self-conflicts-on-local-markdown-the-ag.md index 6ece8545..4a6d0eae 100644 --- a/goals/73-dogfood-first-push-self-conflicts-on-local-markdown-the-ag.md +++ b/goals/73-dogfood-first-push-self-conflicts-on-local-markdown-the-ag.md @@ -8,13 +8,13 @@ The dogfood agent authored `POCKET-001` **entirely through CLI write commands** (`vspec usecase create`, `vspec scenario add`, `vspec step add` — narration commands 10, 12, 14-20). It made **zero** direct edits to any synced spec file -(the digest's *"Direct edits to synced spec state"* section is empty). Yet +(the digest's _"Direct edits to synced spec state"_ section is empty). Yet command 24, the very first `vspec push`, reported a **conflict** on the local markdown file: -> *"Push reports a conflict on the local markdown file ... The server already +> _"Push reports a conflict on the local markdown file ... The server already > holds my latest revision (`113902c9`); the local markdown cache is stale. Let -> me pull to reconcile."* +> me pull to reconcile."_ The agent then had to run command 29 `vspec pull --format=agent` followed by command 30 `vspec push` just to reconcile a file it had never hand-edited. A diff --git a/goals/74-dogfood-vspec-usecase-verify-with-no-key-leaks-raw-apierro.md b/goals/74-dogfood-vspec-usecase-verify-with-no-key-leaks-raw-apierro.md index 5446efc7..831ea231 100644 --- a/goals/74-dogfood-vspec-usecase-verify-with-no-key-leaks-raw-apierro.md +++ b/goals/74-dogfood-vspec-usecase-verify-with-no-key-leaks-raw-apierro.md @@ -17,7 +17,7 @@ teaching: 1. **No key supplied.** `runVerify` in `apps/cli/src/commands/verify.ts` resolves its argument through `verifyFlagsFrom` → `requiredArgument(usecaseId, - "usecase-id")`, which throws a bare `Error("Missing usecase-id.")`. That error +"usecase-id")`, which throws a bare `Error("Missing usecase-id.")`. That error has no stable `code` and no `suggested_next_actions`, and it propagates to oclif's top-level handler, which stringifies it to stderr. (Depending on how the empty argument is threaded, the request can also reach the API and come diff --git a/goals/75-dogfood-not-found-errors-emit-a-misleading-default-vspec-l.md b/goals/75-dogfood-not-found-errors-emit-a-misleading-default-vspec-l.md index 21c767ad..7468ca59 100644 --- a/goals/75-dogfood-not-found-errors-emit-a-misleading-default-vspec-l.md +++ b/goals/75-dogfood-not-found-errors-emit-a-misleading-default-vspec-l.md @@ -32,7 +32,7 @@ The fix has two halves: 2. **Give entity NOT_FOUND responses a recovery that teaches the real fix.** An entity-lookup 404 should point the agent at re-reading the use case to get the current ids -- `{ command: "vspec usecase show ", reason: "Re-read the - use case to get the current scenario/step ids." }` -- instead of a signup +use case to get the current scenario/step ids." }` -- instead of a signup command. The exact wording is the implementer's call, but the recovery must name `vspec usecase show` (the command that surfaces current ids) and must not mention `vspec login` / "Restart signup". @@ -70,7 +70,7 @@ removes a wrong default and gives entity NOT_FOUND responses a self-teaching one 2. **The shared `problem()` helper no longer ships a signup-flavored default.** This is the negative universal invariant: because the corpus loop can only exercise the senders it lists, a single grep over the helper guarantees no - *other* (present or future) `problem()` caller silently inherits the signup + _other_ (present or future) `problem()` caller silently inherits the signup recovery. The gate fails if the `problem()` default `suggestedNextActions` parameter still hardcodes `Restart signup`. 3. **Entity NOT_FOUND responses are self-teaching and the genuinely auth-related diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d2064ce..96f743d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,12 @@ importers: apps/api: dependencies: + '@fastify/cors': + specifier: ~8.5.0 + version: 8.5.0 + '@fastify/helmet': + specifier: ~11.1.1 + version: 11.1.1 '@vooster/contracts': specifier: workspace:* version: link:../../packages/contracts @@ -957,12 +963,18 @@ packages: '@fastify/ajv-compiler@3.6.0': resolution: {integrity: sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==} + '@fastify/cors@8.5.0': + resolution: {integrity: sha512-/oZ1QSb02XjP0IK1U0IXktEsw/dUBTxJOW7IpIeO8c/tNalw/KjoNSJv1Sf6eqoBPO+TDGkifq6ynFK3v68HFQ==} + '@fastify/error@3.4.1': resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} '@fastify/fast-json-stringify-compiler@4.3.0': resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + '@fastify/helmet@11.1.1': + resolution: {integrity: sha512-pjJxjk6SLEimITWadtYIXt6wBMfFC1I6OQyH/jYVCqSAn36sgAIFjeNiibHtifjCd+e25442pObis3Rjtame6A==} + '@fastify/merge-json-schemas@0.1.1': resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} @@ -3525,6 +3537,9 @@ packages: fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + fastify-plugin@4.5.1: + resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + fastify@4.29.1: resolution: {integrity: sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==} @@ -3740,6 +3755,10 @@ packages: headers-polyfill@5.0.1: resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} + helmet@7.2.0: + resolution: {integrity: sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==} + engines: {node: '>=16.0.0'} + hono@4.12.21: resolution: {integrity: sha512-uV63apnb0kyPtAUwoWgaGh9HyIFcv8lgmzPZSiTBQAFOFGIzka5EZ1dZocmGnn0XdX0+XTqJ6Tqv7selMuGLRQ==} engines: {node: '>=16.9.0'} @@ -4329,6 +4348,9 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + mnemonist@0.39.6: + resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -4462,6 +4484,9 @@ packages: resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} engines: {node: '>= 10'} + obliterator@2.0.5: + resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==} + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -5202,6 +5227,7 @@ packages: tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} + deprecated: unmaintained hasBin: true peerDependencies: typescript: ^5.0.0 @@ -6474,12 +6500,22 @@ snapshots: ajv-formats: 2.1.1(ajv@8.20.0) fast-uri: 2.4.0 + '@fastify/cors@8.5.0': + dependencies: + fastify-plugin: 4.5.1 + mnemonist: 0.39.6 + '@fastify/error@3.4.1': {} '@fastify/fast-json-stringify-compiler@4.3.0': dependencies: fast-json-stringify: 5.16.1 + '@fastify/helmet@11.1.1': + dependencies: + fastify-plugin: 4.5.1 + helmet: 7.2.0 + '@fastify/merge-json-schemas@0.1.1': dependencies: fast-deep-equal: 3.1.3 @@ -9171,6 +9207,8 @@ snapshots: dependencies: fast-string-width: 3.0.2 + fastify-plugin@4.5.1: {} + fastify@4.29.1: dependencies: '@fastify/ajv-compiler': 3.6.0 @@ -9463,6 +9501,8 @@ snapshots: '@types/set-cookie-parser': 2.4.10 set-cookie-parser: 3.1.0 + helmet@7.2.0: {} + hono@4.12.21: {} html-escaper@2.0.2: {} @@ -10120,6 +10160,10 @@ snapshots: minimist@1.2.8: {} + mnemonist@0.39.6: + dependencies: + obliterator: 2.0.5 + mrmime@2.0.1: {} ms@2.1.3: {} @@ -10242,6 +10286,8 @@ snapshots: object-treeify@1.1.33: {} + obliterator@2.0.5: {} + obug@2.1.1: {} ofetch@1.5.1: