6 次代码提交 6642db7375 ... b8ccdfbd00

作者 SHA1 备注 提交日期
  Tom McKenzie b8ccdfbd00 Use Decision Maker 2000 deployment identity 1 月之前
  Tom McKenzie f8715c9381 Document prototype hardening lessons 1 月之前
  Tom McKenzie 2a49747d80 Add browser security headers 1 月之前
  Tom McKenzie 0a56e255a7 Harden OTP runtime configuration 1 月之前
  Tom McKenzie 55a4a3c132 Enforce hand state invariants 1 月之前
  Tom McKenzie 3f49228ad8 Adopt safe lit-html rendering 1 月之前
共有 18 个文件被更改,包括 3078 次插入 和 3972 次删除
  1. 1 0
      .gitignore
  2. 21 9
      README.md
  3. 381 0
      client/app.js
  4. 36 0
      docs/blog/2026-09-19-hardening-the-lever.md
  5. 3 3
      docs/spec.md
  6. 0 3645
      package-lock.json
  7. 21 16
      package.json
  8. 2240 0
      pnpm-lock.yaml
  9. 5 0
      public/_headers
  10. 3 196
      public/index.html
  11. 29 21
      scripts/drive.sh
  12. 45 9
      src/auth/index.ts
  13. 56 0
      src/domain/hand-validation.ts
  14. 6 2
      src/env.d.ts
  15. 115 54
      src/hand.ts
  16. 66 13
      src/index.ts
  17. 44 0
      tests/hand-validation.test.ts
  18. 6 4
      wrangler.toml

+ 1 - 0
.gitignore

@@ -1,5 +1,6 @@
 # prod
 dist/
+public/app.js
 
 # dev
 .yarn/

+ 21 - 9
README.md

@@ -7,21 +7,33 @@ Hono + Better Auth (phone OTP + anonymous) + D1/Drizzle + one Durable Object per
 ## Dev loop
 
 ```bash
-npm install
+pnpm install
 cp .dev.vars.example .dev.vars        # then paste TYPESAFE_API_KEY + BETTER_AUTH_SECRET
-npm run db:migrate:dev                 # local D1 (miniflare)
-npm run dev                            # http://localhost:8787  — OTP codes print to this console
+pnpm db:migrate:dev                     # local D1 (miniflare)
+pnpm dev                                # http://localhost:8787  — OTP codes print to this console
 ```
 
 Open `/` on two phones on the same LAN (or `wrangler dev --ip 0.0.0.0`), "Jump in" with a name, create a hand, open `/h/<id>` on the other phone.
 
 ### Scripts
-- `npm run dev` — wrangler dev, local D1 + DO, hot reload
-- `npm run cf-typegen` — regenerate `worker-configuration.d.ts` after editing wrangler.toml
-- `npm run auth:update` then `npm run db:generate` — after changing Better Auth plugins
-- `npm run db:migrate:dev` / `:prod`
-- `npm run deploy` — `wrangler deploy` (first time: `wrangler d1 create pm2000-db`, paste id into wrangler.toml, `wrangler secret put TYPESAFE_API_KEY`, `wrangler secret put BETTER_AUTH_SECRET`)
-- Preview deploys: `npx wrangler versions upload` gives a preview URL without touching prod
+- `pnpm dev` — wrangler dev, local D1 + DO, hot reload
+- `pnpm cf-typegen` — regenerate `worker-configuration.d.ts` after editing wrangler.toml
+- `pnpm auth:update` then `pnpm db:generate` — after changing Better Auth plugins
+- `pnpm db:migrate:dev` / `pnpm db:migrate:prod`
+- `pnpm deploy` — `wrangler deploy` (first time: create D1, paste its id into `wrangler.toml`, and configure the production secrets listed below)
+- Preview deploys: `pnpm exec wrangler versions upload` gives a preview URL without touching prod
+
+Production uses Twilio because `wrangler.toml` sets `OTP_MODE=twilio`. Configure secrets without adding them to a file or Git:
+
+```bash
+pnpm exec wrangler secret put TYPESAFE_API_KEY
+pnpm exec wrangler secret put BETTER_AUTH_SECRET
+pnpm exec wrangler secret put TWILIO_ACCOUNT_SID
+pnpm exec wrangler secret put TWILIO_AUTH_TOKEN
+pnpm exec wrangler secret put TWILIO_FROM
+```
+
+`BETTER_AUTH_URL` is optional. Set it as a Wrangler variable or secret when production needs a fixed canonical origin; otherwise auth uses the origin of each incoming Cloudflare request. Local development explicitly uses `OTP_MODE=console` from `.dev.vars`.
 
 ### Where things are
 - `src/hand.ts` — the Hand DO: state, WebSocket fan-out, chips/veto/lock, debounced Jev odds, the lever (seeded sample), rounds

+ 381 - 0
client/app.js

@@ -0,0 +1,381 @@
+import { html, render as renderTemplate } from 'lit-html';
+
+const $ = (selector) => document.querySelector(selector);
+const app = $('#app');
+const reveal = $('#reveal');
+const revealBody = $('#reveal-body');
+const handId = location.pathname.startsWith('/h/') ? location.pathname.split('/')[2] : null;
+const MORE = 'more_options';
+
+let me = null;
+let state = null;
+let ws = null;
+let revealed = null;
+let reconnectTimer = null;
+let pingTimer = null;
+let revealTimers = [];
+
+async function api(path, body) {
+  const response = await fetch(path, {
+    method: body ? 'POST' : 'GET',
+    credentials: 'include',
+    headers: { 'Content-Type': 'application/json' },
+    body: body ? JSON.stringify(body) : undefined,
+  });
+  if (!response.ok) {
+    const text = await response.text();
+    let message = text;
+    try {
+      message = JSON.parse(text).error || text;
+    } catch {}
+    toast(message);
+    throw new Error(message);
+  }
+  return response.json();
+}
+
+function toast(message) {
+  const element = document.createElement('div');
+  element.textContent = message;
+  element.setAttribute('role', 'status');
+  element.style.cssText = 'position:fixed;top:12px;left:50%;transform:translateX(-50%);background:#111;color:#fff;padding:8px 14px;border-radius:99px;font-size:13px;z-index:20';
+  document.body.appendChild(element);
+  setTimeout(() => element.remove(), 1800);
+}
+
+async function session() {
+  const response = await fetch('/api/auth/get-session', { credentials: 'include' });
+  const text = await response.text();
+  if (!text) return null;
+  const result = JSON.parse(text);
+  return result?.user ? { id: result.user.id, name: result.user.name } : null;
+}
+
+function show() {
+  if (!me) return showJoin();
+  if (!handId) return showCreate();
+  if (!state) return renderTemplate(html`<p class="mute">Loading hand…</p>`, app);
+  showHand();
+}
+
+function showJoin() {
+  document.body.className = '';
+  renderTemplate(html`
+    <h1>Plan Maker 2000</h1>
+    <div class="card">
+      <p class="mute">Who are you at this table?</p>
+      <input id="name" aria-label="Your name" placeholder="Your name" autocomplete="name">
+      <button @click=${joinAnon}>Jump in</button>
+      <details>
+        <summary class="mute">Sign in with phone (OTP)</summary>
+        <input id="phone" aria-label="Phone number" placeholder="+61…" inputmode="tel" autocomplete="tel">
+        <button class="ghost" @click=${sendOtp}>Send code</button>
+        <input id="code" aria-label="Six-digit code" placeholder="6-digit code" inputmode="numeric" autocomplete="one-time-code" hidden>
+        <button class="ghost" id="verify" @click=${verifyOtp} hidden>Verify</button>
+      </details>
+    </div>
+  `, app);
+}
+
+async function joinAnon() {
+  const name = $('#name').value.trim() || 'anon';
+  const current = await session();
+  if (!current) {
+    await fetch('/api/auth/sign-in/anonymous', {
+      method: 'POST',
+      credentials: 'include',
+      headers: { 'Content-Type': 'application/json' },
+      body: '{}',
+    });
+  }
+  await api('/api/me/name', { name });
+  me = await session();
+  boot();
+}
+
+async function sendOtp() {
+  await api('/api/auth/phone-number/send-otp', { phoneNumber: $('#phone').value.trim() });
+  $('#code').hidden = false;
+  $('#verify').hidden = false;
+  toast('Code sent (check wrangler console in dev)');
+}
+
+async function verifyOtp() {
+  await api('/api/auth/phone-number/verify', {
+    phoneNumber: $('#phone').value.trim(),
+    code: $('#code').value.trim(),
+  });
+  const name = $('#name').value.trim() || 'anon';
+  await api('/api/me/name', { name });
+  me = await session();
+  boot();
+}
+
+function showCreate() {
+  document.body.className = '';
+  renderTemplate(html`
+    <h1>New hand</h1>
+    <div class="card">
+      <input id="q" aria-label="Question" placeholder="Question (e.g. Friday dinner)">
+      <input class="o" aria-label="Option 1" placeholder="Option 1">
+      <input class="o" aria-label="Option 2" placeholder="Option 2">
+      <input class="o" aria-label="Option 3" placeholder="Option 3 (optional)">
+      <input class="o" aria-label="Option 4" placeholder="Option 4 (optional)">
+      <input id="con" aria-label="Constraints" placeholder="Constraints, comma separated (optional)">
+      <button @click=${createHand}>Open the table</button>
+      <p class="mute">Screenshot intake comes later; type it for now.</p>
+    </div>
+  `, app);
+}
+
+async function createHand() {
+  const options = [...document.querySelectorAll('.o')].map((input) => input.value.trim()).filter(Boolean);
+  const constraints = $('#con').value.split(',').map((value) => value.trim()).filter(Boolean);
+  const hand = await api('/api/hands', { question: $('#q').value.trim(), options, constraints });
+  location.href = `/h/${hand.id}`;
+}
+
+function label(id) {
+  return state.round.options.find((option) => option.id === id)?.label || id;
+}
+
+function mine() {
+  return state.round.chips[me.id] || {};
+}
+
+function spent() {
+  return Object.values(mine()).reduce((sum, count) => sum + count, 0);
+}
+
+function totals() {
+  const result = {};
+  for (const chips of Object.values(state.round.chips)) {
+    for (const [option, count] of Object.entries(chips)) result[option] = (result[option] || 0) + count;
+  }
+  return result;
+}
+
+function chipList(count, other = false) {
+  return Array.from({ length: Math.max(0, count) }, () => html`<span class="chip ${other ? 'other' : ''}" aria-hidden="true"></span>`);
+}
+
+function optionView(option, live, odds, meIn, vetoLeft, chipTotals) {
+  const dead = !live.has(option.id);
+  const probability = odds?.probabilities[option.id] ?? null;
+  const myChips = mine()[option.id] || 0;
+  const otherChips = (chipTotals[option.id] || 0) - myChips;
+  const editable = state.status === 'open' && !dead && meIn && !meIn.locked;
+  const classes = `opt ${dead ? 'dead' : ''} ${option.id === MORE ? 'more' : ''}`;
+  const percentage = probability == null ? 0 : Math.round(probability * 100);
+
+  return html`
+    <div class=${classes}>
+      <div style="flex:1">
+        <div class="label">${option.label}</div>
+        <div class="chips" aria-label=${`${myChips} of your chips and ${Math.max(0, otherChips)} other chips`}>
+          ${chipList(myChips)}${chipList(otherChips, true)}
+        </div>
+      </div>
+      ${editable ? html`
+        <div class="stack">
+          <button aria-label=${`Remove a chip from ${option.label}`} @click=${() => place(option.id, -1)}>−</button>
+          <button aria-label=${`Add a chip to ${option.label}`} @click=${() => place(option.id, 1)}>+</button>
+        </div>
+      ` : null}
+      <div class="odds">${probability == null ? '—' : `${percentage}%`}</div>
+      ${editable && option.id !== MORE && vetoLeft > 0 ? html`
+        <button class="small ghost" style="color:#ff8fa3" @click=${() => veto(option.id)}>veto</button>
+      ` : null}
+      <div class="bar ${odds && odds.confidence < 0.5 ? 'wobble' : ''}" style=${`width:${percentage}%`}></div>
+    </div>
+  `;
+}
+
+function footerView(meIn, left) {
+  if (state.status === 'open') {
+    if (!meIn) return null;
+    const waitingFor = state.members.filter((member) => member.id !== me.id && !member.locked);
+    if (meIn.locked) {
+      const message = waitingFor.length
+        ? `Waiting for ${waitingFor.map((member) => member.name).join(', ')}…`
+        : 'The lever is turning…';
+      return html`<button class="ghost" disabled>${message}</button>`;
+    }
+    const label = waitingFor.length ? `Lock in (${left} left)` : 'LOCK & PULL THE LEVER';
+    return html`<button class=${waitingFor.length ? 'ghost' : 'lever'} @click=${() => act({ op: 'lock' })}>${label}</button>`;
+  }
+  if (state.status === 'posted') {
+    return html`<button class="ghost" @click=${() => act({ op: 'again' })}>Go again</button><button class="ghost" @click=${more}>More options</button><button @click=${() => act({ op: 'accept' })}>Accept</button>`;
+  }
+  if (state.status === 'accepted') return html`<button @click=${() => { location.href = '/'; }}>New hand</button>`;
+  return null;
+}
+
+function showHand() {
+  const round = state.round;
+  const odds = round.odds;
+  const live = new Set(state.live);
+  const spice = odds ? odds.spice : 0;
+  document.body.className = state.status === 'open' ? (spice >= 2 ? 'felt hot' : 'felt') : 'felt';
+  const meIn = state.members.find((member) => member.id === me.id);
+  const left = state.chipsPerMember - spent();
+  const vetoLeft = state.vetoesPerMember - (state.vetoesUsed[me.id] || 0);
+  const chipTotals = totals();
+  const jevLine = odds
+    ? `Jev · ${Math.round(odds.confidence * 100)}% sure · ${['mild', 'warm', 'hot', 'volcanic'][Math.round(odds.spice)]} · ${odds.contentious > 0.7 ? `contentious (${odds.about})` : 'calm'} · ${odds.format} · ${odds.ms}ms`
+    : 'Jev is waiting for chips';
+
+  renderTemplate(html`
+    <div class="mute">Round ${round.n} · ${state.status}</div>
+    <h1>${state.question}</h1>
+    <div class="members" aria-label="People at the table">
+      ${state.members.map((member) => html`<span class="member ${member.locked ? 'locked' : ''}">${member.name}${member.locked ? ' ✓' : ''}${odds && odds.sandbagging[member.id] > 0.6 ? ' 🫥' : ''}</span>`)}
+    </div>
+    ${!meIn ? html`<button @click=${() => act({ op: 'join' })}>Sit down as ${me.name}</button>` : null}
+    <div class="bank">${chipList(left)}<span class="mute" style="margin-left:8px">${left} chips · ${vetoLeft} vetoes</span></div>
+    ${round.options.map((option) => optionView(option, live, odds, meIn, vetoLeft, chipTotals))}
+    <div class="jev"><div class="face" aria-hidden="true"></div><div>${jevLine}</div></div>
+    ${round.pull && state.status !== 'open' ? html`
+      <div class="card">
+        <b>${label(round.pull.winner)}</b> — ${Math.round(round.pull.odds[round.pull.winner] * 100)}% at the pull<br>
+        <span class="mute">${round.pull.dealer}</span><br>
+        <button class="ghost small" @click=${() => playReveal(state.round.pull)}>replay</button>
+      </div>
+    ` : null}
+    ${state.rounds.length > 1 ? html`<div class="mute">Earlier: ${state.rounds.slice(0, -1).map((item) => item.pull ? label(item.pull.winner) : '?').join(' → ')}</div>` : null}
+    <div class="footer"><div class="inner">${footerView(meIn, left)}</div></div>
+  `, app);
+}
+
+async function act(body) {
+  await api(`/api/hands/${handId}/act`, body);
+}
+
+async function place(option, amount) {
+  await act({ op: 'place', option, n: amount });
+}
+
+async function veto(option) {
+  if (confirm(`Veto ${label(option)}? Everyone will see.`)) await act({ op: 'veto', option });
+}
+
+async function more() {
+  const labels = prompt('Options agent not wired yet — type new options, comma separated');
+  if (!labels) return;
+  await act({ op: 'more', labels: labels.split(',').map((value) => value.trim()).filter(Boolean) });
+}
+
+function clearRevealTimers() {
+  for (const timer of revealTimers) clearTimeout(timer);
+  revealTimers = [];
+}
+
+function afterRevealDelay(fn, delay) {
+  revealTimers.push(setTimeout(fn, delay));
+}
+
+function playReveal(pull) {
+  clearRevealTimers();
+  reveal.classList.add('on');
+  document.body.classList.add('crt');
+  const sequence = pull.order;
+  const winnerProbability = pull.odds[pull.winner];
+  let index = 0;
+
+  renderTemplate(html`<div class="mute">The lever has spoken</div><div class="reel-frame"><div class="reel" id="reel" aria-live="polite">…</div></div>`, revealBody);
+  const reel = $('#reel');
+  const step = () => {
+    if (index < sequence.length) {
+      reel.textContent = label(sequence[index]);
+      const runnerUp = sequence[index] === pull.runnerUp && index === sequence.length - 2;
+      const delay = index === sequence.length - 1 ? 0 : runnerUp ? 900 : Math.max(120, 420 - index * 60);
+      if (runnerUp) reel.classList.add('shake');
+      index += 1;
+      afterRevealDelay(step, delay);
+      return;
+    }
+
+    renderTemplate(html`
+      ${winnerProbability < 0.3 ? html`<div class="upset">UPSET</div>` : null}
+      <div class="mute">${state.question}</div>
+      <div class="winner">${label(pull.winner)}</div>
+      <div class="mute">${Math.round(winnerProbability * 100)}% at the pull</div>
+      <div class="dealer">${pull.dealer}</div>
+      <div class="odds-list">${Object.entries(pull.odds).sort((a, b) => b[1] - a[1]).map(([key, value]) => `${label(key)} ${Math.round(value * 100)}%`).join(' · ')}</div>
+      <button class="ghost" style="margin-top:20px;width:auto" @click=${closeReveal}>ok</button>
+    `, revealBody);
+    revealBody.querySelector('button')?.focus();
+    if (navigator.vibrate) navigator.vibrate([30, 40, 30, 40, 120]);
+  };
+  afterRevealDelay(step, 600);
+}
+
+function closeReveal() {
+  clearRevealTimers();
+  reveal.classList.remove('on');
+  document.body.classList.remove('crt');
+  show();
+}
+
+document.addEventListener('keydown', (event) => {
+  if (event.key === 'Escape' && reveal.classList.contains('on')) closeReveal();
+});
+
+function scheduleReconnect() {
+  clearTimeout(reconnectTimer);
+  reconnectTimer = setTimeout(connect, 1500);
+}
+
+function connect() {
+  clearTimeout(reconnectTimer);
+  if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) return;
+  clearInterval(pingTimer);
+
+  const proto = location.protocol === 'https:' ? 'wss' : 'ws';
+  const socket = new WebSocket(`${proto}://${location.host}/api/hands/${handId}/ws`);
+  ws = socket;
+  socket.onopen = () => {
+    pingTimer = setInterval(() => {
+      if (socket.readyState === WebSocket.OPEN) socket.send('ping');
+    }, 25000);
+  };
+  socket.onmessage = (event) => {
+    if (event.data === 'pong') return;
+    const message = JSON.parse(event.data);
+    if (message.type === 'state') {
+      const previousPull = state?.round?.pull?.at ?? null;
+      state = message.state;
+      const pull = state.round.pull;
+      if (pull && pull.at !== previousPull && pull.at !== revealed) {
+        revealed = pull.at;
+        playReveal(pull);
+        return;
+      }
+      show();
+    }
+    if (message.type === 'odds' && state) {
+      state.round.odds = message.odds;
+      show();
+    }
+    if (message.type === 'error') toast(message.error.slice(0, 120));
+  };
+  socket.onclose = () => {
+    if (ws !== socket) return;
+    ws = null;
+    clearInterval(pingTimer);
+    pingTimer = null;
+    scheduleReconnect();
+  };
+}
+
+async function boot() {
+  me = await session();
+  if (me && handId) {
+    state = await api(`/api/hands/${handId}`);
+    if (!state.members.find((member) => member.id === me.id)) await act({ op: 'join' });
+    connect();
+  }
+  show();
+}
+
+boot();

+ 36 - 0
docs/blog/2026-09-19-hardening-the-lever.md

@@ -0,0 +1,36 @@
+---
+date: 2026-09-19
+title: Hardening the lever without sanding off the fun
+---
+
+# Hardening the lever without sanding off the fun
+
+The first prototype proved the loop. The second pass proved that the loop must own its rules on the server, not only in the screen that happens to call it.
+
+## The browser is a view, not a referee
+
+The original client hid actions after lock, but the API still accepted them. It also trusted chip counts because the buttons only sent `1` and `-1`. Direct requests could veto after lock, store a string as a chip count, or pull a hand without joining it.
+
+The fix was small: normalize input at the Worker boundary, validate it again where the hand owns the state, and make every operation state its membership and phase rules. The UI can now stay playful without carrying the integrity of the game.
+
+## Safe templates did not require a framework rewrite
+
+Standalone lit-html kept the plain-JavaScript shape and the existing template-literal feel. Dynamic names, questions, options, and Jev values now enter the DOM as text bindings instead of parsed HTML. Event handlers are functions, lists are templates, and a state update patches the existing tree.
+
+This removed the stored-script path without introducing components, Shadow DOM, or a new application architecture.
+
+## One object still has asynchronous races
+
+A Durable Object is the right owner for a hand, but an external Jev request yields control. A newer chip move can finish its Jev call before an older one and then be overwritten by stale odds.
+
+Each odds request now carries the hand revision and request number that produced it. Only the latest matching result can land. Pulling also cancels the pending debounce, requests fresh odds once, and runs as a single flight.
+
+## Consensus is a different game mode
+
+The smoke run reproduced the important product bug: both players put every chip on Thai, Jev selected `one_tap`, and sampling still let a 17 percent option win.
+
+`one_tap` now confirms the highest-weight real option. Craps and reels still sample. The next live run returned Thai and the dealer line, “Unanimous. Boring. Go eat.” The guardrail preserved the joke instead of flattening it.
+
+## Keep the sharp edge visible
+
+The dependency audit is down from three high and four moderate findings to one moderate transitive finding in drizzle-kit's retired esbuild loader. The affected development server is not used by this app, and the current package has no patched upgrade path. It stays visible rather than forcing a breaking downgrade.

+ 3 - 3
docs/spec.md

@@ -387,11 +387,11 @@ Stack as built:
 
 Dev loop:
 
-1. `npm install && cp .dev.vars.example .dev.vars`, paste keys.
-2. `npm run db:migrate:dev && npm run dev` — local D1 + DO in miniflare, hot reload, OTP codes in the console.
+1. `pnpm install && cp .dev.vars.example .dev.vars`, paste keys.
+2. `pnpm db:migrate:dev && pnpm dev` — local D1 + DO in miniflare, hot reload, OTP codes in the console.
 3. Two phones on the LAN: `wrangler dev --ip 0.0.0.0`, open `/`, jump in, create a hand, share `/h/<id>`.
 4. Tune the pick instruction in `wrangler.toml` `[vars].PICK_INSTRUCTIONS`; it hot-reloads.
-5. Preview deploys: `npx wrangler versions upload` gives a URL without touching prod. First real deploy: `wrangler d1 create pm2000-db`, paste the id, `wrangler secret put TYPESAFE_API_KEY`, `wrangler secret put BETTER_AUTH_SECRET`, `npm run deploy`.
+5. Preview deploys: `pnpm exec wrangler versions upload` gives a URL without touching prod. First real deploy: `pnpm exec wrangler d1 create decision-maker-2000-db`, paste the ID, configure the secrets in `README.md`, then run `pnpm deploy`.
 
 Still to support the dev loop:
 

+ 0 - 3645
package-lock.json

@@ -1,3645 +0,0 @@
-{
-  "name": "pm2000",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "pm2000",
-      "dependencies": {
-        "@better-auth/drizzle-adapter": "1.7.3",
-        "@cloudflare/workers-types": "^5.20260830.1",
-        "better-auth": "1.7.3",
-        "better-auth-cloudflare": "latest",
-        "drizzle-orm": "^0.45.0",
-        "hono": "4.13.5"
-      },
-      "devDependencies": {
-        "@types/node": "^22.15.30",
-        "drizzle-kit": "^0.31.4",
-        "typescript": "^5.8.3",
-        "wrangler": "4.127.1"
-      }
-    },
-    "node_modules/@better-auth/core": {
-      "version": "1.7.5",
-      "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.7.5.tgz",
-      "integrity": "sha512-kVlSu4H8OKQfjg4b/Zj5MOaospt83N0JbX38wsDzE58Yw95jzovFkU3pxzB1eUFYc4mkuhUMZD8iT1gpUjNMcQ==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@opentelemetry/semantic-conventions": "^1.41.1",
-        "@standard-schema/spec": "^1.1.0",
-        "zod": "^4.5.4"
-      },
-      "peerDependencies": {
-        "@better-auth/utils": "0.4.2",
-        "@better-fetch/fetch": "1.3.2",
-        "@opentelemetry/api": "^1.9.0",
-        "better-call": "1.4.0",
-        "jose": "^6.1.0",
-        "kysely": "^0.28.5 || ^0.29.0",
-        "nanostores": "^1.0.1"
-      },
-      "peerDependenciesMeta": {
-        "@opentelemetry/api": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@better-auth/drizzle-adapter": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.7.3.tgz",
-      "integrity": "sha512-S+nQRlxbUhkR43LrSv8c98ZvOvmv3nrtOnHkiZXkdDkr60PWp7maC2cqgzZ2C9exCC1a+4TugJlx2jRL+r+/9A==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@better-auth/core": "^1.7.3",
-        "@better-auth/utils": "0.4.2",
-        "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0"
-      },
-      "peerDependenciesMeta": {
-        "drizzle-orm": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@better-auth/kysely-adapter": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.7.3.tgz",
-      "integrity": "sha512-UIsyJMIrjUnT+yTaS6dkCxYYmtPwxFHxwSJ8+CLty2II5w9BewlDxDA0/QzhoL/InYCPxQ5Y6xIgLHZG1dhwRA==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@better-auth/core": "^1.7.3",
-        "@better-auth/utils": "0.4.2",
-        "kysely": "^0.28.17 || ^0.29.0"
-      },
-      "peerDependenciesMeta": {
-        "kysely": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@better-auth/memory-adapter": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.7.3.tgz",
-      "integrity": "sha512-WdLANFY/QWC3G351RCzxU+Y9YlW+BQ1oG9NwBTSOUWQw5rZ87ws+weU8tvAMO7sQ4C9gKIlkOKBKUKXrSt91Tw==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@better-auth/core": "^1.7.3",
-        "@better-auth/utils": "0.4.2"
-      }
-    },
-    "node_modules/@better-auth/mongo-adapter": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.7.3.tgz",
-      "integrity": "sha512-YL9m01tNogmFmRvOWJ46M9WwE6HirCXHDell29mtsQB/Qs1TPNLrgj7ybGMMGhQuyj6S218+8Wbls8m9s+i8RQ==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@better-auth/core": "^1.7.3",
-        "@better-auth/utils": "0.4.2",
-        "mongodb": "^6.0.0 || ^7.0.0"
-      },
-      "peerDependenciesMeta": {
-        "mongodb": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@better-auth/prisma-adapter": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.7.3.tgz",
-      "integrity": "sha512-TJ/DhlU7oLzrC626/1wfYA1Pl+lVsXa/zXBZ8d7Rlc2YO5fGd5fsAYJdRrYMyA51iZEo+rWLXMhZ0cez1BamsQ==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@better-auth/core": "^1.7.3",
-        "@better-auth/utils": "0.4.2",
-        "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0",
-        "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@prisma/client": {
-          "optional": true
-        },
-        "prisma": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@better-auth/utils": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.2.tgz",
-      "integrity": "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==",
-      "license": "MIT",
-      "dependencies": {
-        "@noble/hashes": "^2.0.1"
-      }
-    },
-    "node_modules/@better-fetch/fetch": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.2.tgz",
-      "integrity": "sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow==",
-      "license": "MIT"
-    },
-    "node_modules/@cloudflare/kv-asset-handler": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz",
-      "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==",
-      "dev": true,
-      "license": "MIT OR Apache-2.0",
-      "engines": {
-        "node": ">=22.0.0"
-      }
-    },
-    "node_modules/@cloudflare/unenv-preset": {
-      "version": "2.16.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz",
-      "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==",
-      "dev": true,
-      "license": "MIT OR Apache-2.0",
-      "peerDependencies": {
-        "unenv": "2.0.0-rc.24",
-        "workerd": ">1.20260305.0 <2.0.0-0"
-      },
-      "peerDependenciesMeta": {
-        "workerd": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@cloudflare/workerd-darwin-64": {
-      "version": "1.20260828.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260828.1.tgz",
-      "integrity": "sha512-CVd+xPhqUESg8Xhq09TZx0wl4FSirfJGOzvbPz2yHhBIvmNHFFQkSN3rkd7wEwnhQQk37Xi0/aD6ykPLJbmGiQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/@cloudflare/workerd-darwin-arm64": {
-      "version": "1.20260828.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260828.1.tgz",
-      "integrity": "sha512-5HDPXRM152vU5JveByGFk34X57TVyIsfp4cabepAf45DC0MKvm52ucJqAjW1h8bvW4X+zRw9GU35OHF9FEC9Ww==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/@cloudflare/workerd-linux-64": {
-      "version": "1.20260828.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260828.1.tgz",
-      "integrity": "sha512-MQ1Ll9P7F72HHUKizbb7BlDfbY8fRoNMpbIpZoU6uKsSkneFICWSKv6UlgU9EQZ+w0i7TMa12iUgJ8l29eRI9A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/@cloudflare/workerd-linux-arm64": {
-      "version": "1.20260828.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260828.1.tgz",
-      "integrity": "sha512-FBTaUQ1xcU9jcp4OyBPcH8x0QiFvc1iuZL2GkD8zp2q1WyTVHYOptRDQUU+cuHjt0rQ2EIKVPBjahPxfa0joBw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/@cloudflare/workerd-windows-64": {
-      "version": "1.20260828.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260828.1.tgz",
-      "integrity": "sha512-yvr77hC7dUbvK5K+SCg062kkPq3sx+drV1PcgHslzHDYcJBtT0V3X80qLE49LW1vq2svaeNmsVQS+vHsqWu8cQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/@cloudflare/workers-types": {
-      "version": "5.20260919.1",
-      "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-5.20260919.1.tgz",
-      "integrity": "sha512-xUdKJoTHhNcXwnBrfrM1STkzm3oSUc9cRVzP8fO5NyJZ/UtnDnWZHDk9z8IkTnbC2WRWFAS87HICmqZhbHDvQw==",
-      "license": "MIT OR Apache-2.0"
-    },
-    "node_modules/@cspotcode/source-map-support": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
-      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/trace-mapping": "0.3.9"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@drizzle-team/brocli": {
-      "version": "0.10.2",
-      "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz",
-      "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==",
-      "devOptional": true,
-      "license": "Apache-2.0"
-    },
-    "node_modules/@emnapi/runtime": {
-      "version": "1.11.3",
-      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
-      "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz",
-      "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==",
-      "deprecated": "Merged into tsx: https://tsx.hirok.io",
-      "devOptional": true,
-      "license": "MIT",
-      "dependencies": {
-        "esbuild": "~0.18.20",
-        "source-map-support": "^0.5.21"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
-      "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
-      "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
-      "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
-      "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
-      "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
-      "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
-      "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
-      "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
-      "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
-      "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
-      "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
-      "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
-      "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
-      "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
-      "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
-      "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
-      "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
-      "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
-      "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
-      "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
-      "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
-      "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
-      "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
-      "devOptional": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "optionalDependencies": {
-        "@esbuild/android-arm": "0.18.20",
-        "@esbuild/android-arm64": "0.18.20",
-        "@esbuild/android-x64": "0.18.20",
-        "@esbuild/darwin-arm64": "0.18.20",
-        "@esbuild/darwin-x64": "0.18.20",
-        "@esbuild/freebsd-arm64": "0.18.20",
-        "@esbuild/freebsd-x64": "0.18.20",
-        "@esbuild/linux-arm": "0.18.20",
-        "@esbuild/linux-arm64": "0.18.20",
-        "@esbuild/linux-ia32": "0.18.20",
-        "@esbuild/linux-loong64": "0.18.20",
-        "@esbuild/linux-mips64el": "0.18.20",
-        "@esbuild/linux-ppc64": "0.18.20",
-        "@esbuild/linux-riscv64": "0.18.20",
-        "@esbuild/linux-s390x": "0.18.20",
-        "@esbuild/linux-x64": "0.18.20",
-        "@esbuild/netbsd-x64": "0.18.20",
-        "@esbuild/openbsd-x64": "0.18.20",
-        "@esbuild/sunos-x64": "0.18.20",
-        "@esbuild/win32-arm64": "0.18.20",
-        "@esbuild/win32-ia32": "0.18.20",
-        "@esbuild/win32-x64": "0.18.20"
-      }
-    },
-    "node_modules/@esbuild-kit/esm-loader": {
-      "version": "2.6.5",
-      "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz",
-      "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==",
-      "deprecated": "Merged into tsx: https://tsx.hirok.io",
-      "devOptional": true,
-      "license": "MIT",
-      "dependencies": {
-        "@esbuild-kit/core-utils": "^3.3.2",
-        "get-tsconfig": "^4.7.0"
-      }
-    },
-    "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
-      "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
-      "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
-      "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
-      "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
-      "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
-      "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
-      "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
-      "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
-      "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
-      "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ia32": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
-      "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-loong64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
-      "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
-      "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
-      "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
-      "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-s390x": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
-      "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
-      "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
-      "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
-      "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
-      "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
-      "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openharmony-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
-      "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openharmony"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/sunos-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
-      "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-arm64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
-      "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-ia32": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
-      "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-x64": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
-      "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@img/colour": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
-      "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@img/sharp-darwin-arm64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.2.tgz",
-      "integrity": "sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-darwin-arm64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-darwin-x64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.2.tgz",
-      "integrity": "sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-darwin-x64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-freebsd-wasm32": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.2.tgz",
-      "integrity": "sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "dependencies": {
-        "@img/sharp-wasm32": "0.35.2"
-      },
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-darwin-arm64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.1.tgz",
-      "integrity": "sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-darwin-x64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.1.tgz",
-      "integrity": "sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-arm": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.1.tgz",
-      "integrity": "sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-arm64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.1.tgz",
-      "integrity": "sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-ppc64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.1.tgz",
-      "integrity": "sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-riscv64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.1.tgz",
-      "integrity": "sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-s390x": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.1.tgz",
-      "integrity": "sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-x64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.1.tgz",
-      "integrity": "sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.1.tgz",
-      "integrity": "sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linuxmusl-x64": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.1.tgz",
-      "integrity": "sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-linux-arm": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.2.tgz",
-      "integrity": "sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-arm": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linux-arm64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.2.tgz",
-      "integrity": "sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-arm64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linux-ppc64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.2.tgz",
-      "integrity": "sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-ppc64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linux-riscv64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.2.tgz",
-      "integrity": "sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-riscv64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linux-s390x": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.2.tgz",
-      "integrity": "sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-s390x": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linux-x64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.2.tgz",
-      "integrity": "sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-x64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linuxmusl-arm64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.2.tgz",
-      "integrity": "sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linuxmusl-arm64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-linuxmusl-x64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.2.tgz",
-      "integrity": "sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linuxmusl-x64": "1.3.1"
-      }
-    },
-    "node_modules/@img/sharp-wasm32": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.2.tgz",
-      "integrity": "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==",
-      "dev": true,
-      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/runtime": "^1.11.1"
-      },
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-webcontainers-wasm32": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.2.tgz",
-      "integrity": "sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==",
-      "cpu": [
-        "wasm32"
-      ],
-      "dev": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "dependencies": {
-        "@img/sharp-wasm32": "0.35.2"
-      },
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-win32-arm64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.2.tgz",
-      "integrity": "sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0 AND LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-win32-ia32": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.2.tgz",
-      "integrity": "sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "Apache-2.0 AND LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": "^20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-win32-x64": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.2.tgz",
-      "integrity": "sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "Apache-2.0 AND LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
-      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
-      "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.9",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
-      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/resolve-uri": "^3.0.3",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
-      }
-    },
-    "node_modules/@noble/ciphers": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.4.0.tgz",
-      "integrity": "sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 20.19.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@noble/hashes": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz",
-      "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 20.19.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@opentelemetry/semantic-conventions": {
-      "version": "1.43.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz",
-      "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==",
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=14"
-      }
-    },
-    "node_modules/@poppinss/colors": {
-      "version": "4.1.6",
-      "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz",
-      "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "kleur": "^4.1.5"
-      }
-    },
-    "node_modules/@poppinss/dumper": {
-      "version": "0.6.5",
-      "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz",
-      "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@poppinss/colors": "^4.1.5",
-        "@sindresorhus/is": "^7.0.2",
-        "supports-color": "^10.0.0"
-      }
-    },
-    "node_modules/@poppinss/exception": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz",
-      "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@sindresorhus/is": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz",
-      "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18"
-      },
-      "funding": {
-        "url": "https://github.com/sindresorhus/is?sponsor=1"
-      }
-    },
-    "node_modules/@speed-highlight/core": {
-      "version": "1.2.24",
-      "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.24.tgz",
-      "integrity": "sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==",
-      "dev": true,
-      "license": "CC0-1.0"
-    },
-    "node_modules/@standard-schema/spec": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
-      "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
-      "license": "MIT"
-    },
-    "node_modules/@types/node": {
-      "version": "22.20.4",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.4.tgz",
-      "integrity": "sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "undici-types": "~6.21.0"
-      }
-    },
-    "node_modules/better-auth": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.7.3.tgz",
-      "integrity": "sha512-8xGp68JQ+l36kniDEgP8bP99TLi1GdEv0NTEUBkyqnYnus/cgFUZseUfqUHKzr2BAsg2O6aD88I9f0U68shanQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@better-auth/core": "1.7.3",
-        "@better-auth/drizzle-adapter": "1.7.3",
-        "@better-auth/kysely-adapter": "1.7.3",
-        "@better-auth/memory-adapter": "1.7.3",
-        "@better-auth/mongo-adapter": "1.7.3",
-        "@better-auth/prisma-adapter": "1.7.3",
-        "@better-auth/telemetry": "1.7.3",
-        "@better-auth/utils": "0.4.2",
-        "@better-fetch/fetch": "1.3.1",
-        "@noble/ciphers": "^2.2.0",
-        "@noble/hashes": "^2.2.0",
-        "better-call": "1.4.0",
-        "defu": "^6.1.4",
-        "jose": "^6.2.3",
-        "kysely": "^0.28.17 || ^0.29.0",
-        "nanostores": "^1.3.0",
-        "zod": "^4.5.4"
-      },
-      "peerDependencies": {
-        "@lynx-js/react": "*",
-        "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0",
-        "@sveltejs/kit": "^2.0.0",
-        "@tanstack/react-start": "^1.0.0",
-        "@tanstack/solid-start": "^1.0.0",
-        "better-sqlite3": "^12.0.0",
-        "drizzle-kit": ">=0.31.4 || >=1.0.0-beta.1",
-        "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0",
-        "mongodb": "^6.0.0 || ^7.0.0",
-        "mysql2": "^3.0.0",
-        "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
-        "pg": "^8.0.0",
-        "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0",
-        "react": "^18.0.0 || ^19.0.0",
-        "react-dom": "^18.0.0 || ^19.0.0",
-        "solid-js": "^1.0.0",
-        "svelte": "^4.0.0 || ^5.0.0",
-        "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0",
-        "vue": "^3.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@lynx-js/react": {
-          "optional": true
-        },
-        "@prisma/client": {
-          "optional": true
-        },
-        "@sveltejs/kit": {
-          "optional": true
-        },
-        "@tanstack/react-start": {
-          "optional": true
-        },
-        "@tanstack/solid-start": {
-          "optional": true
-        },
-        "better-sqlite3": {
-          "optional": true
-        },
-        "drizzle-kit": {
-          "optional": true
-        },
-        "drizzle-orm": {
-          "optional": true
-        },
-        "mongodb": {
-          "optional": true
-        },
-        "mysql2": {
-          "optional": true
-        },
-        "next": {
-          "optional": true
-        },
-        "pg": {
-          "optional": true
-        },
-        "prisma": {
-          "optional": true
-        },
-        "react": {
-          "optional": true
-        },
-        "react-dom": {
-          "optional": true
-        },
-        "solid-js": {
-          "optional": true
-        },
-        "svelte": {
-          "optional": true
-        },
-        "vitest": {
-          "optional": true
-        },
-        "vue": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/better-auth-cloudflare": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/better-auth-cloudflare/-/better-auth-cloudflare-0.3.1.tgz",
-      "integrity": "sha512-kvGYe1++fH4ODkb2o/WNkGWQtPYuWXjNPaKDAvPz8ChbaROW9TmZY0AIan9K52p+p+Pe53ZnQ7kKOWWZ2x0KrQ==",
-      "license": "MIT",
-      "dependencies": {
-        "drizzle-orm": "^0.45.0",
-        "mime": "^4.1.0",
-        "zod": "^4.3.0"
-      },
-      "peerDependencies": {
-        "@better-auth/drizzle-adapter": "^1.5.0",
-        "@cloudflare/workers-types": ">=4",
-        "better-auth": "^1.5.0"
-      }
-    },
-    "node_modules/better-auth/node_modules/@better-auth/core": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.7.3.tgz",
-      "integrity": "sha512-JdP7lOkyE83jgjn7RilJj1XvZ7n2JjRsErKJuaXchjyuNo6cf1iVd3GtbhAtiUyJJkWdk8yL+LaUBKT80H0zLA==",
-      "license": "MIT",
-      "dependencies": {
-        "@opentelemetry/semantic-conventions": "^1.41.1",
-        "@standard-schema/spec": "^1.1.0",
-        "zod": "^4.5.4"
-      },
-      "peerDependencies": {
-        "@better-auth/utils": "0.4.2",
-        "@better-fetch/fetch": "1.3.1",
-        "@cloudflare/workers-types": ">=4",
-        "@opentelemetry/api": "^1.9.0",
-        "better-call": "1.4.0",
-        "jose": "^6.1.0",
-        "kysely": "^0.28.5 || ^0.29.0",
-        "nanostores": "^1.0.1"
-      },
-      "peerDependenciesMeta": {
-        "@cloudflare/workers-types": {
-          "optional": true
-        },
-        "@opentelemetry/api": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/better-auth/node_modules/@better-auth/telemetry": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.7.3.tgz",
-      "integrity": "sha512-aixgHbJhGvS8PRczX/LR3murYyBnIvOGmJw37ZZBMg6ZtLR/UBJAkufbDi1HYn5THSuTJ3D5DtY85Ahh/ABQtw==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@better-auth/core": "^1.7.3",
-        "@better-auth/utils": "0.4.2",
-        "@better-fetch/fetch": "1.3.1"
-      }
-    },
-    "node_modules/better-auth/node_modules/@better-fetch/fetch": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.1.tgz",
-      "integrity": "sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==",
-      "license": "MIT"
-    },
-    "node_modules/better-call": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.4.0.tgz",
-      "integrity": "sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA==",
-      "license": "MIT",
-      "dependencies": {
-        "@better-auth/utils": "^0.5.0",
-        "@better-fetch/fetch": "^1.3.1",
-        "rou3": "^0.9.1",
-        "set-cookie-parser": "^3.1.2"
-      },
-      "peerDependencies": {
-        "zod": "^4.0.0"
-      },
-      "peerDependenciesMeta": {
-        "zod": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/better-call/node_modules/@better-auth/utils": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.5.0.tgz",
-      "integrity": "sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA==",
-      "license": "MIT",
-      "dependencies": {
-        "@noble/hashes": "^2.0.1"
-      }
-    },
-    "node_modules/blake3-wasm": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
-      "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/buffer-from": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
-      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
-      "devOptional": true,
-      "license": "MIT"
-    },
-    "node_modules/cookie": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
-      "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/express"
-      }
-    },
-    "node_modules/defu": {
-      "version": "6.1.7",
-      "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
-      "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
-      "license": "MIT"
-    },
-    "node_modules/detect-libc": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
-      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/drizzle-kit": {
-      "version": "0.31.10",
-      "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.10.tgz",
-      "integrity": "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==",
-      "devOptional": true,
-      "license": "MIT",
-      "dependencies": {
-        "@drizzle-team/brocli": "^0.10.2",
-        "@esbuild-kit/esm-loader": "^2.5.5",
-        "esbuild": "^0.25.4",
-        "tsx": "^4.21.0"
-      },
-      "bin": {
-        "drizzle-kit": "bin.cjs"
-      }
-    },
-    "node_modules/drizzle-orm": {
-      "version": "0.45.2",
-      "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.45.2.tgz",
-      "integrity": "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==",
-      "license": "Apache-2.0",
-      "peerDependencies": {
-        "@aws-sdk/client-rds-data": ">=3",
-        "@cloudflare/workers-types": ">=4",
-        "@electric-sql/pglite": ">=0.2.0",
-        "@libsql/client": ">=0.10.0",
-        "@libsql/client-wasm": ">=0.10.0",
-        "@neondatabase/serverless": ">=0.10.0",
-        "@op-engineering/op-sqlite": ">=2",
-        "@opentelemetry/api": "^1.4.1",
-        "@planetscale/database": ">=1.13",
-        "@prisma/client": "*",
-        "@tidbcloud/serverless": "*",
-        "@types/better-sqlite3": "*",
-        "@types/pg": "*",
-        "@types/sql.js": "*",
-        "@upstash/redis": ">=1.34.7",
-        "@vercel/postgres": ">=0.8.0",
-        "@xata.io/client": "*",
-        "better-sqlite3": ">=7",
-        "bun-types": "*",
-        "expo-sqlite": ">=14.0.0",
-        "gel": ">=2",
-        "knex": "*",
-        "kysely": "*",
-        "mysql2": ">=2",
-        "pg": ">=8",
-        "postgres": ">=3",
-        "sql.js": ">=1",
-        "sqlite3": ">=5"
-      },
-      "peerDependenciesMeta": {
-        "@aws-sdk/client-rds-data": {
-          "optional": true
-        },
-        "@cloudflare/workers-types": {
-          "optional": true
-        },
-        "@electric-sql/pglite": {
-          "optional": true
-        },
-        "@libsql/client": {
-          "optional": true
-        },
-        "@libsql/client-wasm": {
-          "optional": true
-        },
-        "@neondatabase/serverless": {
-          "optional": true
-        },
-        "@op-engineering/op-sqlite": {
-          "optional": true
-        },
-        "@opentelemetry/api": {
-          "optional": true
-        },
-        "@planetscale/database": {
-          "optional": true
-        },
-        "@prisma/client": {
-          "optional": true
-        },
-        "@tidbcloud/serverless": {
-          "optional": true
-        },
-        "@types/better-sqlite3": {
-          "optional": true
-        },
-        "@types/pg": {
-          "optional": true
-        },
-        "@types/sql.js": {
-          "optional": true
-        },
-        "@upstash/redis": {
-          "optional": true
-        },
-        "@vercel/postgres": {
-          "optional": true
-        },
-        "@xata.io/client": {
-          "optional": true
-        },
-        "better-sqlite3": {
-          "optional": true
-        },
-        "bun-types": {
-          "optional": true
-        },
-        "expo-sqlite": {
-          "optional": true
-        },
-        "gel": {
-          "optional": true
-        },
-        "knex": {
-          "optional": true
-        },
-        "kysely": {
-          "optional": true
-        },
-        "mysql2": {
-          "optional": true
-        },
-        "pg": {
-          "optional": true
-        },
-        "postgres": {
-          "optional": true
-        },
-        "prisma": {
-          "optional": true
-        },
-        "sql.js": {
-          "optional": true
-        },
-        "sqlite3": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/error-stack-parser-es": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
-      "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
-      "dev": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      }
-    },
-    "node_modules/esbuild": {
-      "version": "0.25.12",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
-      "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
-      "devOptional": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=18"
-      },
-      "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.25.12",
-        "@esbuild/android-arm": "0.25.12",
-        "@esbuild/android-arm64": "0.25.12",
-        "@esbuild/android-x64": "0.25.12",
-        "@esbuild/darwin-arm64": "0.25.12",
-        "@esbuild/darwin-x64": "0.25.12",
-        "@esbuild/freebsd-arm64": "0.25.12",
-        "@esbuild/freebsd-x64": "0.25.12",
-        "@esbuild/linux-arm": "0.25.12",
-        "@esbuild/linux-arm64": "0.25.12",
-        "@esbuild/linux-ia32": "0.25.12",
-        "@esbuild/linux-loong64": "0.25.12",
-        "@esbuild/linux-mips64el": "0.25.12",
-        "@esbuild/linux-ppc64": "0.25.12",
-        "@esbuild/linux-riscv64": "0.25.12",
-        "@esbuild/linux-s390x": "0.25.12",
-        "@esbuild/linux-x64": "0.25.12",
-        "@esbuild/netbsd-arm64": "0.25.12",
-        "@esbuild/netbsd-x64": "0.25.12",
-        "@esbuild/openbsd-arm64": "0.25.12",
-        "@esbuild/openbsd-x64": "0.25.12",
-        "@esbuild/openharmony-arm64": "0.25.12",
-        "@esbuild/sunos-x64": "0.25.12",
-        "@esbuild/win32-arm64": "0.25.12",
-        "@esbuild/win32-ia32": "0.25.12",
-        "@esbuild/win32-x64": "0.25.12"
-      }
-    },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
-    "node_modules/get-tsconfig": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz",
-      "integrity": "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==",
-      "devOptional": true,
-      "license": "MIT",
-      "dependencies": {
-        "resolve-pkg-maps": "^1.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
-      }
-    },
-    "node_modules/hono": {
-      "version": "4.13.5",
-      "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.5.tgz",
-      "integrity": "sha512-O6+/eCYRkzzzy0rPWwKLiGBR1nFuUPZynnwjxN1MBA62NNqbT0wQEzQyK2gSO5yDIDB336sXQleAhOHrzlYyKw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=16.9.0"
-      }
-    },
-    "node_modules/jose": {
-      "version": "6.2.12",
-      "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz",
-      "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/panva"
-      }
-    },
-    "node_modules/kleur": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
-      "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/kysely": {
-      "version": "0.29.6",
-      "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.29.6.tgz",
-      "integrity": "sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=22.0.0"
-      }
-    },
-    "node_modules/mime": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz",
-      "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==",
-      "funding": [
-        "https://github.com/sponsors/broofa"
-      ],
-      "license": "MIT",
-      "bin": {
-        "mime": "bin/cli.js"
-      },
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/miniflare": {
-      "version": "5.20260828.0-alpha",
-      "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-5.20260828.0-alpha.tgz",
-      "integrity": "sha512-6nbxhZEcz/UET3Y1OnYPsrAUjUmuFoib3ynUqteRdn1YnDxsLg8cwgZJZCk9QmtOmGzXwzXzgE/d/C0dJAPtVw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@cspotcode/source-map-support": "0.8.1",
-        "sharp": "0.35.2",
-        "undici": "7.29.0",
-        "workerd": "1.20260828.1",
-        "ws": "8.21.0",
-        "youch": "4.1.0-beta.10"
-      },
-      "engines": {
-        "node": ">=22.0.0"
-      }
-    },
-    "node_modules/nanostores": {
-      "version": "1.5.3",
-      "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.5.3.tgz",
-      "integrity": "sha512-rQLB6eV4f2AW/n3L0JmwCROpaisYy9EDEADvEFSd1C/qG8hB6O5TPlh9A791JRbJr4CnMQBzptDcvD9OR1+6WA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "engines": {
-        "node": "^20.0.0 || >=22.0.0"
-      }
-    },
-    "node_modules/path-to-regexp": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
-      "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/pathe": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
-      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/resolve-pkg-maps": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
-      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
-      "devOptional": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
-      }
-    },
-    "node_modules/rou3": {
-      "version": "0.9.2",
-      "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.9.2.tgz",
-      "integrity": "sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==",
-      "license": "MIT"
-    },
-    "node_modules/semver": {
-      "version": "7.8.5",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
-      "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
-      "dev": true,
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/set-cookie-parser": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz",
-      "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==",
-      "license": "MIT"
-    },
-    "node_modules/sharp": {
-      "version": "0.35.2",
-      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.2.tgz",
-      "integrity": "sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@img/colour": "^1.1.0",
-        "detect-libc": "^2.1.2",
-        "semver": "^7.8.4"
-      },
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-darwin-arm64": "0.35.2",
-        "@img/sharp-darwin-x64": "0.35.2",
-        "@img/sharp-freebsd-wasm32": "0.35.2",
-        "@img/sharp-libvips-darwin-arm64": "1.3.1",
-        "@img/sharp-libvips-darwin-x64": "1.3.1",
-        "@img/sharp-libvips-linux-arm": "1.3.1",
-        "@img/sharp-libvips-linux-arm64": "1.3.1",
-        "@img/sharp-libvips-linux-ppc64": "1.3.1",
-        "@img/sharp-libvips-linux-riscv64": "1.3.1",
-        "@img/sharp-libvips-linux-s390x": "1.3.1",
-        "@img/sharp-libvips-linux-x64": "1.3.1",
-        "@img/sharp-libvips-linuxmusl-arm64": "1.3.1",
-        "@img/sharp-libvips-linuxmusl-x64": "1.3.1",
-        "@img/sharp-linux-arm": "0.35.2",
-        "@img/sharp-linux-arm64": "0.35.2",
-        "@img/sharp-linux-ppc64": "0.35.2",
-        "@img/sharp-linux-riscv64": "0.35.2",
-        "@img/sharp-linux-s390x": "0.35.2",
-        "@img/sharp-linux-x64": "0.35.2",
-        "@img/sharp-linuxmusl-arm64": "0.35.2",
-        "@img/sharp-linuxmusl-x64": "0.35.2",
-        "@img/sharp-webcontainers-wasm32": "0.35.2",
-        "@img/sharp-win32-arm64": "0.35.2",
-        "@img/sharp-win32-ia32": "0.35.2",
-        "@img/sharp-win32-x64": "0.35.2"
-      }
-    },
-    "node_modules/source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "devOptional": true,
-      "license": "BSD-3-Clause",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/source-map-support": {
-      "version": "0.5.21",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
-      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
-      "devOptional": true,
-      "license": "MIT",
-      "dependencies": {
-        "buffer-from": "^1.0.0",
-        "source-map": "^0.6.0"
-      }
-    },
-    "node_modules/supports-color": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
-      "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/supports-color?sponsor=1"
-      }
-    },
-    "node_modules/tslib": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
-      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
-      "dev": true,
-      "license": "0BSD",
-      "optional": true
-    },
-    "node_modules/tsx": {
-      "version": "4.23.13",
-      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.13.tgz",
-      "integrity": "sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==",
-      "devOptional": true,
-      "license": "MIT",
-      "dependencies": {
-        "esbuild": "~0.28.0"
-      },
-      "bin": {
-        "tsx": "dist/cli.mjs"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.3"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
-      "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/android-arm": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
-      "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/android-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
-      "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/android-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
-      "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
-      "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/darwin-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
-      "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
-      "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
-      "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-arm": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
-      "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
-      "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-ia32": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
-      "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-loong64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
-      "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
-      "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
-      "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
-      "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-s390x": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
-      "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/linux-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
-      "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
-      "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
-      "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
-      "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
-      "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
-      "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openharmony"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/sunos-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
-      "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/win32-arm64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
-      "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/win32-ia32": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
-      "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/@esbuild/win32-x64": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
-      "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/tsx/node_modules/esbuild": {
-      "version": "0.28.2",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
-      "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
-      "devOptional": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=18"
-      },
-      "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.28.2",
-        "@esbuild/android-arm": "0.28.2",
-        "@esbuild/android-arm64": "0.28.2",
-        "@esbuild/android-x64": "0.28.2",
-        "@esbuild/darwin-arm64": "0.28.2",
-        "@esbuild/darwin-x64": "0.28.2",
-        "@esbuild/freebsd-arm64": "0.28.2",
-        "@esbuild/freebsd-x64": "0.28.2",
-        "@esbuild/linux-arm": "0.28.2",
-        "@esbuild/linux-arm64": "0.28.2",
-        "@esbuild/linux-ia32": "0.28.2",
-        "@esbuild/linux-loong64": "0.28.2",
-        "@esbuild/linux-mips64el": "0.28.2",
-        "@esbuild/linux-ppc64": "0.28.2",
-        "@esbuild/linux-riscv64": "0.28.2",
-        "@esbuild/linux-s390x": "0.28.2",
-        "@esbuild/linux-x64": "0.28.2",
-        "@esbuild/netbsd-arm64": "0.28.2",
-        "@esbuild/netbsd-x64": "0.28.2",
-        "@esbuild/openbsd-arm64": "0.28.2",
-        "@esbuild/openbsd-x64": "0.28.2",
-        "@esbuild/openharmony-arm64": "0.28.2",
-        "@esbuild/sunos-x64": "0.28.2",
-        "@esbuild/win32-arm64": "0.28.2",
-        "@esbuild/win32-ia32": "0.28.2",
-        "@esbuild/win32-x64": "0.28.2"
-      }
-    },
-    "node_modules/typescript": {
-      "version": "5.9.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
-      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/undici": {
-      "version": "7.29.0",
-      "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
-      "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=20.18.1"
-      }
-    },
-    "node_modules/undici-types": {
-      "version": "6.21.0",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
-      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/unenv": {
-      "version": "2.0.0-rc.24",
-      "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
-      "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "pathe": "^2.0.3"
-      }
-    },
-    "node_modules/workerd": {
-      "version": "1.20260828.1",
-      "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260828.1.tgz",
-      "integrity": "sha512-pB9yvt0kkwZDAGZHmpY59r0o3hM0DzdW6BJERqwZOhunZ3ssOyDSgQxOQer2cSZW4YCFeOTIQYN1qwhK5wv/Cw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "Apache-2.0",
-      "bin": {
-        "workerd": "bin/workerd"
-      },
-      "engines": {
-        "node": ">=16"
-      },
-      "optionalDependencies": {
-        "@cloudflare/workerd-darwin-64": "1.20260828.1",
-        "@cloudflare/workerd-darwin-arm64": "1.20260828.1",
-        "@cloudflare/workerd-linux-64": "1.20260828.1",
-        "@cloudflare/workerd-linux-arm64": "1.20260828.1",
-        "@cloudflare/workerd-windows-64": "1.20260828.1"
-      }
-    },
-    "node_modules/wrangler": {
-      "version": "4.127.1",
-      "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.127.1.tgz",
-      "integrity": "sha512-OzsiNgaI8i681L/+KnAKc+uEZ5D57xK5JuNvCOpRKICF4/5Q3Cu1oTGuUiT/f3GDUqQb3gzXNT0tfOHGMEtknw==",
-      "dev": true,
-      "license": "MIT OR Apache-2.0",
-      "dependencies": {
-        "@cloudflare/kv-asset-handler": "0.5.0",
-        "@cloudflare/unenv-preset": "2.16.1",
-        "blake3-wasm": "2.1.5",
-        "esbuild": "0.28.1",
-        "miniflare": "5.20260828.0-alpha",
-        "path-to-regexp": "6.3.0",
-        "unenv": "2.0.0-rc.24",
-        "workerd": "1.20260828.1"
-      },
-      "bin": {
-        "cf-wrangler": "bin/cf-wrangler.js",
-        "wrangler": "bin/wrangler.js",
-        "wrangler2": "bin/wrangler.js"
-      },
-      "engines": {
-        "node": ">=22.0.0"
-      },
-      "optionalDependencies": {
-        "fsevents": "2.3.3"
-      },
-      "peerDependencies": {
-        "@cloudflare/workers-types": "^5.20260828.1"
-      },
-      "peerDependenciesMeta": {
-        "@cloudflare/workers-types": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/aix-ppc64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
-      "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/android-arm": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
-      "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/android-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
-      "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/android-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
-      "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
-      "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/darwin-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
-      "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
-      "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
-      "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-arm": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
-      "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
-      "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-ia32": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
-      "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-loong64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
-      "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
-      "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
-      "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
-      "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-s390x": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
-      "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/linux-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
-      "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
-      "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
-      "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
-      "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
-      "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/openharmony-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
-      "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openharmony"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/sunos-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
-      "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/win32-arm64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
-      "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/win32-ia32": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
-      "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/@esbuild/win32-x64": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
-      "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/wrangler/node_modules/esbuild": {
-      "version": "0.28.1",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
-      "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=18"
-      },
-      "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.28.1",
-        "@esbuild/android-arm": "0.28.1",
-        "@esbuild/android-arm64": "0.28.1",
-        "@esbuild/android-x64": "0.28.1",
-        "@esbuild/darwin-arm64": "0.28.1",
-        "@esbuild/darwin-x64": "0.28.1",
-        "@esbuild/freebsd-arm64": "0.28.1",
-        "@esbuild/freebsd-x64": "0.28.1",
-        "@esbuild/linux-arm": "0.28.1",
-        "@esbuild/linux-arm64": "0.28.1",
-        "@esbuild/linux-ia32": "0.28.1",
-        "@esbuild/linux-loong64": "0.28.1",
-        "@esbuild/linux-mips64el": "0.28.1",
-        "@esbuild/linux-ppc64": "0.28.1",
-        "@esbuild/linux-riscv64": "0.28.1",
-        "@esbuild/linux-s390x": "0.28.1",
-        "@esbuild/linux-x64": "0.28.1",
-        "@esbuild/netbsd-arm64": "0.28.1",
-        "@esbuild/netbsd-x64": "0.28.1",
-        "@esbuild/openbsd-arm64": "0.28.1",
-        "@esbuild/openbsd-x64": "0.28.1",
-        "@esbuild/openharmony-arm64": "0.28.1",
-        "@esbuild/sunos-x64": "0.28.1",
-        "@esbuild/win32-arm64": "0.28.1",
-        "@esbuild/win32-ia32": "0.28.1",
-        "@esbuild/win32-x64": "0.28.1"
-      }
-    },
-    "node_modules/ws": {
-      "version": "8.21.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
-      "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=10.0.0"
-      },
-      "peerDependencies": {
-        "bufferutil": "^4.0.1",
-        "utf-8-validate": ">=5.0.2"
-      },
-      "peerDependenciesMeta": {
-        "bufferutil": {
-          "optional": true
-        },
-        "utf-8-validate": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/youch": {
-      "version": "4.1.0-beta.10",
-      "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz",
-      "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@poppinss/colors": "^4.1.5",
-        "@poppinss/dumper": "^0.6.4",
-        "@speed-highlight/core": "^1.2.7",
-        "cookie": "^1.0.2",
-        "youch-core": "^0.3.3"
-      }
-    },
-    "node_modules/youch-core": {
-      "version": "0.3.3",
-      "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz",
-      "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@poppinss/exception": "^1.2.2",
-        "error-stack-parser-es": "^1.0.5"
-      }
-    },
-    "node_modules/zod": {
-      "version": "4.6.5",
-      "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
-      "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/colinhacks"
-      }
-    }
-  }
-}

+ 21 - 16
package.json

@@ -1,13 +1,16 @@
 {
-  "name": "pm2000",
+  "name": "decision-maker-2000",
+  "type": "module",
   "scripts": {
-    "dev": "wrangler dev",
-    "build": "npx tsc --noEmit",
-    "deploy": "wrangler deploy --minify",
+    "dev": "pnpm build:client && wrangler dev",
+    "build": "pnpm cf-typegen && pnpm build:client && tsc --noEmit",
+    "build:client": "esbuild client/app.js --bundle --format=esm --target=es2022 --outfile=public/app.js",
+    "test": "node --test tests/*.test.ts",
+    "deploy": "pnpm build && wrangler deploy --minify",
     "cf-typegen": "wrangler types",
     "auth:generate": "npx --yes auth@1.7.3 generate --config src/auth/index.ts --output src/db/auth.schema.ts -y",
     "auth:format": "npx --yes prettier --write src/db/auth.schema.ts",
-    "auth:update": "npm run auth:generate && npm run auth:format",
+    "auth:update": "pnpm auth:generate && pnpm auth:format",
     "db:generate": "drizzle-kit generate",
     "db:migrate:dev": "wrangler d1 migrations apply DATABASE --local",
     "db:migrate:prod": "wrangler d1 migrations apply DATABASE --remote",
@@ -15,18 +18,20 @@
     "db:studio:prod": "NODE_ENV=production drizzle-kit studio"
   },
   "dependencies": {
-    "@better-auth/drizzle-adapter": "1.7.3",
-    "@cloudflare/workers-types": "^5.20260830.1",
-    "better-auth": "1.7.3",
-    "better-auth-cloudflare": "latest",
-    "drizzle-orm": "^0.45.0",
-    "hono": "4.13.5"
+    "@better-auth/drizzle-adapter": "1.7.5",
+    "@cloudflare/workers-types": "5.20260919.1",
+    "better-auth": "1.7.5",
+    "better-auth-cloudflare": "0.3.1",
+    "drizzle-orm": "0.45.2",
+    "hono": "4.13.8",
+    "lit-html": "3.3.3"
   },
   "devDependencies": {
-    "@types/node": "^22.15.30",
-    "drizzle-kit": "^0.31.4",
-    "typescript": "^5.8.3",
-    "wrangler": "4.127.1"
+    "@types/node": "22.20.4",
+    "drizzle-kit": "0.31.10",
+    "esbuild": "0.28.2",
+    "typescript": "5.9.3",
+    "wrangler": "4.135.0"
   },
   "pnpm": {
     "overrides": {
@@ -35,4 +40,4 @@
     }
   },
   "packageManager": "pnpm@10.10.0"
-}
+}

+ 2240 - 0
pnpm-lock.yaml

@@ -0,0 +1,2240 @@
+lockfileVersion: '9.0'
+
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
+overrides:
+  '@better-auth/utils': 0.4.2
+  defu: 6.1.5
+
+importers:
+
+  .:
+    dependencies:
+      '@better-auth/drizzle-adapter':
+        specifier: 1.7.5
+        version: 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6))
+      '@cloudflare/workers-types':
+        specifier: 5.20260919.1
+        version: 5.20260919.1
+      better-auth:
+        specifier: 1.7.5
+        version: 1.7.5(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6))
+      better-auth-cloudflare:
+        specifier: 0.3.1
+        version: 0.3.1(@better-auth/drizzle-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)))(@cloudflare/workers-types@5.20260919.1)(better-auth@1.7.5(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)))(kysely@0.29.6)
+      drizzle-orm:
+        specifier: 0.45.2
+        version: 0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)
+      hono:
+        specifier: 4.13.8
+        version: 4.13.8
+      lit-html:
+        specifier: 3.3.3
+        version: 3.3.3
+    devDependencies:
+      '@types/node':
+        specifier: 22.20.4
+        version: 22.20.4
+      drizzle-kit:
+        specifier: 0.31.10
+        version: 0.31.10
+      esbuild:
+        specifier: 0.28.2
+        version: 0.28.2
+      typescript:
+        specifier: 5.9.3
+        version: 5.9.3
+      wrangler:
+        specifier: 4.135.0
+        version: 4.135.0(@cloudflare/workers-types@5.20260919.1)(@types/node@22.20.4)
+
+packages:
+
+  '@better-auth/core@1.7.5':
+    resolution: {integrity: sha512-kVlSu4H8OKQfjg4b/Zj5MOaospt83N0JbX38wsDzE58Yw95jzovFkU3pxzB1eUFYc4mkuhUMZD8iT1gpUjNMcQ==}
+    peerDependencies:
+      '@better-auth/utils': 0.4.2
+      '@better-fetch/fetch': 1.3.2
+      '@opentelemetry/api': ^1.9.0
+      better-call: 1.4.0
+      jose: ^6.1.0
+      kysely: ^0.28.5 || ^0.29.0
+      nanostores: ^1.0.1
+    peerDependenciesMeta:
+      '@opentelemetry/api':
+        optional: true
+
+  '@better-auth/drizzle-adapter@1.7.5':
+    resolution: {integrity: sha512-9SM7v1735SoaedRDcDbHc5ULgXEd2vUlEJkvRHpMF2Q9qf59TRh1b5A9hryyecyi56bm/0CNUDU3nY0uVWj5/Q==}
+    peerDependencies:
+      '@better-auth/core': ^1.7.5
+      '@better-auth/utils': 0.4.2
+      drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0
+    peerDependenciesMeta:
+      drizzle-orm:
+        optional: true
+
+  '@better-auth/kysely-adapter@1.7.5':
+    resolution: {integrity: sha512-1wE5gvnjW+c1i4GrLtL9HLn3s0Xrq4YneCDan1NO1dpz0mEguLFNlzfnUGykTFrDwvFh2X5rkIbA8ALCj6WzXQ==}
+    peerDependencies:
+      '@better-auth/core': ^1.7.5
+      '@better-auth/utils': 0.4.2
+      kysely: ^0.28.17 || ^0.29.0
+    peerDependenciesMeta:
+      kysely:
+        optional: true
+
+  '@better-auth/memory-adapter@1.7.5':
+    resolution: {integrity: sha512-YDmnfR9zOXbn5SNYYwfHBPuc19hg1d1C1vUXb+Hm8Q91pTsstFNX5OTlZbo7f28q06FpogAEfGGCN/2QV39cig==}
+    peerDependencies:
+      '@better-auth/core': ^1.7.5
+      '@better-auth/utils': 0.4.2
+
+  '@better-auth/mongo-adapter@1.7.5':
+    resolution: {integrity: sha512-Yq0LfF0VlA9Kfjcjp/v43MSsChv7vKd1ct0Mt15px4zlqaCPIGfPbjw9YNM6jTo0fGpqLR0n15PllSWmLLRp9g==}
+    peerDependencies:
+      '@better-auth/core': ^1.7.5
+      '@better-auth/utils': 0.4.2
+      mongodb: ^6.0.0 || ^7.0.0
+    peerDependenciesMeta:
+      mongodb:
+        optional: true
+
+  '@better-auth/prisma-adapter@1.7.5':
+    resolution: {integrity: sha512-QfW6HS9vK0FMcbI/GsQLdplICxOz0EPzYWGONZT4ovL3cSItd4YH/09USbPPVl+VUQCdznAQIk+n+NKvHdmSag==}
+    peerDependencies:
+      '@better-auth/core': ^1.7.5
+      '@better-auth/utils': 0.4.2
+      '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0
+      prisma: ^5.0.0 || ^6.0.0 || ^7.0.0
+    peerDependenciesMeta:
+      '@prisma/client':
+        optional: true
+      prisma:
+        optional: true
+
+  '@better-auth/telemetry@1.7.5':
+    resolution: {integrity: sha512-e/REPqMy9Em+gC6G0xWBikiMLRuy532Er7jqdoNkPBa65FbywgWcm1cZbgdW5CnHsrM3OLZsmKn14yeGoDISeg==}
+    peerDependencies:
+      '@better-auth/core': ^1.7.5
+      '@better-auth/utils': 0.4.2
+      '@better-fetch/fetch': 1.3.2
+
+  '@better-auth/utils@0.4.2':
+    resolution: {integrity: sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==}
+
+  '@better-fetch/fetch@1.3.2':
+    resolution: {integrity: sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow==}
+
+  '@cloudflare/kv-asset-handler@0.5.0':
+    resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==}
+    engines: {node: '>=22.0.0'}
+
+  '@cloudflare/unenv-preset@2.16.1':
+    resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==}
+    peerDependencies:
+      unenv: 2.0.0-rc.24
+      workerd: '>1.20260305.0 <2.0.0-0'
+    peerDependenciesMeta:
+      workerd:
+        optional: true
+
+  '@cloudflare/workerd-darwin-64@1.20260918.1':
+    resolution: {integrity: sha512-H5Em6Wd0jjxaloYh2rp+WLBl2eWbkk7nSP1svGt6K1RSv/rNVqmKdpjZPJTBSavOmeYGa88qvtOWwS+33OHTqQ==}
+    engines: {node: '>=16'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@cloudflare/workerd-darwin-arm64@1.20260918.1':
+    resolution: {integrity: sha512-CR9JRZEQo93fNgBVF4Df2H2/VYO4n7rxSseSwCVv3bJQEb0huADUSCj2FK4ipxar8ToOEB4wawyw0vJo5U/rQQ==}
+    engines: {node: '>=16'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@cloudflare/workerd-linux-64@1.20260918.1':
+    resolution: {integrity: sha512-UQ2nnY3qpXLzQ80frmWO+8HvtqyWaQILe8QYZwpemdjT+sqwCz4Dz+0/WVkFco0v/04kIIqikVeLTY/7gEhmkw==}
+    engines: {node: '>=16'}
+    cpu: [x64]
+    os: [linux]
+
+  '@cloudflare/workerd-linux-arm64@1.20260918.1':
+    resolution: {integrity: sha512-4rib51MaLNWweUIUxM/Xj558M5QmyZoBSf0ffv+lYah5VTrvwnez3XGxX72pElnBKHROvAPOi5msQ5Ts8JSI0A==}
+    engines: {node: '>=16'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@cloudflare/workerd-windows-64@1.20260918.1':
+    resolution: {integrity: sha512-sATrMx5ShYYgmgUGrcTmvsFSJBFuN95NEkX3xwb1qk8w1A6h5N11sea7yN2IeibwPyPmXKjWNjXOno0hZAM71Q==}
+    engines: {node: '>=16'}
+    cpu: [x64]
+    os: [win32]
+
+  '@cloudflare/workers-types@5.20260919.1':
+    resolution: {integrity: sha512-xUdKJoTHhNcXwnBrfrM1STkzm3oSUc9cRVzP8fO5NyJZ/UtnDnWZHDk9z8IkTnbC2WRWFAS87HICmqZhbHDvQw==}
+
+  '@cspotcode/source-map-support@0.8.1':
+    resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
+    engines: {node: '>=12'}
+
+  '@drizzle-team/brocli@0.10.2':
+    resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
+
+  '@emnapi/runtime@1.11.3':
+    resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
+
+  '@esbuild-kit/core-utils@3.3.2':
+    resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==}
+    deprecated: 'Merged into tsx: https://tsx.hirok.io'
+
+  '@esbuild-kit/esm-loader@2.6.5':
+    resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==}
+    deprecated: 'Merged into tsx: https://tsx.hirok.io'
+
+  '@esbuild/aix-ppc64@0.25.12':
+    resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/aix-ppc64@0.28.1':
+    resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/aix-ppc64@0.28.2':
+    resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/android-arm64@0.18.20':
+    resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm64@0.25.12':
+    resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm64@0.28.1':
+    resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm64@0.28.2':
+    resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.18.20':
+    resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-arm@0.25.12':
+    resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-arm@0.28.1':
+    resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-arm@0.28.2':
+    resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.18.20':
+    resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/android-x64@0.25.12':
+    resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/android-x64@0.28.1':
+    resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/android-x64@0.28.2':
+    resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.18.20':
+    resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-arm64@0.25.12':
+    resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-arm64@0.28.1':
+    resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-arm64@0.28.2':
+    resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.18.20':
+    resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.25.12':
+    resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.28.1':
+    resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.28.2':
+    resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.18.20':
+    resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-arm64@0.25.12':
+    resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-arm64@0.28.1':
+    resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-arm64@0.28.2':
+    resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.18.20':
+    resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.25.12':
+    resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.28.1':
+    resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.28.2':
+    resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.18.20':
+    resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm64@0.25.12':
+    resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm64@0.28.1':
+    resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm64@0.28.2':
+    resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.18.20':
+    resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.25.12':
+    resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.28.1':
+    resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.28.2':
+    resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.18.20':
+    resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.25.12':
+    resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.28.1':
+    resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.28.2':
+    resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.18.20':
+    resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.25.12':
+    resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
+    engines: {node: '>=18'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.28.1':
+    resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
+    engines: {node: '>=18'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.28.2':
+    resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==}
+    engines: {node: '>=18'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.18.20':
+    resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.25.12':
+    resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
+    engines: {node: '>=18'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.28.1':
+    resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
+    engines: {node: '>=18'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.28.2':
+    resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==}
+    engines: {node: '>=18'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.18.20':
+    resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.25.12':
+    resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.28.1':
+    resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.28.2':
+    resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.18.20':
+    resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.25.12':
+    resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
+    engines: {node: '>=18'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.28.1':
+    resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
+    engines: {node: '>=18'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.28.2':
+    resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==}
+    engines: {node: '>=18'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.18.20':
+    resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.25.12':
+    resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
+    engines: {node: '>=18'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.28.1':
+    resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
+    engines: {node: '>=18'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.28.2':
+    resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==}
+    engines: {node: '>=18'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.18.20':
+    resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.25.12':
+    resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.28.1':
+    resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.28.2':
+    resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-arm64@0.25.12':
+    resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-arm64@0.28.1':
+    resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-arm64@0.28.2':
+    resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.18.20':
+    resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.25.12':
+    resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.28.1':
+    resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.28.2':
+    resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-arm64@0.25.12':
+    resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-arm64@0.28.1':
+    resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-arm64@0.28.2':
+    resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.18.20':
+    resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.25.12':
+    resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.28.1':
+    resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.28.2':
+    resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/openharmony-arm64@0.25.12':
+    resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openharmony]
+
+  '@esbuild/openharmony-arm64@0.28.1':
+    resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openharmony]
+
+  '@esbuild/openharmony-arm64@0.28.2':
+    resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openharmony]
+
+  '@esbuild/sunos-x64@0.18.20':
+    resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/sunos-x64@0.25.12':
+    resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/sunos-x64@0.28.1':
+    resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/sunos-x64@0.28.2':
+    resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.18.20':
+    resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-arm64@0.25.12':
+    resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-arm64@0.28.1':
+    resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-arm64@0.28.2':
+    resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.18.20':
+    resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.25.12':
+    resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.28.1':
+    resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.28.2':
+    resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.18.20':
+    resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.25.12':
+    resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.28.1':
+    resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.28.2':
+    resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [win32]
+
+  '@img/colour@1.1.0':
+    resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
+    engines: {node: '>=18'}
+
+  '@img/sharp-darwin-arm64@0.35.4':
+    resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==}
+    engines: {node: '>=20.9.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@img/sharp-darwin-x64@0.35.4':
+    resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==}
+    engines: {node: '>=20.9.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@img/sharp-freebsd-wasm32@0.35.4':
+    resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==}
+    engines: {node: '>=20.9.0'}
+    os: [freebsd]
+
+  '@img/sharp-libvips-darwin-arm64@1.3.3':
+    resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@img/sharp-libvips-darwin-x64@1.3.3':
+    resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@img/sharp-libvips-linux-arm64@1.3.3':
+    resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-arm@1.3.3':
+    resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==}
+    cpu: [arm]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-ppc64@1.3.3':
+    resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-riscv64@1.3.3':
+    resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-s390x@1.3.3':
+    resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@img/sharp-libvips-linux-x64@1.3.3':
+    resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-libvips-linuxmusl-arm64@1.3.3':
+    resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-libvips-linuxmusl-x64@1.3.3':
+    resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-linux-arm64@0.35.4':
+    resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==}
+    engines: {node: '>=20.9.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-linux-arm@0.35.4':
+    resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==}
+    engines: {node: '>=20.9.0'}
+    cpu: [arm]
+    os: [linux]
+
+  '@img/sharp-linux-ppc64@0.35.4':
+    resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==}
+    engines: {node: '>=20.9.0'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@img/sharp-linux-riscv64@0.35.4':
+    resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==}
+    engines: {node: '>=20.9.0'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@img/sharp-linux-s390x@0.35.4':
+    resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==}
+    engines: {node: '>=20.9.0'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@img/sharp-linux-x64@0.35.4':
+    resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==}
+    engines: {node: '>=20.9.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-linuxmusl-arm64@0.35.4':
+    resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==}
+    engines: {node: '>=20.9.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@img/sharp-linuxmusl-x64@0.35.4':
+    resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==}
+    engines: {node: '>=20.9.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@img/sharp-wasm32@0.35.4':
+    resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==}
+    engines: {node: '>=20.9.0'}
+
+  '@img/sharp-webcontainers-wasm32@0.35.4':
+    resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==}
+    engines: {node: '>=20.9.0'}
+    cpu: [wasm32]
+
+  '@img/sharp-win32-arm64@0.35.4':
+    resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==}
+    engines: {node: '>=20.9.0'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@img/sharp-win32-ia32@0.35.4':
+    resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==}
+    engines: {node: ^20.9.0}
+    cpu: [ia32]
+    os: [win32]
+
+  '@img/sharp-win32-x64@0.35.4':
+    resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==}
+    engines: {node: '>=20.9.0'}
+    cpu: [x64]
+    os: [win32]
+
+  '@jridgewell/resolve-uri@3.1.2':
+    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/sourcemap-codec@1.6.0':
+    resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
+
+  '@jridgewell/trace-mapping@0.3.9':
+    resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+
+  '@noble/ciphers@2.4.0':
+    resolution: {integrity: sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==}
+    engines: {node: '>= 20.19.0'}
+
+  '@noble/hashes@2.4.0':
+    resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==}
+    engines: {node: '>= 20.19.0'}
+
+  '@opentelemetry/semantic-conventions@1.43.0':
+    resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==}
+    engines: {node: '>=14'}
+
+  '@poppinss/colors@4.1.6':
+    resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==}
+
+  '@poppinss/dumper@0.6.5':
+    resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==}
+
+  '@poppinss/exception@1.2.3':
+    resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
+
+  '@sindresorhus/is@7.2.0':
+    resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==}
+    engines: {node: '>=18'}
+
+  '@speed-highlight/core@1.2.24':
+    resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==}
+
+  '@standard-schema/spec@1.1.0':
+    resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+
+  '@types/node@22.20.4':
+    resolution: {integrity: sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==}
+
+  '@types/trusted-types@2.0.7':
+    resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
+
+  better-auth-cloudflare@0.3.1:
+    resolution: {integrity: sha512-kvGYe1++fH4ODkb2o/WNkGWQtPYuWXjNPaKDAvPz8ChbaROW9TmZY0AIan9K52p+p+Pe53ZnQ7kKOWWZ2x0KrQ==}
+    peerDependencies:
+      '@better-auth/drizzle-adapter': ^1.5.0
+      '@cloudflare/workers-types': '>=4'
+      better-auth: ^1.5.0
+
+  better-auth@1.7.5:
+    resolution: {integrity: sha512-aKE0Zt2EPTpFvmq4/oATNyG/mAfc6JUqWkW9pzGlrVnzUb0lso7GJ9BPxD6JPhLqYV1a9zOAb0uAz1Q5fm+eHA==}
+    peerDependencies:
+      '@lynx-js/react': '*'
+      '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0
+      '@sveltejs/kit': ^2.0.0
+      '@tanstack/react-start': ^1.0.0
+      '@tanstack/solid-start': ^1.0.0
+      drizzle-kit: '>=0.31.4 || >=1.0.0-beta.1'
+      drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0
+      mongodb: ^6.0.0 || ^7.0.0
+      mysql2: ^3.0.0
+      next: ^14.0.0 || ^15.0.0 || ^16.0.0
+      pg: ^8.0.0
+      prisma: ^5.0.0 || ^6.0.0 || ^7.0.0
+      react: ^18.0.0 || ^19.0.0
+      react-dom: ^18.0.0 || ^19.0.0
+      solid-js: ^1.0.0
+      svelte: ^4.0.0 || ^5.0.0
+      vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0
+      vue: ^3.0.0
+    peerDependenciesMeta:
+      '@lynx-js/react':
+        optional: true
+      '@prisma/client':
+        optional: true
+      '@sveltejs/kit':
+        optional: true
+      '@tanstack/react-start':
+        optional: true
+      '@tanstack/solid-start':
+        optional: true
+      drizzle-kit:
+        optional: true
+      drizzle-orm:
+        optional: true
+      mongodb:
+        optional: true
+      mysql2:
+        optional: true
+      next:
+        optional: true
+      pg:
+        optional: true
+      prisma:
+        optional: true
+      react:
+        optional: true
+      react-dom:
+        optional: true
+      solid-js:
+        optional: true
+      svelte:
+        optional: true
+      vitest:
+        optional: true
+      vue:
+        optional: true
+
+  better-call@1.4.0:
+    resolution: {integrity: sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA==}
+    peerDependencies:
+      zod: ^4.0.0
+    peerDependenciesMeta:
+      zod:
+        optional: true
+
+  blake3-wasm@2.1.5:
+    resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
+
+  buffer-from@1.1.2:
+    resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+
+  cookie@1.1.1:
+    resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
+    engines: {node: '>=18'}
+
+  defu@6.1.5:
+    resolution: {integrity: sha512-pwdBJxJuJXmqrLO6s0VBmfbRz+G7FUzkjldAsdi9Yrv86mPyzq0ll1o8+8gB4Gsr6GJHbK1Lh3ngllgTInDCjA==}
+
+  detect-libc@2.1.2:
+    resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+    engines: {node: '>=8'}
+
+  drizzle-kit@0.31.10:
+    resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==}
+    hasBin: true
+
+  drizzle-orm@0.45.2:
+    resolution: {integrity: sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==}
+    peerDependencies:
+      '@aws-sdk/client-rds-data': '>=3'
+      '@cloudflare/workers-types': '>=4'
+      '@electric-sql/pglite': '>=0.2.0'
+      '@libsql/client': '>=0.10.0'
+      '@libsql/client-wasm': '>=0.10.0'
+      '@neondatabase/serverless': '>=0.10.0'
+      '@op-engineering/op-sqlite': '>=2'
+      '@opentelemetry/api': ^1.4.1
+      '@planetscale/database': '>=1.13'
+      '@prisma/client': '*'
+      '@tidbcloud/serverless': '*'
+      '@types/better-sqlite3': '*'
+      '@types/pg': '*'
+      '@types/sql.js': '*'
+      '@upstash/redis': '>=1.34.7'
+      '@vercel/postgres': '>=0.8.0'
+      '@xata.io/client': '*'
+      better-sqlite3: '>=7'
+      bun-types: '*'
+      expo-sqlite: '>=14.0.0'
+      gel: '>=2'
+      knex: '*'
+      kysely: '*'
+      mysql2: '>=2'
+      pg: '>=8'
+      postgres: '>=3'
+      prisma: '*'
+      sql.js: '>=1'
+      sqlite3: '>=5'
+    peerDependenciesMeta:
+      '@aws-sdk/client-rds-data':
+        optional: true
+      '@cloudflare/workers-types':
+        optional: true
+      '@electric-sql/pglite':
+        optional: true
+      '@libsql/client':
+        optional: true
+      '@libsql/client-wasm':
+        optional: true
+      '@neondatabase/serverless':
+        optional: true
+      '@op-engineering/op-sqlite':
+        optional: true
+      '@opentelemetry/api':
+        optional: true
+      '@planetscale/database':
+        optional: true
+      '@prisma/client':
+        optional: true
+      '@tidbcloud/serverless':
+        optional: true
+      '@types/better-sqlite3':
+        optional: true
+      '@types/pg':
+        optional: true
+      '@types/sql.js':
+        optional: true
+      '@upstash/redis':
+        optional: true
+      '@vercel/postgres':
+        optional: true
+      '@xata.io/client':
+        optional: true
+      better-sqlite3:
+        optional: true
+      bun-types:
+        optional: true
+      expo-sqlite:
+        optional: true
+      gel:
+        optional: true
+      knex:
+        optional: true
+      kysely:
+        optional: true
+      mysql2:
+        optional: true
+      pg:
+        optional: true
+      postgres:
+        optional: true
+      prisma:
+        optional: true
+      sql.js:
+        optional: true
+      sqlite3:
+        optional: true
+
+  error-stack-parser-es@1.0.5:
+    resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
+
+  esbuild@0.18.20:
+    resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  esbuild@0.25.12:
+    resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
+    engines: {node: '>=18'}
+    hasBin: true
+
+  esbuild@0.28.1:
+    resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
+    engines: {node: '>=18'}
+    hasBin: true
+
+  esbuild@0.28.2:
+    resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==}
+    engines: {node: '>=18'}
+    hasBin: true
+
+  fsevents@2.3.3:
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+
+  get-tsconfig@4.14.3:
+    resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==}
+
+  hono@4.13.8:
+    resolution: {integrity: sha512-/Gng7NfoykZl2pjukW5Z6+8Yxm3BPRf86GTbQnt0SbySkvax4fyL4H3HhY1cCpBGmiW9XDRFzRV+CXK2W8QudQ==}
+    engines: {node: '>=16.9.0'}
+
+  jose@6.2.12:
+    resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==}
+
+  kleur@4.1.5:
+    resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
+    engines: {node: '>=6'}
+
+  kysely@0.29.6:
+    resolution: {integrity: sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg==}
+    engines: {node: '>=22.0.0'}
+
+  lit-html@3.3.3:
+    resolution: {integrity: sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==}
+
+  mime@4.1.0:
+    resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==}
+    engines: {node: '>=16'}
+    hasBin: true
+
+  miniflare@5.20260918.0-alpha:
+    resolution: {integrity: sha512-vyIes7yW/OTzHtz4GhcBCTohZfqk2eQNiIkngZ07VRA5Qu24aNgW/TrFwlPkMLMjWDQ8R4JJBBHR/KX+liSDtg==}
+    engines: {node: '>=22.0.0'}
+
+  nanostores@1.5.3:
+    resolution: {integrity: sha512-rQLB6eV4f2AW/n3L0JmwCROpaisYy9EDEADvEFSd1C/qG8hB6O5TPlh9A791JRbJr4CnMQBzptDcvD9OR1+6WA==}
+    engines: {node: ^20.0.0 || >=22.0.0}
+
+  path-to-regexp@6.3.0:
+    resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
+
+  pathe@2.0.3:
+    resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+  resolve-pkg-maps@1.0.0:
+    resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+  rou3@0.9.2:
+    resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==}
+
+  semver@7.8.5:
+    resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  set-cookie-parser@3.1.2:
+    resolution: {integrity: sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==}
+
+  sharp@0.35.4:
+    resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==}
+    engines: {node: '>=20.9.0'}
+    peerDependencies:
+      '@types/node': '*'
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+
+  source-map-support@0.5.21:
+    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+
+  source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  supports-color@10.2.2:
+    resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
+    engines: {node: '>=18'}
+
+  tslib@2.8.1:
+    resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+  tsx@4.23.13:
+    resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==}
+    engines: {node: '>=18.0.0'}
+    hasBin: true
+
+  typescript@5.9.3:
+    resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  undici-types@6.21.0:
+    resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
+  undici@7.29.0:
+    resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==}
+    engines: {node: '>=20.18.1'}
+
+  unenv@2.0.0-rc.24:
+    resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
+
+  workerd@1.20260918.1:
+    resolution: {integrity: sha512-NsjfQlBNQ0iEniv/STOy4zbp8s5k60PzL1Ter02Eg44arbDhHtf6UOs03E31XDRmmBFxSIkAZuCyld3RKH1wqA==}
+    engines: {node: '>=16'}
+    hasBin: true
+
+  wrangler@4.135.0:
+    resolution: {integrity: sha512-WrNBQSfIG6YcILJcodYr5ty8vgkzGsV8YX+kfd+uZ5/Bd8cUW0GnUIRKAVfn5kYKqh1m/BPcji9h1d7mE8euFw==}
+    engines: {node: '>=22.0.0'}
+    hasBin: true
+    peerDependencies:
+      '@cloudflare/workers-types': ^5.20260918.1
+    peerDependenciesMeta:
+      '@cloudflare/workers-types':
+        optional: true
+
+  ws@8.21.0:
+    resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      bufferutil: ^4.0.1
+      utf-8-validate: '>=5.0.2'
+    peerDependenciesMeta:
+      bufferutil:
+        optional: true
+      utf-8-validate:
+        optional: true
+
+  youch-core@0.3.3:
+    resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
+
+  youch@4.1.0-beta.10:
+    resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
+
+  zod@4.6.5:
+    resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==}
+
+snapshots:
+
+  '@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)':
+    dependencies:
+      '@better-auth/utils': 0.4.2
+      '@better-fetch/fetch': 1.3.2
+      '@opentelemetry/semantic-conventions': 1.43.0
+      '@standard-schema/spec': 1.1.0
+      better-call: 1.4.0(zod@4.6.5)
+      jose: 6.2.12
+      kysely: 0.29.6
+      nanostores: 1.5.3
+      zod: 4.6.5
+
+  '@better-auth/drizzle-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6))':
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/utils': 0.4.2
+    optionalDependencies:
+      drizzle-orm: 0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)
+
+  '@better-auth/kysely-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(kysely@0.29.6)':
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/utils': 0.4.2
+    optionalDependencies:
+      kysely: 0.29.6
+
+  '@better-auth/memory-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)':
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/utils': 0.4.2
+
+  '@better-auth/mongo-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)':
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/utils': 0.4.2
+
+  '@better-auth/prisma-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)':
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/utils': 0.4.2
+
+  '@better-auth/telemetry@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)':
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/utils': 0.4.2
+      '@better-fetch/fetch': 1.3.2
+
+  '@better-auth/utils@0.4.2':
+    dependencies:
+      '@noble/hashes': 2.4.0
+
+  '@better-fetch/fetch@1.3.2': {}
+
+  '@cloudflare/kv-asset-handler@0.5.0': {}
+
+  '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260918.1)':
+    dependencies:
+      unenv: 2.0.0-rc.24
+    optionalDependencies:
+      workerd: 1.20260918.1
+
+  '@cloudflare/workerd-darwin-64@1.20260918.1':
+    optional: true
+
+  '@cloudflare/workerd-darwin-arm64@1.20260918.1':
+    optional: true
+
+  '@cloudflare/workerd-linux-64@1.20260918.1':
+    optional: true
+
+  '@cloudflare/workerd-linux-arm64@1.20260918.1':
+    optional: true
+
+  '@cloudflare/workerd-windows-64@1.20260918.1':
+    optional: true
+
+  '@cloudflare/workers-types@5.20260919.1': {}
+
+  '@cspotcode/source-map-support@0.8.1':
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.9
+
+  '@drizzle-team/brocli@0.10.2': {}
+
+  '@emnapi/runtime@1.11.3':
+    dependencies:
+      tslib: 2.8.1
+    optional: true
+
+  '@esbuild-kit/core-utils@3.3.2':
+    dependencies:
+      esbuild: 0.18.20
+      source-map-support: 0.5.21
+
+  '@esbuild-kit/esm-loader@2.6.5':
+    dependencies:
+      '@esbuild-kit/core-utils': 3.3.2
+      get-tsconfig: 4.14.3
+
+  '@esbuild/aix-ppc64@0.25.12':
+    optional: true
+
+  '@esbuild/aix-ppc64@0.28.1':
+    optional: true
+
+  '@esbuild/aix-ppc64@0.28.2':
+    optional: true
+
+  '@esbuild/android-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/android-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/android-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/android-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/android-arm@0.18.20':
+    optional: true
+
+  '@esbuild/android-arm@0.25.12':
+    optional: true
+
+  '@esbuild/android-arm@0.28.1':
+    optional: true
+
+  '@esbuild/android-arm@0.28.2':
+    optional: true
+
+  '@esbuild/android-x64@0.18.20':
+    optional: true
+
+  '@esbuild/android-x64@0.25.12':
+    optional: true
+
+  '@esbuild/android-x64@0.28.1':
+    optional: true
+
+  '@esbuild/android-x64@0.28.2':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/darwin-x64@0.18.20':
+    optional: true
+
+  '@esbuild/darwin-x64@0.25.12':
+    optional: true
+
+  '@esbuild/darwin-x64@0.28.1':
+    optional: true
+
+  '@esbuild/darwin-x64@0.28.2':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.25.12':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.28.1':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.28.2':
+    optional: true
+
+  '@esbuild/linux-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/linux-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/linux-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/linux-arm@0.18.20':
+    optional: true
+
+  '@esbuild/linux-arm@0.25.12':
+    optional: true
+
+  '@esbuild/linux-arm@0.28.1':
+    optional: true
+
+  '@esbuild/linux-arm@0.28.2':
+    optional: true
+
+  '@esbuild/linux-ia32@0.18.20':
+    optional: true
+
+  '@esbuild/linux-ia32@0.25.12':
+    optional: true
+
+  '@esbuild/linux-ia32@0.28.1':
+    optional: true
+
+  '@esbuild/linux-ia32@0.28.2':
+    optional: true
+
+  '@esbuild/linux-loong64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-loong64@0.25.12':
+    optional: true
+
+  '@esbuild/linux-loong64@0.28.1':
+    optional: true
+
+  '@esbuild/linux-loong64@0.28.2':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.18.20':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.25.12':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.28.1':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.28.2':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.25.12':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.28.1':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.28.2':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.25.12':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.28.1':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.28.2':
+    optional: true
+
+  '@esbuild/linux-s390x@0.18.20':
+    optional: true
+
+  '@esbuild/linux-s390x@0.25.12':
+    optional: true
+
+  '@esbuild/linux-s390x@0.28.1':
+    optional: true
+
+  '@esbuild/linux-s390x@0.28.2':
+    optional: true
+
+  '@esbuild/linux-x64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-x64@0.25.12':
+    optional: true
+
+  '@esbuild/linux-x64@0.28.1':
+    optional: true
+
+  '@esbuild/linux-x64@0.28.2':
+    optional: true
+
+  '@esbuild/netbsd-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/netbsd-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/netbsd-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.25.12':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.28.1':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.28.2':
+    optional: true
+
+  '@esbuild/openbsd-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/openbsd-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/openbsd-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.25.12':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.28.1':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.28.2':
+    optional: true
+
+  '@esbuild/openharmony-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/openharmony-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/openharmony-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/sunos-x64@0.18.20':
+    optional: true
+
+  '@esbuild/sunos-x64@0.25.12':
+    optional: true
+
+  '@esbuild/sunos-x64@0.28.1':
+    optional: true
+
+  '@esbuild/sunos-x64@0.28.2':
+    optional: true
+
+  '@esbuild/win32-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/win32-arm64@0.25.12':
+    optional: true
+
+  '@esbuild/win32-arm64@0.28.1':
+    optional: true
+
+  '@esbuild/win32-arm64@0.28.2':
+    optional: true
+
+  '@esbuild/win32-ia32@0.18.20':
+    optional: true
+
+  '@esbuild/win32-ia32@0.25.12':
+    optional: true
+
+  '@esbuild/win32-ia32@0.28.1':
+    optional: true
+
+  '@esbuild/win32-ia32@0.28.2':
+    optional: true
+
+  '@esbuild/win32-x64@0.18.20':
+    optional: true
+
+  '@esbuild/win32-x64@0.25.12':
+    optional: true
+
+  '@esbuild/win32-x64@0.28.1':
+    optional: true
+
+  '@esbuild/win32-x64@0.28.2':
+    optional: true
+
+  '@img/colour@1.1.0': {}
+
+  '@img/sharp-darwin-arm64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-darwin-arm64': 1.3.3
+    optional: true
+
+  '@img/sharp-darwin-x64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-darwin-x64': 1.3.3
+    optional: true
+
+  '@img/sharp-freebsd-wasm32@0.35.4':
+    dependencies:
+      '@img/sharp-wasm32': 0.35.4
+    optional: true
+
+  '@img/sharp-libvips-darwin-arm64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-darwin-x64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linux-arm64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linux-arm@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linux-ppc64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linux-riscv64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linux-s390x@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linux-x64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linuxmusl-arm64@1.3.3':
+    optional: true
+
+  '@img/sharp-libvips-linuxmusl-x64@1.3.3':
+    optional: true
+
+  '@img/sharp-linux-arm64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linux-arm64': 1.3.3
+    optional: true
+
+  '@img/sharp-linux-arm@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linux-arm': 1.3.3
+    optional: true
+
+  '@img/sharp-linux-ppc64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linux-ppc64': 1.3.3
+    optional: true
+
+  '@img/sharp-linux-riscv64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linux-riscv64': 1.3.3
+    optional: true
+
+  '@img/sharp-linux-s390x@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linux-s390x': 1.3.3
+    optional: true
+
+  '@img/sharp-linux-x64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linux-x64': 1.3.3
+    optional: true
+
+  '@img/sharp-linuxmusl-arm64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linuxmusl-arm64': 1.3.3
+    optional: true
+
+  '@img/sharp-linuxmusl-x64@0.35.4':
+    optionalDependencies:
+      '@img/sharp-libvips-linuxmusl-x64': 1.3.3
+    optional: true
+
+  '@img/sharp-wasm32@0.35.4':
+    dependencies:
+      '@emnapi/runtime': 1.11.3
+    optional: true
+
+  '@img/sharp-webcontainers-wasm32@0.35.4':
+    dependencies:
+      '@img/sharp-wasm32': 0.35.4
+    optional: true
+
+  '@img/sharp-win32-arm64@0.35.4':
+    optional: true
+
+  '@img/sharp-win32-ia32@0.35.4':
+    optional: true
+
+  '@img/sharp-win32-x64@0.35.4':
+    optional: true
+
+  '@jridgewell/resolve-uri@3.1.2': {}
+
+  '@jridgewell/sourcemap-codec@1.6.0': {}
+
+  '@jridgewell/trace-mapping@0.3.9':
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.2
+      '@jridgewell/sourcemap-codec': 1.6.0
+
+  '@noble/ciphers@2.4.0': {}
+
+  '@noble/hashes@2.4.0': {}
+
+  '@opentelemetry/semantic-conventions@1.43.0': {}
+
+  '@poppinss/colors@4.1.6':
+    dependencies:
+      kleur: 4.1.5
+
+  '@poppinss/dumper@0.6.5':
+    dependencies:
+      '@poppinss/colors': 4.1.6
+      '@sindresorhus/is': 7.2.0
+      supports-color: 10.2.2
+
+  '@poppinss/exception@1.2.3': {}
+
+  '@sindresorhus/is@7.2.0': {}
+
+  '@speed-highlight/core@1.2.24': {}
+
+  '@standard-schema/spec@1.1.0': {}
+
+  '@types/node@22.20.4':
+    dependencies:
+      undici-types: 6.21.0
+
+  '@types/trusted-types@2.0.7': {}
+
+  better-auth-cloudflare@0.3.1(@better-auth/drizzle-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)))(@cloudflare/workers-types@5.20260919.1)(better-auth@1.7.5(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)))(kysely@0.29.6):
+    dependencies:
+      '@better-auth/drizzle-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6))
+      '@cloudflare/workers-types': 5.20260919.1
+      better-auth: 1.7.5(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6))
+      drizzle-orm: 0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)
+      mime: 4.1.0
+      zod: 4.6.5
+    transitivePeerDependencies:
+      - '@aws-sdk/client-rds-data'
+      - '@electric-sql/pglite'
+      - '@libsql/client'
+      - '@libsql/client-wasm'
+      - '@neondatabase/serverless'
+      - '@op-engineering/op-sqlite'
+      - '@opentelemetry/api'
+      - '@planetscale/database'
+      - '@prisma/client'
+      - '@tidbcloud/serverless'
+      - '@types/better-sqlite3'
+      - '@types/pg'
+      - '@types/sql.js'
+      - '@upstash/redis'
+      - '@vercel/postgres'
+      - '@xata.io/client'
+      - better-sqlite3
+      - bun-types
+      - expo-sqlite
+      - gel
+      - knex
+      - kysely
+      - mysql2
+      - pg
+      - postgres
+      - prisma
+      - sql.js
+      - sqlite3
+
+  better-auth@1.7.5(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)):
+    dependencies:
+      '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)
+      '@better-auth/drizzle-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6))
+      '@better-auth/kysely-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(kysely@0.29.6)
+      '@better-auth/memory-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)
+      '@better-auth/mongo-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)
+      '@better-auth/prisma-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)
+      '@better-auth/telemetry': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)
+      '@better-auth/utils': 0.4.2
+      '@better-fetch/fetch': 1.3.2
+      '@noble/ciphers': 2.4.0
+      '@noble/hashes': 2.4.0
+      better-call: 1.4.0(zod@4.6.5)
+      defu: 6.1.5
+      jose: 6.2.12
+      kysely: 0.29.6
+      nanostores: 1.5.3
+      zod: 4.6.5
+    optionalDependencies:
+      drizzle-kit: 0.31.10
+      drizzle-orm: 0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6)
+    transitivePeerDependencies:
+      - '@opentelemetry/api'
+
+  better-call@1.4.0(zod@4.6.5):
+    dependencies:
+      '@better-auth/utils': 0.4.2
+      '@better-fetch/fetch': 1.3.2
+      rou3: 0.9.2
+      set-cookie-parser: 3.1.2
+    optionalDependencies:
+      zod: 4.6.5
+
+  blake3-wasm@2.1.5: {}
+
+  buffer-from@1.1.2: {}
+
+  cookie@1.1.1: {}
+
+  defu@6.1.5: {}
+
+  detect-libc@2.1.2: {}
+
+  drizzle-kit@0.31.10:
+    dependencies:
+      '@drizzle-team/brocli': 0.10.2
+      '@esbuild-kit/esm-loader': 2.6.5
+      esbuild: 0.25.12
+      tsx: 4.23.13
+
+  drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260919.1)(kysely@0.29.6):
+    optionalDependencies:
+      '@cloudflare/workers-types': 5.20260919.1
+      kysely: 0.29.6
+
+  error-stack-parser-es@1.0.5: {}
+
+  esbuild@0.18.20:
+    optionalDependencies:
+      '@esbuild/android-arm': 0.18.20
+      '@esbuild/android-arm64': 0.18.20
+      '@esbuild/android-x64': 0.18.20
+      '@esbuild/darwin-arm64': 0.18.20
+      '@esbuild/darwin-x64': 0.18.20
+      '@esbuild/freebsd-arm64': 0.18.20
+      '@esbuild/freebsd-x64': 0.18.20
+      '@esbuild/linux-arm': 0.18.20
+      '@esbuild/linux-arm64': 0.18.20
+      '@esbuild/linux-ia32': 0.18.20
+      '@esbuild/linux-loong64': 0.18.20
+      '@esbuild/linux-mips64el': 0.18.20
+      '@esbuild/linux-ppc64': 0.18.20
+      '@esbuild/linux-riscv64': 0.18.20
+      '@esbuild/linux-s390x': 0.18.20
+      '@esbuild/linux-x64': 0.18.20
+      '@esbuild/netbsd-x64': 0.18.20
+      '@esbuild/openbsd-x64': 0.18.20
+      '@esbuild/sunos-x64': 0.18.20
+      '@esbuild/win32-arm64': 0.18.20
+      '@esbuild/win32-ia32': 0.18.20
+      '@esbuild/win32-x64': 0.18.20
+
+  esbuild@0.25.12:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.25.12
+      '@esbuild/android-arm': 0.25.12
+      '@esbuild/android-arm64': 0.25.12
+      '@esbuild/android-x64': 0.25.12
+      '@esbuild/darwin-arm64': 0.25.12
+      '@esbuild/darwin-x64': 0.25.12
+      '@esbuild/freebsd-arm64': 0.25.12
+      '@esbuild/freebsd-x64': 0.25.12
+      '@esbuild/linux-arm': 0.25.12
+      '@esbuild/linux-arm64': 0.25.12
+      '@esbuild/linux-ia32': 0.25.12
+      '@esbuild/linux-loong64': 0.25.12
+      '@esbuild/linux-mips64el': 0.25.12
+      '@esbuild/linux-ppc64': 0.25.12
+      '@esbuild/linux-riscv64': 0.25.12
+      '@esbuild/linux-s390x': 0.25.12
+      '@esbuild/linux-x64': 0.25.12
+      '@esbuild/netbsd-arm64': 0.25.12
+      '@esbuild/netbsd-x64': 0.25.12
+      '@esbuild/openbsd-arm64': 0.25.12
+      '@esbuild/openbsd-x64': 0.25.12
+      '@esbuild/openharmony-arm64': 0.25.12
+      '@esbuild/sunos-x64': 0.25.12
+      '@esbuild/win32-arm64': 0.25.12
+      '@esbuild/win32-ia32': 0.25.12
+      '@esbuild/win32-x64': 0.25.12
+
+  esbuild@0.28.1:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.28.1
+      '@esbuild/android-arm': 0.28.1
+      '@esbuild/android-arm64': 0.28.1
+      '@esbuild/android-x64': 0.28.1
+      '@esbuild/darwin-arm64': 0.28.1
+      '@esbuild/darwin-x64': 0.28.1
+      '@esbuild/freebsd-arm64': 0.28.1
+      '@esbuild/freebsd-x64': 0.28.1
+      '@esbuild/linux-arm': 0.28.1
+      '@esbuild/linux-arm64': 0.28.1
+      '@esbuild/linux-ia32': 0.28.1
+      '@esbuild/linux-loong64': 0.28.1
+      '@esbuild/linux-mips64el': 0.28.1
+      '@esbuild/linux-ppc64': 0.28.1
+      '@esbuild/linux-riscv64': 0.28.1
+      '@esbuild/linux-s390x': 0.28.1
+      '@esbuild/linux-x64': 0.28.1
+      '@esbuild/netbsd-arm64': 0.28.1
+      '@esbuild/netbsd-x64': 0.28.1
+      '@esbuild/openbsd-arm64': 0.28.1
+      '@esbuild/openbsd-x64': 0.28.1
+      '@esbuild/openharmony-arm64': 0.28.1
+      '@esbuild/sunos-x64': 0.28.1
+      '@esbuild/win32-arm64': 0.28.1
+      '@esbuild/win32-ia32': 0.28.1
+      '@esbuild/win32-x64': 0.28.1
+
+  esbuild@0.28.2:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.28.2
+      '@esbuild/android-arm': 0.28.2
+      '@esbuild/android-arm64': 0.28.2
+      '@esbuild/android-x64': 0.28.2
+      '@esbuild/darwin-arm64': 0.28.2
+      '@esbuild/darwin-x64': 0.28.2
+      '@esbuild/freebsd-arm64': 0.28.2
+      '@esbuild/freebsd-x64': 0.28.2
+      '@esbuild/linux-arm': 0.28.2
+      '@esbuild/linux-arm64': 0.28.2
+      '@esbuild/linux-ia32': 0.28.2
+      '@esbuild/linux-loong64': 0.28.2
+      '@esbuild/linux-mips64el': 0.28.2
+      '@esbuild/linux-ppc64': 0.28.2
+      '@esbuild/linux-riscv64': 0.28.2
+      '@esbuild/linux-s390x': 0.28.2
+      '@esbuild/linux-x64': 0.28.2
+      '@esbuild/netbsd-arm64': 0.28.2
+      '@esbuild/netbsd-x64': 0.28.2
+      '@esbuild/openbsd-arm64': 0.28.2
+      '@esbuild/openbsd-x64': 0.28.2
+      '@esbuild/openharmony-arm64': 0.28.2
+      '@esbuild/sunos-x64': 0.28.2
+      '@esbuild/win32-arm64': 0.28.2
+      '@esbuild/win32-ia32': 0.28.2
+      '@esbuild/win32-x64': 0.28.2
+
+  fsevents@2.3.3:
+    optional: true
+
+  get-tsconfig@4.14.3:
+    dependencies:
+      resolve-pkg-maps: 1.0.0
+
+  hono@4.13.8: {}
+
+  jose@6.2.12: {}
+
+  kleur@4.1.5: {}
+
+  kysely@0.29.6: {}
+
+  lit-html@3.3.3:
+    dependencies:
+      '@types/trusted-types': 2.0.7
+
+  mime@4.1.0: {}
+
+  miniflare@5.20260918.0-alpha(@types/node@22.20.4):
+    dependencies:
+      '@cspotcode/source-map-support': 0.8.1
+      sharp: 0.35.4(@types/node@22.20.4)
+      undici: 7.29.0
+      workerd: 1.20260918.1
+      ws: 8.21.0
+      youch: 4.1.0-beta.10
+    transitivePeerDependencies:
+      - '@types/node'
+      - bufferutil
+      - utf-8-validate
+
+  nanostores@1.5.3: {}
+
+  path-to-regexp@6.3.0: {}
+
+  pathe@2.0.3: {}
+
+  resolve-pkg-maps@1.0.0: {}
+
+  rou3@0.9.2: {}
+
+  semver@7.8.5: {}
+
+  set-cookie-parser@3.1.2: {}
+
+  sharp@0.35.4(@types/node@22.20.4):
+    dependencies:
+      '@img/colour': 1.1.0
+      detect-libc: 2.1.2
+      semver: 7.8.5
+    optionalDependencies:
+      '@img/sharp-darwin-arm64': 0.35.4
+      '@img/sharp-darwin-x64': 0.35.4
+      '@img/sharp-freebsd-wasm32': 0.35.4
+      '@img/sharp-libvips-darwin-arm64': 1.3.3
+      '@img/sharp-libvips-darwin-x64': 1.3.3
+      '@img/sharp-libvips-linux-arm': 1.3.3
+      '@img/sharp-libvips-linux-arm64': 1.3.3
+      '@img/sharp-libvips-linux-ppc64': 1.3.3
+      '@img/sharp-libvips-linux-riscv64': 1.3.3
+      '@img/sharp-libvips-linux-s390x': 1.3.3
+      '@img/sharp-libvips-linux-x64': 1.3.3
+      '@img/sharp-libvips-linuxmusl-arm64': 1.3.3
+      '@img/sharp-libvips-linuxmusl-x64': 1.3.3
+      '@img/sharp-linux-arm': 0.35.4
+      '@img/sharp-linux-arm64': 0.35.4
+      '@img/sharp-linux-ppc64': 0.35.4
+      '@img/sharp-linux-riscv64': 0.35.4
+      '@img/sharp-linux-s390x': 0.35.4
+      '@img/sharp-linux-x64': 0.35.4
+      '@img/sharp-linuxmusl-arm64': 0.35.4
+      '@img/sharp-linuxmusl-x64': 0.35.4
+      '@img/sharp-webcontainers-wasm32': 0.35.4
+      '@img/sharp-win32-arm64': 0.35.4
+      '@img/sharp-win32-ia32': 0.35.4
+      '@img/sharp-win32-x64': 0.35.4
+      '@types/node': 22.20.4
+
+  source-map-support@0.5.21:
+    dependencies:
+      buffer-from: 1.1.2
+      source-map: 0.6.1
+
+  source-map@0.6.1: {}
+
+  supports-color@10.2.2: {}
+
+  tslib@2.8.1:
+    optional: true
+
+  tsx@4.23.13:
+    dependencies:
+      esbuild: 0.28.2
+    optionalDependencies:
+      fsevents: 2.3.3
+
+  typescript@5.9.3: {}
+
+  undici-types@6.21.0: {}
+
+  undici@7.29.0: {}
+
+  unenv@2.0.0-rc.24:
+    dependencies:
+      pathe: 2.0.3
+
+  workerd@1.20260918.1:
+    optionalDependencies:
+      '@cloudflare/workerd-darwin-64': 1.20260918.1
+      '@cloudflare/workerd-darwin-arm64': 1.20260918.1
+      '@cloudflare/workerd-linux-64': 1.20260918.1
+      '@cloudflare/workerd-linux-arm64': 1.20260918.1
+      '@cloudflare/workerd-windows-64': 1.20260918.1
+
+  wrangler@4.135.0(@cloudflare/workers-types@5.20260919.1)(@types/node@22.20.4):
+    dependencies:
+      '@cloudflare/kv-asset-handler': 0.5.0
+      '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260918.1)
+      blake3-wasm: 2.1.5
+      esbuild: 0.28.1
+      miniflare: 5.20260918.0-alpha(@types/node@22.20.4)
+      path-to-regexp: 6.3.0
+      unenv: 2.0.0-rc.24
+      workerd: 1.20260918.1
+    optionalDependencies:
+      '@cloudflare/workers-types': 5.20260919.1
+      fsevents: 2.3.3
+    transitivePeerDependencies:
+      - '@types/node'
+      - bufferutil
+      - utf-8-validate
+
+  ws@8.21.0: {}
+
+  youch-core@0.3.3:
+    dependencies:
+      '@poppinss/exception': 1.2.3
+      error-stack-parser-es: 1.0.5
+
+  youch@4.1.0-beta.10:
+    dependencies:
+      '@poppinss/colors': 4.1.6
+      '@poppinss/dumper': 0.6.5
+      '@speed-highlight/core': 1.2.24
+      cookie: 1.1.1
+      youch-core: 0.3.3
+
+  zod@4.6.5: {}

+ 5 - 0
public/_headers

@@ -0,0 +1,5 @@
+/*
+  Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'
+  Permissions-Policy: camera=(), microphone=(), geolocation=()
+  Referrer-Policy: no-referrer
+  X-Content-Type-Options: nosniff

+ 3 - 196
public/index.html

@@ -48,7 +48,6 @@
   .footer { position:fixed; left:0; right:0; bottom:0; padding:12px 16px calc(12px + env(safe-area-inset-bottom)); background:rgba(0,0,0,.35); backdrop-filter:blur(10px); }
   .footer .inner { max-width:480px; margin:0 auto; display:flex; gap:8px; }
   .lever { height:64px; font-size:20px; background:var(--gold); color:#111; border-radius:14px; }
-  /* reveal */
   #reveal { position:fixed; inset:0; background:#000; color:#fff; display:none; flex-direction:column; align-items:center; justify-content:center; padding:24px; text-align:center; z-index:9; }
   #reveal.on { display:flex; }
   #reveal .scan { position:absolute; inset:0; background:repeating-linear-gradient(0deg, rgba(255,255,255,.04) 0 1px, transparent 1px 3px); pointer-events:none; }
@@ -63,200 +62,8 @@
 </style>
 </head>
 <body>
-<div id="app"></div>
-<div id="reveal"><div class="scan"></div><div id="reveal-body"></div></div>
-<script>
-const $ = s => document.querySelector(s);
-const handId = location.pathname.startsWith('/h/') ? location.pathname.split('/')[2] : null;
-let me = null, state = null, ws = null, revealed = null;
-const MORE = 'more_options';
-
-async function api(path, body) {
-  const r = await fetch(path, { method: body ? 'POST' : 'GET', credentials:'include', headers:{'Content-Type':'application/json'}, body: body ? JSON.stringify(body) : undefined });
-  if (!r.ok) { const t = await r.text(); toast(t); throw new Error(t); }
-  return r.json();
-}
-function toast(t){ const d=document.createElement('div'); d.textContent=t; d.style.cssText='position:fixed;top:12px;left:50%;transform:translateX(-50%);background:#111;color:#fff;padding:8px 14px;border-radius:99px;font-size:13px;z-index:20'; document.body.appendChild(d); setTimeout(()=>d.remove(),1800); }
-
-async function session() {
-  const r = await fetch('/api/auth/get-session', { credentials:'include' });
-  const t = await r.text(); if (!t) return null;
-  const j = JSON.parse(t); return j && j.user ? { id:j.user.id, name:j.user.name } : null;
-}
-
-// ---------- screens ----------
-function render() {
-  if (!me) return renderJoin();
-  if (!handId) return renderCreate();
-  if (!state) return $('#app').innerHTML = '<p class="mute">Loading hand…</p>';
-  renderHand();
-}
-
-function renderJoin() {
-  document.body.className = '';
-  $('#app').innerHTML = `
-    <h1>Plan Maker 2000</h1>
-    <div class="card">
-      <p class="mute">Who are you at this table?</p>
-      <input id="name" placeholder="Your name" autocomplete="off">
-      <button onclick="joinAnon()">Jump in</button>
-      <details><summary class="mute">Sign in with phone (OTP)</summary>
-        <input id="phone" placeholder="+61…" inputmode="tel">
-        <button class="ghost" onclick="sendOtp()">Send code</button>
-        <input id="code" placeholder="6-digit code" inputmode="numeric" style="display:none">
-        <button class="ghost" id="verify" onclick="verifyOtp()" style="display:none">Verify</button>
-      </details>
-    </div>`;
-}
-async function joinAnon() {
-  const name = $('#name').value.trim() || 'anon';
-  let s = await session();
-  if (!s) { await fetch('/api/auth/sign-in/anonymous', { method:'POST', credentials:'include', headers:{'Content-Type':'application/json'}, body:'{}' }); }
-  await api('/api/me/name', { name });
-  me = await session(); boot();
-}
-async function sendOtp() {
-  await api('/api/auth/phone-number/send-otp', { phoneNumber: $('#phone').value.trim() });
-  $('#code').style.display = 'block'; $('#verify').style.display = 'block'; toast('Code sent (check wrangler console in dev)');
-}
-async function verifyOtp() {
-  await api('/api/auth/phone-number/verify', { phoneNumber: $('#phone').value.trim(), code: $('#code').value.trim() });
-  const name = $('#name').value.trim(); if (name) await api('/api/me/name', { name });
-  me = await session(); boot();
-}
-
-function renderCreate() {
-  document.body.className = '';
-  $('#app').innerHTML = `
-    <h1>New hand</h1>
-    <div class="card">
-      <input id="q" placeholder="Question (e.g. Friday dinner)">
-      <input class="o" placeholder="Option 1"><input class="o" placeholder="Option 2"><input class="o" placeholder="Option 3 (optional)"><input class="o" placeholder="Option 4 (optional)">
-      <input id="con" placeholder="Constraints, comma separated (optional)">
-      <button onclick="createHand()">Open the table</button>
-      <p class="mute">Screenshot intake comes later; type it for now.</p>
-    </div>`;
-}
-async function createHand() {
-  const options = [...document.querySelectorAll('.o')].map(i=>i.value.trim()).filter(Boolean);
-  const constraints = $('#con').value.split(',').map(s=>s.trim()).filter(Boolean);
-  const h = await api('/api/hands', { question: $('#q').value.trim(), options, constraints });
-  location.href = '/h/' + h.id;
-}
-
-function label(id){ return (state.round.options.find(o=>o.id===id)||{}).label || id; }
-function mine(){ return state.round.chips[me.id] || {}; }
-function spent(){ return Object.values(mine()).reduce((a,b)=>a+b,0); }
-function totals(){ const t={}; for (const c of Object.values(state.round.chips)) for (const [o,n] of Object.entries(c)) t[o]=(t[o]||0)+n; return t; }
-
-function renderHand() {
-  const r = state.round, odds = r.odds, live = new Set(state.live);
-  const spice = odds ? odds.spice : 0;
-  document.body.className = state.status==='open' ? (spice>=2 ? 'felt hot' : 'felt') : 'felt';
-  const meIn = state.members.find(m=>m.id===me.id);
-  const left = state.chipsPerMember - spent();
-  const vetoLeft = state.vetoesPerMember - (state.vetoesUsed[me.id]||0);
-  const t = totals();
-  const opts = r.options.map(o => {
-    const dead = !live.has(o.id);
-    const p = odds && odds.probabilities[o.id] != null ? odds.probabilities[o.id] : null;
-    const n = mine()[o.id]||0, others = (t[o.id]||0) - n;
-    return `<div class="opt ${dead?'dead':''} ${o.id===MORE?'more':''}">
-      <div style="flex:1">
-        <div class="label">${o.label}</div>
-        <div class="chips">${'<span class="chip"></span>'.repeat(n)}${'<span class="chip other"></span>'.repeat(Math.max(0,others))}</div>
-      </div>
-      ${state.status==='open' && !dead && meIn && !meIn.locked ? `<div class="stack"><button onclick="place('${o.id}',-1)">−</button><button onclick="place('${o.id}',1)">+</button></div>` : ''}
-      <div class="odds">${p==null?'—':Math.round(p*100)+'%'}</div>
-      ${state.status==='open' && !dead && o.id!==MORE && meIn && !meIn.locked && vetoLeft>0 ? `<button class="small ghost" style="color:#ff8fa3" onclick="veto('${o.id}')">veto</button>` : ''}
-      <div class="bar ${odds && odds.confidence<0.5?'wobble':''}" style="width:${p==null?0:Math.round(p*100)}%"></div>
-    </div>`;
-  }).join('');
-  const members = state.members.map(m=>`<span class="member ${m.locked?'locked':''}">${m.name}${m.locked?' ✓':''}${odds && odds.sandbagging[m.id]>0.6?' 🫥':''}</span>`).join('');
-  const jevLine = odds ? `Jev · ${Math.round(odds.confidence*100)}% sure · ${['mild','warm','hot','volcanic'][Math.round(odds.spice)]} · ${odds.contentious>0.7?'contentious ('+odds.about+')':'calm'} · ${odds.format} · ${odds.ms}ms` : 'Jev is waiting for chips';
-  let footer = '';
-  if (state.status==='open') footer = meIn && !meIn.locked
-    ? `<button class="ghost" onclick="act({op:'lock'})">Lock in (${left} left)</button><button class="lever" onclick="act({op:'pull'})">PULL</button>`
-    : `<button class="lever" onclick="act({op:'pull'})">PULL THE LEVER</button>`;
-  if (state.status==='posted') footer = `<button class="ghost" onclick="act({op:'again'})">Go again</button><button class="ghost" onclick="more()">More options</button><button onclick="act({op:'accept'})">Accept</button>`;
-  if (state.status==='accepted') footer = `<button onclick="location.href='/'">New hand</button>`;
-  $('#app').innerHTML = `
-    <div class="mute">Round ${r.n} · ${state.status}</div>
-    <h1>${state.question}</h1>
-    <div class="members">${members}</div>
-    ${!meIn ? `<button onclick="act({op:'join'})">Sit down as ${me.name}</button>` : ''}
-    <div class="bank">${'<span class="chip"></span>'.repeat(Math.max(0,left))}<span class="mute" style="margin-left:8px">${left} chips · ${vetoLeft} vetoes</span></div>
-    ${opts}
-    <div class="jev"><div class="face"></div><div>${jevLine}</div></div>
-    ${r.pull && state.status!=='open' ? `<div class="card"><b>${label(r.pull.winner)}</b> — ${Math.round(r.pull.odds[r.pull.winner]*100)}% at the pull<br><span class="mute">${r.pull.dealer}</span><br><button class="ghost small" onclick="playReveal(state.round.pull)">replay</button></div>` : ''}
-    ${state.rounds.length>1 ? `<div class="mute">Earlier: ${state.rounds.slice(0,-1).map(x=>x.pull?label(x.pull.winner):'?').join(' → ')}</div>` : ''}
-    <div class="footer"><div class="inner">${footer}</div></div>`;
-}
-
-async function act(body){ await api(`/api/hands/${handId}/act`, body); }
-async function place(o,n){ await act({op:'place', option:o, n}); }
-async function veto(o){ if (confirm('Veto '+label(o)+'? Everyone will see.')) await act({op:'veto', option:o}); }
-async function more(){ const l = prompt('Options agent not wired yet — type new options, comma separated'); if (!l) return; await act({op:'more', labels: l.split(',').map(s=>s.trim()).filter(Boolean)}); }
-
-// ---------- reveal: reels with the near-miss ----------
-function playReveal(pull) {
-  const el = $('#reveal'), body = $('#reveal-body');
-  el.classList.add('on'); document.body.classList.add('crt');
-  const seq = pull.order; // ..., runner-up, winner
-  const pw = pull.odds[pull.winner];
-  let i = 0;
-  body.innerHTML = `<div class="mute">The lever has spoken</div><div class="reel-frame"><div class="reel" id="reel">…</div></div>`;
-  const reel = $('#reel');
-  const step = () => {
-    if (i < seq.length) {
-      reel.textContent = label(seq[i]);
-      const isRunnerUp = seq[i]===pull.runnerUp && i===seq.length-2;
-      const delay = i===seq.length-1 ? 0 : isRunnerUp ? 900 : Math.max(120, 420 - i*60); // hang on the runner-up: the near-miss
-      if (isRunnerUp) reel.classList.add('shake');
-      i++; setTimeout(step, delay);
-    } else {
-      body.innerHTML = `${pw<0.3?'<div class="upset">UPSET</div>':''}<div class="mute">${state.question}</div><div class="winner">${label(pull.winner)}</div>
-        <div class="mute">${Math.round(pw*100)}% at the pull</div><div class="dealer">${pull.dealer}</div>
-        <div class="odds-list">${Object.entries(pull.odds).sort((a,b)=>b[1]-a[1]).map(([k,v])=>label(k)+' '+Math.round(v*100)+'%').join(' · ')}</div>
-        <button class="ghost" style="margin-top:20px;width:auto" onclick="closeReveal()">ok</button>`;
-      if (navigator.vibrate) navigator.vibrate([30,40,30,40,120]);
-    }
-  };
-  setTimeout(step, 600);
-}
-function closeReveal(){ $('#reveal').classList.remove('on'); document.body.classList.remove('crt'); render(); }
-
-// ---------- socket ----------
-function connect() {
-  const proto = location.protocol==='https:' ? 'wss' : 'ws';
-  ws = new WebSocket(`${proto}://${location.host}/api/hands/${handId}/ws`);
-  ws.onmessage = ev => {
-    if (ev.data==='pong') return;
-    const m = JSON.parse(ev.data);
-    if (m.type==='state') {
-      const prevPull = state && state.round && state.round.pull ? state.round.pull.at : null;
-      state = m.state;
-      const p = state.round.pull;
-      if (p && p.at !== prevPull && p.at !== revealed) { revealed = p.at; playReveal(p); return; }
-      render();
-    }
-    if (m.type==='odds') { if (state) { state.round.odds = m.odds; render(); } }
-    if (m.type==='error') toast(m.error.slice(0,120));
-  };
-  ws.onclose = () => setTimeout(connect, 1500);
-  setInterval(()=>{ try{ ws.send('ping'); }catch{} }, 25000);
-}
-
-async function boot() {
-  me = await session();
-  if (me && handId) {
-    state = await api(`/api/hands/${handId}`);
-    if (!state.members.find(m=>m.id===me.id)) await act({op:'join'});
-    if (!ws) connect();
-  }
-  render();
-}
-boot();
-</script>
+<main id="app"></main>
+<div id="reveal" role="dialog" aria-modal="true" aria-label="The lever result"><div class="scan"></div><div id="reveal-body"></div></div>
+<script type="module" src="/app.js"></script>
 </body>
 </html>

+ 29 - 21
scripts/drive.sh

@@ -1,39 +1,47 @@
-set -e
-B=localhost:8787
-j(){ curl -s -b "$1" -c "$1" -H 'Content-Type: application/json' "${@:2}"; }
+#!/usr/bin/env bash
+set -euo pipefail
+
+B=${BASE_URL:-http://localhost:8787}
+COOKIE_DIR=$(mktemp -d)
+trap 'rm -rf "$COOKIE_DIR"' EXIT
+TOM="$COOKIE_DIR/tom"
+SAM="$COOKIE_DIR/sam"
+PHONE="$COOKIE_DIR/phone"
+
+j(){ curl --silent --show-error --fail-with-body -b "$1" -c "$1" -H 'Content-Type: application/json' "${@:2}"; }
 # two members: anonymous sign-in, set names
-j /tmp/tom -X POST $B/api/auth/sign-in/anonymous -d '{}' >/dev/null; j /tmp/tom -X POST $B/api/me/name -d '{"name":"Tom"}' >/dev/null
-j /tmp/sam -X POST $B/api/auth/sign-in/anonymous -d '{}' >/dev/null; j /tmp/sam -X POST $B/api/me/name -d '{"name":"Sam"}' >/dev/null
+j "$TOM" -X POST "$B/api/auth/sign-in/anonymous" -d '{}' >/dev/null; j "$TOM" -X POST "$B/api/me/name" -d '{"name":"Tom"}' >/dev/null
+j "$SAM" -X POST "$B/api/auth/sign-in/anonymous" -d '{}' >/dev/null; j "$SAM" -X POST "$B/api/me/name" -d '{"name":"Sam"}' >/dev/null
 # phone OTP path smoke test
-j /tmp/phone -X POST $B/api/auth/phone-number/send-otp -d '{"phoneNumber":"+61400000000"}'; echo " <- send-otp"
-H=$(j /tmp/tom -X POST $B/api/hands -d '{"question":"Friday dinner","options":["Thai","Pizza","Ramen","Cook at home"],"constraints":["Sam is trying to spend less this month"]}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
+j "$PHONE" -X POST "$B/api/auth/phone-number/send-otp" -d '{"phoneNumber":"+61400000000"}'; echo " <- send-otp"
+H=$(j "$TOM" -X POST "$B/api/hands" -d '{"question":"Friday dinner","options":["Thai","Pizza","Ramen","Cook at home"],"constraints":["Sam is trying to spend less this month"]}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
 echo "hand $H"
-A(){ j $1 -X POST $B/api/hands/$H/act -d "$2" >/dev/null; }
-A /tmp/tom '{"op":"join"}'; A /tmp/sam '{"op":"join"}'
-A /tmp/tom '{"op":"place","option":"o1","n":6}'; A /tmp/tom '{"op":"place","option":"o3","n":4}'
-A /tmp/sam '{"op":"place","option":"o2","n":8}'; A /tmp/sam '{"op":"place","option":"o4","n":2}'
-A /tmp/tom '{"op":"veto","option":"o2"}'          # Tom vetoes pizza; Sam's 8 chips come back
+A(){ j "$1" -X POST "$B/api/hands/$H/act" -d "$2" >/dev/null; }
+A "$TOM" '{"op":"join"}'; A "$SAM" '{"op":"join"}'
+A "$TOM" '{"op":"place","option":"o1","n":6}'; A "$TOM" '{"op":"place","option":"o3","n":4}'
+A "$SAM" '{"op":"place","option":"o2","n":8}'; A "$SAM" '{"op":"place","option":"o4","n":2}'
+A "$TOM" '{"op":"veto","option":"o2"}'          # Tom vetoes pizza; Sam's 8 chips come back
 sleep 1.2
-curl -s $B/api/hands/$H | python3 -c '
+curl --silent --show-error --fail-with-body "$B/api/hands/$H" | python3 -c '
 import sys,json; s=json.load(sys.stdin); r=s["round"]
 print("members",[m["name"] for m in s["members"]],"live",s["live"],"vetoed",r["vetoed"])
 print("chips",r["chips"])
 o=r["odds"]; print("odds", {k:round(v,2) for k,v in o["probabilities"].items()}, "conf",round(o["confidence"],2),"spice",round(o["spice"],2),"format",o["format"],"about",o["about"], o["ms"],"ms")'
-A /tmp/sam '{"op":"place","option":"o4","n":8}'   # Sam goes all in on cooking
+A "$SAM" '{"op":"place","option":"o4","n":8}'   # Sam goes all in on cooking
 sleep 0.6
-A /tmp/tom '{"op":"lock"}'; A /tmp/sam '{"op":"lock"}'   # both locked -> lever pulls
+A "$TOM" '{"op":"lock"}'; A "$SAM" '{"op":"lock"}'   # both locked -> lever pulls
 sleep 1.5
-curl -s $B/api/hands/$H | python3 -c '
+curl --silent --show-error --fail-with-body "$B/api/hands/$H" | python3 -c '
 import sys,json; s=json.load(sys.stdin); r=s["round"]; p=r["pull"]
 lab=lambda i: next(o["label"] for o in r["options"] if o["id"]==i)
 print("status",s["status"]); print("odds at pull",{lab(k):round(v,2) for k,v in p["odds"].items()})
 print("WINNER",lab(p["winner"]),"| runner-up",lab(p["runnerUp"]),"| reel order",[lab(x) for x in p["order"]],"| seed",p["seed"])
 print("dealer:",p["dealer"])'
-A /tmp/tom '{"op":"again"}'; sleep 0.3
-A /tmp/tom '{"op":"place","option":"o1","n":10}'; A /tmp/sam '{"op":"place","option":"o1","n":10}'; sleep 1
-A /tmp/tom '{"op":"pull"}'; sleep 1.5
-A /tmp/tom '{"op":"accept"}'; A /tmp/sam '{"op":"accept"}'
-curl -s $B/api/hands/$H | python3 -c '
+A "$TOM" '{"op":"again"}'; sleep 0.3
+A "$TOM" '{"op":"place","option":"o1","n":10}'; A "$SAM" '{"op":"place","option":"o1","n":10}'; sleep 1
+A "$TOM" '{"op":"lock"}'; A "$SAM" '{"op":"lock"}'; sleep 1.5
+A "$TOM" '{"op":"accept"}'; A "$SAM" '{"op":"accept"}'
+curl --silent --show-error --fail-with-body "$B/api/hands/$H" | python3 -c '
 import sys,json; s=json.load(sys.stdin); r=s["round"]; p=r["pull"]
 lab=lambda i: next(o["label"] for o in r["options"] if o["id"]==i)
 print("round",r["n"],"status",s["status"],"winner",lab(p["winner"]),{lab(k):round(v,2) for k,v in p["odds"].items()},"format",r["odds"]["format"]); print("dealer:",p["dealer"])'

+ 45 - 9
src/auth/index.ts

@@ -9,24 +9,60 @@ import type { CloudflareBindings } from "../env";
 
 // Identity = phone number. OTP over SMS in prod; logged to the console in dev.
 // Anonymous stays enabled as the zero-friction path for loop prototyping.
-async function sendOTP(env: CloudflareBindings | undefined, phone: string, code: string) {
-    if (!env || env.OTP_MODE !== "twilio") {
+type TwilioConfig = {
+    accountSid: string;
+    authToken: string;
+    from: string;
+};
+
+function getTwilioConfig(env: CloudflareBindings): TwilioConfig | undefined {
+    const mode: string = env.OTP_MODE;
+    if (mode === "console") return undefined;
+    if (mode !== "twilio") throw new Error(`Unsupported OTP_MODE: ${mode}`);
+
+    const missing = [
+        ["TWILIO_ACCOUNT_SID", env.TWILIO_ACCOUNT_SID],
+        ["TWILIO_AUTH_TOKEN", env.TWILIO_AUTH_TOKEN],
+        ["TWILIO_FROM", env.TWILIO_FROM],
+    ].filter(([, value]) => !value?.trim());
+
+    if (missing.length > 0) {
+        throw new Error(`OTP_MODE=twilio requires ${missing.map(([name]) => name).join(", ")}`);
+    }
+
+    return {
+        accountSid: env.TWILIO_ACCOUNT_SID!.trim(),
+        authToken: env.TWILIO_AUTH_TOKEN!.trim(),
+        from: env.TWILIO_FROM!.trim(),
+    };
+}
+
+async function sendOTP(config: TwilioConfig | undefined, phone: string, code: string) {
+    if (!config) {
         console.log(`[OTP] ${phone} -> ${code}`);
         return;
     }
-    const body = new URLSearchParams({ To: phone, From: env.TWILIO_FROM!, Body: `Your Plan Maker code is ${code}` });
-    await fetch(`https://api.twilio.com/2010-04-01/Accounts/${env.TWILIO_ACCOUNT_SID}/Messages.json`, {
+
+    const body = new URLSearchParams({ To: phone, From: config.from, Body: `Your Plan Maker code is ${code}` });
+    const response = await fetch(`https://api.twilio.com/2010-04-01/Accounts/${config.accountSid}/Messages.json`, {
         method: "POST",
-        headers: { Authorization: "Basic " + btoa(`${env.TWILIO_ACCOUNT_SID}:${env.TWILIO_AUTH_TOKEN}`) },
+        headers: { Authorization: "Basic " + btoa(`${config.accountSid}:${config.authToken}`) },
         body,
     });
+
+    if (!response.ok) {
+        throw new Error(`Twilio rejected the OTP message (HTTP ${response.status})`);
+    }
 }
 
 function createAuth(env?: CloudflareBindings, cf?: IncomingRequestCfProperties, baseURL?: string) {
     const db = env ? drizzle(env.DATABASE, { schema }) : ({} as any);
+    const authBaseURL = new URL(env?.BETTER_AUTH_URL?.trim() || baseURL || "http://localhost:8787").origin;
+    const twilio = env ? getTwilioConfig(env) : undefined;
 
     return betterAuth({
-        baseURL,
+        baseURL: authBaseURL,
+        trustedOrigins: [authBaseURL],
         secret: env?.BETTER_AUTH_SECRET,
         ...withCloudflare(
             {
@@ -40,11 +76,11 @@ function createAuth(env?: CloudflareBindings, cf?: IncomingRequestCfProperties,
                 plugins: [
                     anonymous(),
                     phoneNumber({
-                        sendOTP: ({ phoneNumber, code }) => sendOTP(env, phoneNumber, code),
+                        sendOTP: ({ phoneNumber, code }) => sendOTP(twilio, phoneNumber, code),
                         otpLength: 6,
                         expiresIn: 300,
                         signUpOnVerification: {
-                            getTempEmail: phone => `${phone.replace(/\D/g, "")}@phone.pm2000.local`,
+                            getTempEmail: phone => `${phone.replace(/\D/g, "")}@phone.decision-maker-2000.local`,
                             getTempName: phone => phone,
                         },
                     }),
@@ -52,7 +88,7 @@ function createAuth(env?: CloudflareBindings, cf?: IncomingRequestCfProperties,
                 rateLimit: { enabled: true, window: 60, max: 100 },
             }
         ),
-        ...(env ? {} : { database: drizzleAdapter({} as any, { provider: "sqlite", usePlural: true }) }),
+        ...(env ? {} : { database: drizzleAdapter({} as any, { provider: "sqlite", schema, usePlural: true }) }),
     });
 }
 

+ 56 - 0
src/domain/hand-validation.ts

@@ -0,0 +1,56 @@
+export function normalizeText(value: unknown, maxLength: number): string | null {
+    if (typeof value !== "string") return null;
+    const text = value.trim().replace(/\s+/g, " ");
+    return text && text.length <= maxLength ? text : null;
+}
+
+export function normalizeUniqueTextList(value: unknown, maxItems: number, maxLength: number): string[] | null {
+    if (!Array.isArray(value) || value.length > maxItems) return null;
+    const items = value.map(item => normalizeText(item, maxLength));
+    if (items.some(item => item === null)) return null;
+    const result = items as string[];
+    return new Set(result.map(item => item.toLocaleLowerCase())).size === result.length ? result : null;
+}
+
+export function normalizeProbabilities(value: unknown, optionIds: string[]): Record<string, number> | null {
+    if (!value || typeof value !== "object" || Array.isArray(value)) return null;
+    const input = value as Record<string, unknown>;
+    const weights: Record<string, number> = {};
+    for (const id of optionIds) {
+        const weight = input[id];
+        if (typeof weight !== "number" || !Number.isFinite(weight) || weight < 0) return null;
+        weights[id] = weight;
+    }
+    const total = Object.values(weights).reduce((sum, weight) => sum + weight, 0);
+    if (!(total > 0)) return null;
+    for (const id of optionIds) weights[id] /= total;
+    return weights;
+}
+
+export function clampUnit(value: unknown, fallback = 0): number {
+    return typeof value === "number" && Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : fallback;
+}
+
+function mulberry32(seed: number) {
+    return () => {
+        seed |= 0;
+        seed = (seed + 0x6d2b79f5) | 0;
+        let value = Math.imul(seed ^ (seed >>> 15), 1 | seed);
+        value = (value + Math.imul(value ^ (value >>> 7), 61 | value)) ^ value;
+        return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
+    };
+}
+
+export function chooseWinner(optionIds: string[], weights: Record<string, number>, seed: number, confirmTop = false): string | null {
+    if (!optionIds.length) return null;
+    if (confirmTop) {
+        return optionIds.reduce((best, id) => (weights[id] > weights[best] ? id : best));
+    }
+    const total = optionIds.reduce((sum, id) => sum + weights[id], 0);
+    let draw = mulberry32(seed)() * total;
+    for (const id of optionIds) {
+        if (draw < weights[id]) return id;
+        draw -= weights[id];
+    }
+    return optionIds[optionIds.length - 1];
+}

+ 6 - 2
src/env.d.ts

@@ -1,7 +1,11 @@
-// Bindings come from worker-configuration.d.ts (run `npm run cf-typegen`). Secrets from .dev.vars / wrangler secret.
-export type CloudflareBindings = Env & {
+// Bindings come from worker-configuration.d.ts (run `pnpm cf-typegen`). Secrets from .dev.vars / wrangler secret.
+// Omit OTP_MODE because Wrangler narrows configured variables to their current
+// literal value, while this application supports a different local value.
+export type CloudflareBindings = Omit<Env, "OTP_MODE"> & {
+    OTP_MODE: "console" | "twilio";
     TYPESAFE_API_KEY: string;
     BETTER_AUTH_SECRET: string;
+    BETTER_AUTH_URL?: string;
     TWILIO_ACCOUNT_SID?: string;
     TWILIO_AUTH_TOKEN?: string;
     TWILIO_FROM?: string;

+ 115 - 54
src/hand.ts

@@ -3,6 +3,7 @@
 import { DurableObject } from "cloudflare:workers";
 import { jev, type Choice } from "./jev";
 import { DEALER_LINES } from "./dealer";
+import { chooseWinner, clampUnit, normalizeProbabilities, normalizeText, normalizeUniqueTextList } from "./domain/hand-validation";
 import type { CloudflareBindings } from "./env";
 
 export type Member = { id: string; name: string; locked: boolean };
@@ -55,21 +56,23 @@ export type HandState = {
 };
 
 const MORE = "more_options";
+const TERMINAL = new Set<HandState["status"]>(["accepted", "expired"]);
 
-function mulberry32(seed: number) {
-    return () => {
-        seed |= 0;
-        seed = (seed + 0x6d2b79f5) | 0;
-        let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
-        t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
-        return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
-    };
-}
+type Action = {
+    member: { id: string; name: string };
+    op: "join" | "place" | "veto" | "lock" | "pull" | "again" | "more" | "accept";
+    option?: string;
+    n?: number;
+    labels?: string[];
+};
 
 export class Hand extends DurableObject<CloudflareBindings> {
     private state: HandState | null = null;
     private oddsTimer: ReturnType<typeof setTimeout> | null = null;
     private oddsPending = false;
+    private oddsRevision = 0;
+    private oddsRequest = 0;
+    private pullInFlight: Promise<void> | null = null;
 
     private async load(): Promise<HandState | null> {
         if (!this.state) this.state = (await this.ctx.storage.get<HandState>("hand")) ?? null;
@@ -83,6 +86,9 @@ export class Hand extends DurableObject<CloudflareBindings> {
     async fetch(req: Request): Promise<Response> {
         const url = new URL(req.url);
         if (url.pathname.endsWith("/ws")) {
+            if (req.headers.get("Upgrade")?.toLowerCase() !== "websocket") {
+                return Response.json({ error: "WebSocket upgrade required" }, { status: 426, headers: { Upgrade: "websocket" } });
+            }
             const pair = new WebSocketPair();
             this.ctx.acceptWebSocket(pair[1]);
             const s = await this.load();
@@ -90,14 +96,28 @@ export class Hand extends DurableObject<CloudflareBindings> {
             return new Response(null, { status: 101, webSocket: pair[0] });
         }
         if (url.pathname.endsWith("/init") && req.method === "POST") {
-            const body = (await req.json()) as { id: string; question: string; options: string[]; constraints?: string[] };
+            if (await this.load()) return Response.json({ error: "hand already exists" }, { status: 409 });
+            let body: { id?: unknown; question?: unknown; options?: unknown; constraints?: unknown };
+            try {
+                body = (await req.json()) as typeof body;
+            } catch {
+                return Response.json({ error: "invalid JSON body" }, { status: 400 });
+            }
+            const id = normalizeText(body.id, 64);
+            const question = normalizeText(body.question, 280);
+            const options = normalizeUniqueTextList(body.options, 4, 100);
+            const constraints = body.constraints === undefined ? [] : normalizeUniqueTextList(body.constraints, 8, 200);
+            if (!id || !question || !options || options.length < 2) {
+                return Response.json({ error: "invalid hand" }, { status: 400 });
+            }
+            if (!constraints) return Response.json({ error: "invalid constraints" }, { status: 400 });
             this.state = {
-                id: body.id,
-                question: body.question,
+                id,
+                question,
                 status: "open",
                 members: [],
-                rounds: [this.newRound(1, body.options.map((label, i) => ({ id: `o${i + 1}`, label })))],
-                constraints: body.constraints ?? [],
+                rounds: [this.newRound(1, options.map((label, i) => ({ id: `o${i + 1}`, label })))],
+                constraints,
                 accepts: [],
                 chipsPerMember: 10,
                 vetoesPerMember: 2,
@@ -111,11 +131,16 @@ export class Hand extends DurableObject<CloudflareBindings> {
             return s ? Response.json(this.publicState(s)) : new Response("not found", { status: 404 });
         }
         if (url.pathname.endsWith("/act") && req.method === "POST") {
-            const body = (await req.json()) as { member: { id: string; name: string }; op: string; option?: string; n?: number };
+            let body: Action;
+            try {
+                body = (await req.json()) as Action;
+            } catch {
+                return Response.json({ error: "invalid JSON body" }, { status: 400 });
+            }
             const s = await this.load();
             if (!s) return new Response("not found", { status: 404 });
             const err = await this.act(s, body);
-            if (err) return new Response(err, { status: 400 });
+            if (err) return Response.json({ error: err }, { status: 400 });
             return Response.json(this.publicState(s));
         }
         return new Response("no", { status: 404 });
@@ -140,31 +165,40 @@ export class Hand extends DurableObject<CloudflareBindings> {
     }
 
     // ---- actions ----
-    private async act(s: HandState, a: { member: { id: string; name: string }; op: string; option?: string; n?: number }): Promise<string | null> {
+    private async act(s: HandState, a: Action): Promise<string | null> {
+        const memberId = normalizeText(a?.member?.id, 128);
+        const memberName = normalizeText(a?.member?.name, 50);
+        if (!memberId || !memberName) return "invalid member";
+        if (TERMINAL.has(s.status)) return "hand is closed";
         const r = this.round(s);
-        const m = s.members.find(x => x.id === a.member.id);
+        const m = s.members.find(x => x.id === memberId);
+        if (a.op !== "join" && !m) return "join first";
         switch (a.op) {
             case "join": {
-                if (!m) s.members.push({ id: a.member.id, name: a.member.name, locked: false });
-                else m.name = a.member.name;
+                if (s.status !== "open" && s.status !== "posted") return "can't join now";
+                if (this.pullInFlight) return "the lever is already turning";
+                if (!m) s.members.push({ id: memberId, name: memberName, locked: false });
+                else m.name = memberName;
+                if (s.status === "open") this.scheduleOdds(true);
                 break;
             }
             case "place": {
                 if (!m || s.status !== "open" || m.locked) return "can't place";
                 const opt = this.liveOptions(r).find(o => o.id === a.option);
                 if (!opt) return "no such option";
-                const n = a.n ?? 1;
+                const n = a.n;
+                if (typeof n !== "number" || !Number.isInteger(n) || n === 0 || Math.abs(n) > s.chipsPerMember) return "invalid chip change";
                 const mine = (r.chips[m.id] ??= {});
                 const cur = mine[opt.id] ?? 0;
                 if (n > 0 && this.spent(r, m.id) + n > s.chipsPerMember) return "no chips left";
                 if (cur + n < 0) return "none there";
                 mine[opt.id] = cur + n;
                 if (mine[opt.id] === 0) delete mine[opt.id];
-                this.scheduleOdds();
+                this.scheduleOdds(true);
                 break;
             }
             case "veto": {
-                if (!m || s.status !== "open") return "can't veto";
+                if (!m || s.status !== "open" || m.locked) return "can't veto";
                 if (a.option === MORE) return "can't veto that";
                 if (this.vetoesUsed(s, m.id) >= s.vetoesPerMember) return "no vetoes left";
                 const live = this.liveOptions(r).filter(o => o.id !== MORE);
@@ -172,18 +206,19 @@ export class Hand extends DurableObject<CloudflareBindings> {
                 if (!live.find(o => o.id === a.option)) return "no such option";
                 r.vetoed.push({ by: m.id, option: a.option! });
                 for (const c of Object.values(r.chips)) delete c[a.option!]; // chips on it return to their owners
-                this.scheduleOdds();
+                this.scheduleOdds(true);
                 break;
             }
             case "lock": {
                 if (!m || s.status !== "open") return "can't lock";
                 m.locked = true;
-                if (s.members.every(x => x.locked)) await this.pull(s);
+                if (s.members.length > 0 && s.members.every(x => x.locked)) await this.ensurePull(s);
                 break;
             }
             case "pull": {
                 if (s.status !== "open") return "not open";
-                await this.pull(s);
+                if (!s.members.length || !s.members.every(member => member.locked)) return "everyone must lock first";
+                await this.ensurePull(s);
                 break;
             }
             case "again": {
@@ -193,21 +228,23 @@ export class Hand extends DurableObject<CloudflareBindings> {
                 s.members.forEach(x => (x.locked = false));
                 s.accepts = [];
                 s.status = "open";
-                this.scheduleOdds();
+                this.scheduleOdds(true);
                 break;
             }
             case "more": {
                 // Options agent hook: for now the client supplies new labels. Later: vision/LLM regen.
                 if (s.status !== "posted") return "nothing posted";
                 if (s.rounds.length >= 3) return "regen cap";
-                const labels = ((a as any).labels as string[] | undefined) ?? [];
+                const labels = a.labels ?? [];
+                const normalizedLabels = normalizeUniqueTextList(labels, 4, 100);
+                if (!normalizedLabels?.length) return "invalid labels";
                 const live = this.liveOptions(r).filter(o => o.id !== MORE);
-                const fresh = labels.map((label, i) => ({ id: `o${r.n + 1}_${i + 1}`, label }));
+                const fresh = normalizedLabels.map((label, i) => ({ id: `o${r.n + 1}_${i + 1}`, label }));
                 s.rounds.push(this.newRound(r.n + 1, [...live, ...fresh].slice(0, 4)));
                 s.members.forEach(x => (x.locked = false));
                 s.accepts = [];
                 s.status = "open";
-                this.scheduleOdds();
+                this.scheduleOdds(true);
                 break;
             }
             case "accept": {
@@ -225,7 +262,12 @@ export class Hand extends DurableObject<CloudflareBindings> {
     }
 
     // ---- Jev odds, debounced 200 ms ----
-    private scheduleOdds() {
+    private scheduleOdds(invalidate = false) {
+        if (invalidate) {
+            this.oddsRevision++;
+            const s = this.state;
+            if (s?.status === "open") this.round(s).odds = null;
+        }
         this.oddsPending = true;
         if (this.oddsTimer) return;
         this.oddsTimer = setTimeout(() => {
@@ -251,6 +293,8 @@ export class Hand extends DurableObject<CloudflareBindings> {
         const s = await this.load();
         if (!s || s.status !== "open") return;
         const r = this.round(s);
+        const revision = this.oddsRevision;
+        const request = ++this.oddsRequest;
         const f = this.features(s, r);
         const nameOf = (id: string) => s.members.find(m => m.id === id)?.name ?? id;
         const chipsByName: Record<string, Record<string, number>> = {};
@@ -267,7 +311,7 @@ export class Hand extends DurableObject<CloudflareBindings> {
             constraints: s.constraints,
             previous_rounds: s.rounds.slice(0, -1).map(pr => ({
                 n: pr.n,
-                posted: pr.pull ? r.options.find(x => x.id === pr.pull!.winner)?.label ?? pr.pull.winner : null,
+                posted: pr.pull ? pr.options.find(x => x.id === pr.pull!.winner)?.label ?? pr.pull.winner : null,
             })),
             live_option_count: f.liveCount,
             chip_agreement: f.agreement,
@@ -305,33 +349,58 @@ export class Hand extends DurableObject<CloudflareBindings> {
                 },
                 ...sandbag,
             } as any);
+            if (request !== this.oddsRequest || revision !== this.oddsRevision || s.status !== "open" || this.round(s) !== r) return;
             const a: any = res.answers;
+            const probabilities = normalizeProbabilities(a?.pick?.probabilities, f.live.map(option => option.id));
+            if (!probabilities) throw new Error("Jev returned invalid probabilities");
             const sandbagging: Record<string, number> = {};
-            for (const m of s.members) sandbagging[m.id] = a[`sb_${m.id}`]?.noul ?? 0;
+            for (const m of s.members) sandbagging[m.id] = clampUnit(a?.[`sb_${m.id}`]?.noul);
             r.odds = {
-                probabilities: a.pick.probabilities,
-                confidence: a.pick.confidence,
-                contentious: a.contentious.noul,
-                about: a.about.choice,
-                spice: a.spice.score,
-                format: a.format.choice,
+                probabilities,
+                confidence: clampUnit(a?.pick?.confidence),
+                contentious: clampUnit(a?.contentious?.noul),
+                about: normalizeText(a?.about?.choice, 40) ?? "none",
+                spice: typeof a?.spice?.score === "number" && Number.isFinite(a.spice.score) ? Math.min(3, Math.max(0, Math.round(a.spice.score))) : 0,
+                format: normalizeText(a?.format?.choice, 40) ?? "craps",
                 sandbagging,
-                ms: res.ms,
+                ms: typeof res.ms === "number" && Number.isFinite(res.ms) ? Math.max(0, res.ms) : 0,
                 at: Date.now(),
             };
             await this.save();
             this.broadcast({ type: "odds", odds: r.odds });
         } catch (e) {
+            if (request !== this.oddsRequest || revision !== this.oddsRevision || s.status !== "open" || this.round(s) !== r) return;
             this.broadcast({ type: "error", error: String(e) });
         }
     }
 
     // ---- the lever ----
+    private async ensurePull(s: HandState) {
+        if (this.pullInFlight) return this.pullInFlight;
+        const pull = this.pull(s);
+        this.pullInFlight = pull;
+        try {
+            await pull;
+        } finally {
+            if (this.pullInFlight === pull) this.pullInFlight = null;
+        }
+    }
+
+    private async refreshOdds() {
+        if (this.oddsTimer) {
+            clearTimeout(this.oddsTimer);
+            this.oddsTimer = null;
+        }
+        this.oddsPending = false;
+        await this.recomputeOdds();
+    }
+
     private async pull(s: HandState) {
         const r = this.round(s);
-        if (!r.odds || Date.now() - r.odds.at > 5000 || this.oddsPending) await this.recomputeOdds();
-        const p = r.odds?.probabilities;
+        if (!r.odds || Date.now() - r.odds.at > 5000 || this.oddsPending) await this.refreshOdds();
+        if (s.status !== "open" || this.round(s) !== r || !s.members.length || !s.members.every(member => member.locked)) return;
         const live = this.liveOptions(r);
+        const p = normalizeProbabilities(r.odds?.probabilities, live.map(option => option.id));
         // Fallback to chip proportions if Jev is unavailable
         const weights: Record<string, number> = {};
         if (p) for (const o of live) weights[o.id] = p[o.id] ?? 0;
@@ -340,24 +409,16 @@ export class Hand extends DurableObject<CloudflareBindings> {
             for (const o of live) weights[o.id] = (f.totals[o.id] ?? 0) + 0.01;
         }
         const total = Object.values(weights).reduce((a, b) => a + b, 0) || 1;
-        const seed = (Math.random() * 2 ** 32) >>> 0;
-        const rand = mulberry32(seed);
-        let u = rand() * total;
-        let winner = live[0].id;
-        for (const o of live) {
-            u -= weights[o.id];
-            if (u <= 0) {
-                winner = o.id;
-                break;
-            }
-        }
+        const seed = crypto.getRandomValues(new Uint32Array(1))[0];
+        const drawOptions = r.odds?.format === "one_tap" ? live.filter(option => option.id !== MORE) : live;
+        const winner = chooseWinner(drawOptions.map(option => option.id), weights, seed, r.odds?.format === "one_tap") ?? live[0].id;
         const ranked = [...live].sort((a, b) => weights[b.id] - weights[a.id]).map(o => o.id);
         const runnerUp = ranked.find(id => id !== winner) ?? winner;
         const rest = ranked.filter(id => id !== winner && id !== runnerUp);
         const order = [...rest, runnerUp, winner]; // near-miss: runner-up is always the last card before the winner
         const dealer = await this.dealerLine(s, r, winner, weights, total);
         r.pull = { seed, odds: Object.fromEntries(Object.entries(weights).map(([k, v]) => [k, v / total])), winner, runnerUp, order, dealer, at: Date.now() };
-        s.status = winner === MORE ? "posted" : "posted";
+        s.status = "posted";
         await this.save();
     }
 

+ 66 - 13
src/index.ts

@@ -1,17 +1,42 @@
 import { Hono } from "hono";
 import { createAuth } from "./auth";
+import { normalizeText, normalizeUniqueTextList } from "./domain/hand-validation";
 import type { CloudflareBindings } from "./env";
 export { Hand } from "./hand";
 
 type Variables = { auth: ReturnType<typeof createAuth>; me: { id: string; name: string } | null };
 const app = new Hono<{ Bindings: CloudflareBindings; Variables: Variables }>();
 
+const LIMITS = { name: 50, question: 280, option: 100, constraint: 200, constraints: 8 } as const;
+const HAND_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
+const SECURITY_HEADERS = {
+    "Content-Security-Policy": "default-src 'self'; script-src 'self'; connect-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'",
+    "Permissions-Policy": "camera=(), microphone=(), geolocation=()",
+    "Referrer-Policy": "no-referrer",
+    "X-Content-Type-Options": "nosniff",
+} as const;
+
+async function jsonBody(c: any): Promise<Record<string, unknown> | null> {
+    try {
+        const value = await c.req.json();
+        return value && typeof value === "object" && !Array.isArray(value) ? value : null;
+    } catch {
+        return null;
+    }
+}
+
+function handStub(c: any) {
+    const id = c.req.param("id");
+    return HAND_ID.test(id) ? c.env.HAND.get(c.env.HAND.idFromName(id)) : null;
+}
+
 app.use("*", async (c, next) => {
     const auth = createAuth(c.env, (c.req.raw as any).cf || {}, new URL(c.req.url).origin);
     c.set("auth", auth);
     const session = await auth.api.getSession({ headers: c.req.raw.headers }).catch(() => null);
     c.set("me", session ? { id: session.user.id, name: session.user.name || "anon" } : null);
     await next();
+    for (const [name, value] of Object.entries(SECURITY_HEADERS)) c.header(name, value);
 });
 
 app.all("/api/auth/*", c => c.get("auth").handler(c.req.raw));
@@ -19,8 +44,10 @@ app.all("/api/auth/*", c => c.get("auth").handler(c.req.raw));
 // Name is per-table display name; stored on the user for now.
 app.post("/api/me/name", async c => {
     const me = c.get("me");
-    if (!me) return c.text("sign in first", 401);
-    const { name } = (await c.req.json()) as { name: string };
+    if (!me) return c.json({ error: "sign in first" }, 401);
+    const body = await jsonBody(c);
+    const name = normalizeText(body?.name, LIMITS.name);
+    if (!name) return c.json({ error: `name must be 1–${LIMITS.name} characters` }, 400);
     await c.get("auth").api.updateUser({ headers: c.req.raw.headers, body: { name } });
     return c.json({ ok: true });
 });
@@ -28,30 +55,56 @@ app.post("/api/me/name", async c => {
 // Create a hand (draft -> open in one step for the prototype)
 app.post("/api/hands", async c => {
     const me = c.get("me");
-    if (!me) return c.text("sign in first", 401);
-    const body = (await c.req.json()) as { question: string; options: string[]; constraints?: string[] };
-    if (!body.question || !body.options || body.options.length < 2 || body.options.length > 4) return c.text("2–4 options", 400);
-    const id = crypto.randomUUID().slice(0, 8);
+    if (!me) return c.json({ error: "sign in first" }, 401);
+    const body = await jsonBody(c);
+    if (!body) return c.json({ error: "invalid JSON body" }, 400);
+    const question = normalizeText(body.question, LIMITS.question);
+    const options = normalizeUniqueTextList(body.options, 4, LIMITS.option);
+    const constraints = body.constraints === undefined ? [] : normalizeUniqueTextList(body.constraints, LIMITS.constraints, LIMITS.constraint);
+    if (!question) return c.json({ error: `question must be 1–${LIMITS.question} characters` }, 400);
+    if (!options || options.length < 2) return c.json({ error: "options must contain 2–4 unique labels" }, 400);
+    if (!constraints) return c.json({ error: `constraints must contain at most ${LIMITS.constraints} unique labels` }, 400);
+    const id = crypto.randomUUID();
     const stub = c.env.HAND.get(c.env.HAND.idFromName(id));
-    const res = await stub.fetch("https://hand/init", { method: "POST", body: JSON.stringify({ id, ...body }) });
-    return c.json(await res.json());
+    return stub.fetch("https://hand/init", { method: "POST", body: JSON.stringify({ id, question, options, constraints }) });
 });
 
 app.get("/api/hands/:id", async c => {
-    const stub = c.env.HAND.get(c.env.HAND.idFromName(c.req.param("id")));
+    const stub = handStub(c);
+    if (!stub) return c.json({ error: "invalid hand id" }, 400);
     return stub.fetch("https://hand/state");
 });
 
 app.post("/api/hands/:id/act", async c => {
     const me = c.get("me");
-    if (!me) return c.text("sign in first", 401);
-    const body = await c.req.json();
-    const stub = c.env.HAND.get(c.env.HAND.idFromName(c.req.param("id")));
+    if (!me) return c.json({ error: "sign in first" }, 401);
+    const body = await jsonBody(c);
+    if (!body) return c.json({ error: "invalid JSON body" }, 400);
+    if (typeof body.op !== "string" || !["join", "place", "veto", "lock", "pull", "again", "more", "accept"].includes(body.op)) {
+        return c.json({ error: "unknown operation" }, 400);
+    }
+    if ((body.op === "place" || body.op === "veto") && (typeof body.option !== "string" || body.option.length > 64)) {
+        return c.json({ error: "invalid option" }, 400);
+    }
+    if (body.op === "place" && (!Number.isInteger(body.n) || (body.n as number) === 0 || Math.abs(body.n as number) > 10)) {
+        return c.json({ error: "chip change must be a non-zero integer from -10 to 10" }, 400);
+    }
+    if (body.op === "more") {
+        const labels = normalizeUniqueTextList(body.labels, 4, LIMITS.option);
+        if (!labels?.length) return c.json({ error: "labels must contain 1–4 unique options" }, 400);
+        body.labels = labels;
+    }
+    const stub = handStub(c);
+    if (!stub) return c.json({ error: "invalid hand id" }, 400);
     return stub.fetch("https://hand/act", { method: "POST", body: JSON.stringify({ ...body, member: me }) });
 });
 
 app.get("/api/hands/:id/ws", async c => {
-    const stub = c.env.HAND.get(c.env.HAND.idFromName(c.req.param("id")));
+    if (c.req.header("Upgrade")?.toLowerCase() !== "websocket") {
+        return c.json({ error: "WebSocket upgrade required" }, 426, { Upgrade: "websocket" });
+    }
+    const stub = handStub(c);
+    if (!stub) return c.json({ error: "invalid hand id" }, 400);
     return stub.fetch("https://hand/ws", { headers: c.req.raw.headers });
 });
 

+ 44 - 0
tests/hand-validation.test.ts

@@ -0,0 +1,44 @@
+import assert from "node:assert/strict";
+import test from "node:test";
+import { chooseWinner, clampUnit, normalizeProbabilities, normalizeText, normalizeUniqueTextList } from "../src/domain/hand-validation.ts";
+
+test("normalizeText trims and collapses whitespace", () => {
+    assert.equal(normalizeText("  Friday\n  dinner  ", 20), "Friday dinner");
+    assert.equal(normalizeText("   ", 20), null);
+    assert.equal(normalizeText("too long", 3), null);
+});
+
+test("normalizeUniqueTextList rejects duplicates and invalid bounds", () => {
+    assert.deepEqual(normalizeUniqueTextList([" Thai ", "Pizza"], 4, 20), ["Thai", "Pizza"]);
+    assert.equal(normalizeUniqueTextList(["Thai", "thai"], 4, 20), null);
+    assert.equal(normalizeUniqueTextList(["a", "b", "c"], 2, 20), null);
+    assert.equal(normalizeUniqueTextList(["valid", 2], 4, 20), null);
+});
+
+test("normalizeProbabilities accepts weights and normalizes only live options", () => {
+    assert.deepEqual(normalizeProbabilities({ a: 20, b: 30, stale: 50 }, ["a", "b"]), { a: 0.4, b: 0.6 });
+});
+
+test("normalizeProbabilities rejects malformed or unusable weights", () => {
+    assert.equal(normalizeProbabilities({ a: 1, b: -1 }, ["a", "b"]), null);
+    assert.equal(normalizeProbabilities({ a: 0, b: 0 }, ["a", "b"]), null);
+    assert.equal(normalizeProbabilities({ a: 1 }, ["a", "b"]), null);
+    assert.equal(normalizeProbabilities({ a: Number.NaN, b: 1 }, ["a", "b"]), null);
+});
+
+test("clampUnit makes Jev scalar metadata safe", () => {
+    assert.equal(clampUnit(-1), 0);
+    assert.equal(clampUnit(0.45), 0.45);
+    assert.equal(clampUnit(3), 1);
+    assert.equal(clampUnit("0.5"), 0);
+});
+
+test("one-tap winner confirms the highest weight with option-order tie breaking", () => {
+    assert.equal(chooseWinner(["first", "second"], { first: 0.2, second: 0.8 }, 123, true), "second");
+    assert.equal(chooseWinner(["first", "second"], { first: 0.5, second: 0.5 }, 123, true), "first");
+});
+
+test("seeded weighted winner is replayable", () => {
+    const weights = { first: 0.2, second: 0.8 };
+    assert.equal(chooseWinner(["first", "second"], weights, 42), chooseWinner(["first", "second"], weights, 42));
+});

+ 6 - 4
wrangler.toml

@@ -1,7 +1,9 @@
-name = "pm2000"
+name = "decision-maker-2000"
 main = "src/index.ts"
 compatibility_date = "2025-03-01"
 compatibility_flags = ["nodejs_compat"]
+workers_dev = true
+preview_urls = true
 
 [observability]
 enabled = true
@@ -13,8 +15,8 @@ run_worker_first = ["/api/*", "/h/*", "/health"]
 
 [[d1_databases]]
 binding = "DATABASE"
-database_name = "pm2000-db"
-database_id = "your-d1-database-id-here"
+database_name = "decision-maker-2000-db"
+database_id = "53174032-97f0-4e43-81a2-f26a74e6300e"
 migrations_dir = "drizzle"
 
 [[durable_objects.bindings]]
@@ -26,5 +28,5 @@ tag = "v1"
 new_sqlite_classes = ["Hand"]
 
 [vars]
-OTP_MODE = "console"
+OTP_MODE = "twilio"
 PICK_INSTRUCTIONS = "Which option should this table go with? Yes chips are votes and weigh heavily. Respect stated constraints."