From 4667c314ecc49c2d165d8f9f2be245a85ca650f8 Mon Sep 17 00:00:00 2001 From: Emp1500 Date: Mon, 13 Jul 2026 06:18:07 +0000 Subject: [PATCH 1/5] perf: lazy-load three.js DottedSurface background via next/dynamic --- components/ui/DottedSurface.tsx | 153 +------ components/ui/DottedSurfaceCanvas.tsx | 148 +++++++ .../plans/2026-07-12-perf-and-code-audit.md | 413 ++++++++++++++++++ 3 files changed, 570 insertions(+), 144 deletions(-) create mode 100644 components/ui/DottedSurfaceCanvas.tsx create mode 100644 docs/superpowers/plans/2026-07-12-perf-and-code-audit.md diff --git a/components/ui/DottedSurface.tsx b/components/ui/DottedSurface.tsx index b96db5b..14ec2b3 100644 --- a/components/ui/DottedSurface.tsx +++ b/components/ui/DottedSurface.tsx @@ -1,148 +1,13 @@ -'use client'; -import { cn } from '@/lib/utils'; -import React, { useEffect, useRef } from 'react'; -import * as THREE from 'three'; +'use client' -type DottedSurfaceProps = Omit, 'ref'>; +import dynamic from 'next/dynamic' +import type { DottedSurfaceCanvasProps } from './DottedSurfaceCanvas' -export function DottedSurface({ className, ...props }: DottedSurfaceProps) { +const DottedSurfaceCanvas = dynamic( + () => import('./DottedSurfaceCanvas').then(mod => mod.DottedSurfaceCanvas), + { ssr: false } +) - const containerRef = useRef(null); - const sceneRef = useRef<{ - scene: THREE.Scene; - camera: THREE.PerspectiveCamera; - renderer: THREE.WebGLRenderer; - particles: THREE.Points[]; - animationId: number; - count: number; - } | null>(null); - - useEffect(() => { - if (!containerRef.current) return; - - const SEPARATION = 150; - const AMOUNTX = 40; - const AMOUNTY = 60; - - const scene = new THREE.Scene(); - scene.fog = new THREE.Fog(0xffffff, 2000, 10000); - - const camera = new THREE.PerspectiveCamera( - 60, - window.innerWidth / window.innerHeight, - 1, - 10000, - ); - camera.position.set(0, 355, 1220); - - const renderer = new THREE.WebGLRenderer({ - alpha: true, - antialias: true, - }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.setClearColor(scene.fog.color, 0); - - containerRef.current.appendChild(renderer.domElement); - - const positions: number[] = []; - const colors: number[] = []; - const geometry = new THREE.BufferGeometry(); - - for (let ix = 0; ix < AMOUNTX; ix++) { - for (let iy = 0; iy < AMOUNTY; iy++) { - positions.push( - ix * SEPARATION - (AMOUNTX * SEPARATION) / 2, - 0, - iy * SEPARATION - (AMOUNTY * SEPARATION) / 2, - ); - colors.push(0.78, 0.78, 0.78); - } - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - - const material = new THREE.PointsMaterial({ - size: 8, - vertexColors: true, - transparent: true, - opacity: 0.45, - sizeAttenuation: true, - }); - - const points = new THREE.Points(geometry, material); - scene.add(points); - - let count = 0; - let animationId = 0; - - const animate = () => { - animationId = requestAnimationFrame(animate); - - const positionAttribute = geometry.attributes.position; - const pos = positionAttribute.array as Float32Array; - - let i = 0; - for (let ix = 0; ix < AMOUNTX; ix++) { - for (let iy = 0; iy < AMOUNTY; iy++) { - pos[i * 3 + 1] = - Math.sin((ix + count) * 0.3) * 50 + - Math.sin((iy + count) * 0.5) * 50; - i++; - } - } - - positionAttribute.needsUpdate = true; - renderer.render(scene, camera); - count += 0.1; - }; - - const handleResize = () => { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - renderer.setSize(window.innerWidth, window.innerHeight); - }; - - window.addEventListener('resize', handleResize); - const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - if (reducedMotion) { - renderer.render(scene, camera); - } else { - animate(); - } - - sceneRef.current = { scene, camera, renderer, particles: [points], animationId, count }; - - const container = containerRef.current; - - return () => { - window.removeEventListener('resize', handleResize); - if (sceneRef.current) { - cancelAnimationFrame(sceneRef.current.animationId); - sceneRef.current.scene.traverse((object) => { - if (object instanceof THREE.Points) { - object.geometry.dispose(); - if (Array.isArray(object.material)) { - object.material.forEach((m) => m.dispose()); - } else { - object.material.dispose(); - } - } - }); - sceneRef.current.renderer.dispose(); - if (container && sceneRef.current.renderer.domElement) { - container.removeChild(sceneRef.current.renderer.domElement); - } - } - }; - }, []); - - return ( -
- ); +export function DottedSurface(props: DottedSurfaceCanvasProps) { + return } diff --git a/components/ui/DottedSurfaceCanvas.tsx b/components/ui/DottedSurfaceCanvas.tsx new file mode 100644 index 0000000..0d7f2f2 --- /dev/null +++ b/components/ui/DottedSurfaceCanvas.tsx @@ -0,0 +1,148 @@ +'use client'; +import { cn } from '@/lib/utils'; +import React, { useEffect, useRef } from 'react'; +import * as THREE from 'three'; + +export type DottedSurfaceCanvasProps = Omit, 'ref'>; + +export function DottedSurfaceCanvas({ className, ...props }: DottedSurfaceCanvasProps) { + + const containerRef = useRef(null); + const sceneRef = useRef<{ + scene: THREE.Scene; + camera: THREE.PerspectiveCamera; + renderer: THREE.WebGLRenderer; + particles: THREE.Points[]; + animationId: number; + count: number; + } | null>(null); + + useEffect(() => { + if (!containerRef.current) return; + + const SEPARATION = 150; + const AMOUNTX = 40; + const AMOUNTY = 60; + + const scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0xffffff, 2000, 10000); + + const camera = new THREE.PerspectiveCamera( + 60, + window.innerWidth / window.innerHeight, + 1, + 10000, + ); + camera.position.set(0, 355, 1220); + + const renderer = new THREE.WebGLRenderer({ + alpha: true, + antialias: true, + }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setClearColor(scene.fog.color, 0); + + containerRef.current.appendChild(renderer.domElement); + + const positions: number[] = []; + const colors: number[] = []; + const geometry = new THREE.BufferGeometry(); + + for (let ix = 0; ix < AMOUNTX; ix++) { + for (let iy = 0; iy < AMOUNTY; iy++) { + positions.push( + ix * SEPARATION - (AMOUNTX * SEPARATION) / 2, + 0, + iy * SEPARATION - (AMOUNTY * SEPARATION) / 2, + ); + colors.push(0.78, 0.78, 0.78); + } + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + + const material = new THREE.PointsMaterial({ + size: 8, + vertexColors: true, + transparent: true, + opacity: 0.45, + sizeAttenuation: true, + }); + + const points = new THREE.Points(geometry, material); + scene.add(points); + + let count = 0; + let animationId = 0; + + const animate = () => { + animationId = requestAnimationFrame(animate); + + const positionAttribute = geometry.attributes.position; + const pos = positionAttribute.array as Float32Array; + + let i = 0; + for (let ix = 0; ix < AMOUNTX; ix++) { + for (let iy = 0; iy < AMOUNTY; iy++) { + pos[i * 3 + 1] = + Math.sin((ix + count) * 0.3) * 50 + + Math.sin((iy + count) * 0.5) * 50; + i++; + } + } + + positionAttribute.needsUpdate = true; + renderer.render(scene, camera); + count += 0.1; + }; + + const handleResize = () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); + }; + + window.addEventListener('resize', handleResize); + const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + if (reducedMotion) { + renderer.render(scene, camera); + } else { + animate(); + } + + sceneRef.current = { scene, camera, renderer, particles: [points], animationId, count }; + + const container = containerRef.current; + + return () => { + window.removeEventListener('resize', handleResize); + if (sceneRef.current) { + cancelAnimationFrame(sceneRef.current.animationId); + sceneRef.current.scene.traverse((object) => { + if (object instanceof THREE.Points) { + object.geometry.dispose(); + if (Array.isArray(object.material)) { + object.material.forEach((m) => m.dispose()); + } else { + object.material.dispose(); + } + } + }); + sceneRef.current.renderer.dispose(); + if (container && sceneRef.current.renderer.domElement) { + container.removeChild(sceneRef.current.renderer.domElement); + } + } + }; + }, []); + + return ( +
+ ); +} diff --git a/docs/superpowers/plans/2026-07-12-perf-and-code-audit.md b/docs/superpowers/plans/2026-07-12-perf-and-code-audit.md new file mode 100644 index 0000000..fdafbff --- /dev/null +++ b/docs/superpowers/plans/2026-07-12-perf-and-code-audit.md @@ -0,0 +1,413 @@ +# Performance & Code Audit Remediation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Fix the concrete performance, bundle-size, dead-weight-dependency, and type-safety issues found in a full-repo audit (2026-07-12), without changing any user-visible behavior. + +**Architecture:** Each task is an independent, low-risk change: either (a) defer a heavy client-only library behind `next/dynamic`, (b) remove/relocate a dependency in `package.json`, (c) parallelize independent Supabase calls, or (d) tighten types in the parser. No task depends on another; they can be done in any order or split across subagents. + +**Tech Stack:** Next.js 16 (App Router, Turbopack), React 18, TypeScript, Supabase, Jest. + +## Global Constraints + +- Do not change any visible UI behavior, route, or API response shape — this is a non-functional cleanup pass. +- Every task must end with `npm run build` succeeding and `npm test` passing (baseline: all `__tests__/*.test.ts` green). +- Do not touch RLS/SQL, auth flow, or the Content-Security-Policy in `next.config.js`. +- Preserve existing `next-env.d.ts` / `*.tsbuildinfo` gitignore behavior (already correct — no action needed there). + +--- + +## Audit Findings Summary (context for all tasks) + +Verified via `npm run build` + manifest inspection + grep on 2026-07-12: + +1. **`components/ui/DottedSurface.tsx`** statically imports `three` (`import * as THREE from 'three'`). The compiled chunk is 516 KB and is confirmed present in the client reference manifests for `/`, `/login`, and `/register` (the three highest-traffic, unauthenticated entry pages) — confirmed absent from `/dashboard`. It renders a decorative animated background only, with no SSR-dependent output. +2. Zero uses of `next/dynamic` anywhere in the repo — Monaco (`components/editor/CodeEditor.tsx`, `components/share/ShareView.tsx`) and Mermaid (`components/editor/FlowchartPanel.tsx`) are statically imported too. These are already route-isolated by the App Router (not loaded on `/`, `/login`, `/dashboard`), so lower priority than #1, but still block-render their host component instead of streaming in behind a loading state. +3. `package.json` lists `next-themes` (0 references anywhere in `app/`, `components/`, `lib/`, or CSS) and `tw-animate-css` (0 references — only `tailwindcss-animate` is actually used, in `tailwind.config.ts`) as runtime dependencies. Both are dead weight in `node_modules` and install time. +4. `shadcn` (the scaffolding CLI, never imported in source) and `@types/three` (a types-only package) are declared under `dependencies` instead of `devDependencies`, bloating the production dependency tree unnecessarily. +5. `lib/parser/javascript.ts` and `lib/parser/typescript.ts` both open with `/* eslint-disable @typescript-eslint/no-explicit-any */` and together account for 47 of the repo's 52 `any`/`as any` occurrences — the core parsing engine has type-checking effectively turned off. +6. `app/api/flowcharts/[id]/route.ts` `GET` handler issues two independent Supabase queries (`flowcharts` lookup, then latest `flowchart_versions` lookup) sequentially with `await`, even though neither depends on the other's result — an unnecessary serial round-trip on every editor/share page load. + +--- + +### Task 1: Lazy-load the Three.js background on marketing pages + +**Files:** +- Modify: `components/ui/DottedSurface.tsx` +- Test: manual build verification (no existing unit test touches this component) + +**Interfaces:** +- Consumes: nothing new. +- Produces: same default export `DottedSurface` component, same props — callers (`app/page.tsx`, `app/(auth)/login/page.tsx`, `app/(auth)/register/page.tsx`) do not change. + +- [ ] **Step 1: Read the current component to confirm props/shape** + +Run: `sed -n '1,40p' components/ui/DottedSurface.tsx` +Confirm it's a self-contained `'use client'` component with no required props (or note the props if any exist) before splitting it. + +- [ ] **Step 2: Split into a static wrapper + a dynamically-imported Three.js implementation** + +Rename the current file's contents into `components/ui/DottedSurfaceCanvas.tsx` (same code, same `'use client'` directive, same export name but exported as `DottedSurfaceCanvas`), then replace `components/ui/DottedSurface.tsx` with: + +```tsx +'use client' + +import dynamic from 'next/dynamic' + +const DottedSurfaceCanvas = dynamic( + () => import('./DottedSurfaceCanvas').then(mod => mod.DottedSurfaceCanvas), + { ssr: false } +) + +export function DottedSurface(props: React.ComponentProps) { + return +} +``` + +Adjust the prop type / import path to match whatever `DottedSurfaceCanvas`'s actual prop signature is from Step 1 (e.g. if it takes a `className` prop, keep that typed explicitly instead of `React.ComponentProps` if simpler). + +- [ ] **Step 3: Build and confirm the three.js chunk is no longer in the `/`, `/login`, `/register` client reference manifests** + +Run: +```bash +npm run build +grep -o "THREE\|three" .next/server/app/page_client-reference-manifest.js | head -1 +``` +Expected: the three.js chunk filename referenced by `page_client-reference-manifest.js` for `/` is a *different* (smaller, dynamically-loaded) chunk than before, and does not block the initial page chunk list. Confirm visually that `app/page.tsx`, `app/(auth)/login/page.tsx`, `app/(auth)/register/page.tsx` still render the dotted background by running `npm run dev` and opening `/`, `/login`, `/register` in a browser — the background should still animate, just appear a beat after first paint. + +- [ ] **Step 4: Run full test suite** + +Run: `npm test` +Expected: all existing tests pass unchanged (this component has no unit tests, so this just guards against unrelated breakage). + +- [ ] **Step 5: Commit** + +```bash +git add components/ui/DottedSurface.tsx components/ui/DottedSurfaceCanvas.tsx +git commit -m "perf: lazy-load three.js DottedSurface background via next/dynamic" +``` + +--- + +### Task 2: Remove dead dependencies and relocate dev-only ones + +**Files:** +- Modify: `package.json` +- Modify: `package-lock.json` (regenerated by `npm install`, not hand-edited) + +**Interfaces:** +- Consumes: nothing. +- Produces: nothing consumed by later tasks. + +- [ ] **Step 1: Confirm zero usage one more time immediately before removing** + +Run: +```bash +grep -rn "next-themes" --include='*.ts*' --include='*.css' --include='*.mjs' . --exclude-dir=node_modules --exclude-dir=.next --exclude-dir=.git +grep -rn "tw-animate-css" --include='*.ts*' --include='*.css' --include='*.mjs' . --exclude-dir=node_modules --exclude-dir=.next --exclude-dir=.git +grep -rn "from 'shadcn'\|from \"shadcn\"" app components lib --include='*.ts*' +``` +Expected: no output for any of the three commands. + +- [ ] **Step 2: Remove `next-themes` and `tw-animate-css`, move `shadcn` and `@types/three` to devDependencies** + +```bash +npm uninstall next-themes tw-animate-css +npm uninstall shadcn @types/three +npm install --save-dev shadcn @types/three +``` + +- [ ] **Step 3: Verify `package.json` dependency lists** + +Run: `cat package.json` +Expected: `dependencies` no longer contains `next-themes`, `tw-animate-css`, `shadcn`, or `@types/three`; `devDependencies` now contains `shadcn` and `@types/three`. + +- [ ] **Step 4: Rebuild and retest to confirm nothing depended on the removed packages** + +Run: +```bash +npm run build +npm test +``` +Expected: both succeed with no module-not-found errors. + +- [ ] **Step 5: Commit** + +```bash +git add package.json package-lock.json +git commit -m "chore: drop unused next-themes/tw-animate-css deps, move shadcn/@types/three to devDependencies" +``` + +--- + +### Task 3: Parallelize independent Supabase reads in the flowchart GET route + +**Files:** +- Modify: `app/api/flowcharts/[id]/route.ts:8-27` +- Test: `__tests__` has no existing coverage for this route; add a focused test. + +**Interfaces:** +- Consumes: existing `createClient` from `@/lib/supabase/server`. +- Produces: same `GET` response shape (`{ ...flowchart fields, code, version_number }`) — no external interface change. + +- [ ] **Step 1: Write a failing test asserting both queries fire without waiting on each other** + +Create `__tests__/flowcharts-get-route.test.ts`: + +```ts +import { GET } from '@/app/api/flowcharts/[id]/route' + +const flowchartsQuery = { + select: jest.fn().mockReturnThis(), + eq: jest.fn().mockReturnThis(), + single: jest.fn(), +} +const versionsQuery = { + select: jest.fn().mockReturnThis(), + eq: jest.fn().mockReturnThis(), + order: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + single: jest.fn(), +} + +jest.mock('@/lib/supabase/server', () => ({ + createClient: jest.fn(async () => ({ + auth: { getUser: jest.fn(async () => ({ data: { user: { id: 'user-1' } }, error: null })) }, + from: (table: string) => (table === 'flowcharts' ? flowchartsQuery : versionsQuery), + })), +})) + +describe('GET /api/flowcharts/[id]', () => { + it('issues the flowchart and version lookups concurrently', async () => { + let flowchartResolved = false + let versionStartedBeforeFlowchartResolved = false + + flowchartsQuery.single.mockImplementation( + () => + new Promise(resolve => + setTimeout(() => { + flowchartResolved = true + resolve({ data: { id: 'fc-1', user_id: 'user-1' }, error: null }) + }, 20) + ) + ) + versionsQuery.single.mockImplementation(() => { + versionStartedBeforeFlowchartResolved = !flowchartResolved + return Promise.resolve({ data: { code: 'x', version_number: 3 }, error: null }) + }) + + const request = new Request('http://localhost/api/flowcharts/fc-1') + const response = await GET(request, { params: Promise.resolve({ id: 'fc-1' }) }) + const body = await response.json() + + expect(versionStartedBeforeFlowchartResolved).toBe(true) + expect(body).toMatchObject({ id: 'fc-1', code: 'x', version_number: 3 }) + }) +}) +``` + +- [ ] **Step 2: Run test to verify it fails against the current sequential implementation** + +Run: `npx jest __tests__/flowcharts-get-route.test.ts -v` +Expected: FAIL — `versionStartedBeforeFlowchartResolved` is `false` because today's code `await`s the flowchart query before starting the version query. + +- [ ] **Step 3: Parallelize the two independent queries with `Promise.all`** + +In `app/api/flowcharts/[id]/route.ts`, replace the `GET` handler body (currently sequential `await`s for `fc` then `versionRes`) with: + +```ts +export async function GET(_req: Request, { params }: Params) { + const { id } = await params + const supabase = await createClient() + const { data: { user }, error: authErr } = await supabase.auth.getUser() + if (authErr || !user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + + const [{ data: fc, error }, versionRes] = await Promise.all([ + supabase.from('flowcharts').select('*').eq('id', id).eq('user_id', user.id).single(), + supabase + .from('flowchart_versions') + .select('code, version_number') + .eq('flowchart_id', id) + .order('version_number', { ascending: false }) + .limit(1) + .single(), + ]) + if (error || !fc) return NextResponse.json({ error: 'Not found' }, { status: 404 }) + + const version = versionRes.data as { code: string; version_number: number } | null + + return NextResponse.json(Object.assign({}, fc, { code: version?.code ?? '', version_number: version?.version_number ?? 0 })) +} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx jest __tests__/flowcharts-get-route.test.ts -v` +Expected: PASS + +- [ ] **Step 5: Run full suite and build** + +Run: +```bash +npm test +npm run build +``` +Expected: all green. + +- [ ] **Step 6: Commit** + +```bash +git add app/api/flowcharts/\[id\]/route.ts __tests__/flowcharts-get-route.test.ts +git commit -m "perf: parallelize flowchart+version reads in GET /api/flowcharts/[id]" +``` + +--- + +### Task 4: Re-enable type checking in the parser and eliminate `any` + +**Files:** +- Modify: `lib/parser/javascript.ts` (41 `any` occurrences) +- Modify: `lib/parser/typescript.ts` (5 `any` occurrences) +- Modify: `lib/parser/python.ts` (6 `any` occurrences) +- Test: existing `__tests__/parser-js-accuracy.test.ts`, `__tests__/parser-python-accuracy.test.ts`, `__tests__/parser.test.ts` already cover parser behavior and must stay green throughout — this task is a pure typing refactor with no behavior change. + +**Interfaces:** +- Consumes: `acorn.Node` / `acorn.Program` types from `acorn`, and whatever AST node shapes `acorn-typescript` exports. +- Produces: same exported functions (`convertJS`/`processBlock`/`convertTS`/`convertPython` etc.) with identical signatures — only internal typing changes. + +- [ ] **Step 1: Baseline — confirm parser tests pass before touching anything** + +Run: `npx jest __tests__/parser-js-accuracy.test.ts __tests__/parser-python-accuracy.test.ts __tests__/parser.test.ts __tests__/python-lines.test.ts -v` +Expected: PASS (record this as the behavior baseline — Task 4 must not change these results). + +- [ ] **Step 2: Remove the file-level `eslint-disable` in `lib/parser/javascript.ts` and see what breaks** + +Delete the line `/* eslint-disable @typescript-eslint/no-explicit-any */` at the top of `lib/parser/javascript.ts`. + +Run: `npx eslint lib/parser/javascript.ts` +Expected: a list of `no-explicit-any` errors, one per `any` usage — this is your worklist for this file. + +- [ ] **Step 3: Type the acorn AST node parameters precisely** + +For each flagged line, replace `any` with the correct acorn type. Acorn's own `Node` type only guarantees `type`, `start`, `end`, `loc` — real node shapes (e.g. `IfStatement`, `ForStatement`, `CallExpression`) come from `acorn`'s `Node` union or from casting to a local narrow interface. Prefer this pattern already established in `lib/parser/types.ts` (check that file for any existing narrow AST interfaces before adding new ones): + +```ts +import type { Node } from 'acorn' + +interface IfStatementNode extends Node { + type: 'IfStatement' + test: Node + consequent: Node + alternate: Node | null +} +``` + +Add one narrow interface per distinct node shape the switch/if-chain in `processBlock` (or equivalent) actually dispatches on — do not create a generic catch-all `any` replacement; each usage should get its real shape. + +- [ ] **Step 4: Run eslint again to confirm zero `no-explicit-any` violations in this file** + +Run: `npx eslint lib/parser/javascript.ts` +Expected: no errors. + +- [ ] **Step 5: Run parser tests to confirm no behavior changed** + +Run: `npx jest __tests__/parser-js-accuracy.test.ts __tests__/parser.test.ts -v` +Expected: PASS, identical to Step 1 baseline. + +- [ ] **Step 6: Repeat Steps 2-5 for `lib/parser/typescript.ts`** + +Same process: remove its `eslint-disable`, add narrow types for the 5 flagged spots (this file already documents one legitimate unavoidable `any` — the `tsPlugin` CJS-interop cast explained in its existing comment; that one may stay as a targeted `as any` on that single line with the existing comment, not a file-wide disable — everything else must be typed). + +Run: `npx eslint lib/parser/typescript.ts && npx jest __tests__/parser-js-accuracy.test.ts -v` +Expected: no lint errors outside the documented interop cast; tests pass. + +- [ ] **Step 7: Repeat for `lib/parser/python.ts`'s 6 occurrences** + +Run: `npx eslint lib/parser/python.ts && npx jest __tests__/parser-python-accuracy.test.ts __tests__/python-lines.test.ts -v` +Expected: no lint errors; tests pass. + +- [ ] **Step 8: Full-repo verification** + +Run: +```bash +npm run lint +npm test +npm run build +``` +Expected: all green, zero `no-explicit-any` suppressions remaining outside the one documented `acorn-typescript` interop cast. + +- [ ] **Step 9: Commit** + +```bash +git add lib/parser/javascript.ts lib/parser/typescript.ts lib/parser/python.ts +git commit -m "refactor: replace any with precise AST types across the parser, drop file-wide any suppressions" +``` + +--- + +### Task 5: Defer Monaco and Mermaid behind `next/dynamic` with a loading state + +**Files:** +- Modify: `components/editor/CodeEditor.tsx` +- Modify: `components/editor/FlowchartPanel.tsx` +- Modify: `components/share/ShareView.tsx` + +**Interfaces:** +- Consumes: nothing new. +- Produces: same component exports/props as today — this is purely about *when* the JS downloads/executes relative to first paint of the editor shell, not what renders. + +- [ ] **Step 1: Read current CodeEditor.tsx top-of-file imports and export shape** + +Run: `sed -n '1,30p' components/editor/CodeEditor.tsx` + +- [ ] **Step 2: Wrap the Monaco import with `next/dynamic` and a skeleton fallback** + +In `components/editor/CodeEditor.tsx`, replace the static `import MonacoEditor, { loader } from '@monaco-editor/react'` usage: keep `loader` imported statically (it's tiny, just config), but load the `` component itself via: + +```tsx +import dynamic from 'next/dynamic' +import { loader } from '@monaco-editor/react' + +const MonacoEditor = dynamic(() => import('@monaco-editor/react').then(m => m.default), { + ssr: false, + loading: () =>
Loading editor…
, +}) +``` + +Remove the old default import of `MonacoEditor` and keep every other usage in the file unchanged (same props passed to ``). + +- [ ] **Step 3: Apply the same pattern to `components/share/ShareView.tsx`'s Monaco import** + +Same transformation as Step 2, scoped to that file's own top-of-file imports. + +- [ ] **Step 4: Defer the `mermaid` import in `components/editor/FlowchartPanel.tsx`** + +`mermaid` is imported and used inside `useEffect`, not at module top-level render — confirm with `grep -n "mermaid" components/editor/FlowchartPanel.tsx`. If it's already only referenced inside an effect/async function (not at module scope), convert the static top-level `import mermaid from 'mermaid'` into a dynamic `const { default: mermaid } = await import('mermaid')` inside that same effect, so it's fetched only when the panel actually mounts rather than bundled into the initial chunk for that route. + +- [ ] **Step 5: Manual verification in the browser** + +Run: `npm run dev`, open `/editor`, confirm: the editor shell (toolbar, panel borders) paints immediately, "Loading editor…" briefly shows, then Monaco loads and is fully interactive (typing, syntax highlighting). Open `/editor/[id]` with an existing flowchart (or `/share/[shareId]`) and confirm the mermaid diagram still renders correctly with no console errors. + +- [ ] **Step 6: Run full test suite and build** + +Run: +```bash +npm test +npm run build +``` +Expected: all green. + +- [ ] **Step 7: Commit** + +```bash +git add components/editor/CodeEditor.tsx components/editor/FlowchartPanel.tsx components/share/ShareView.tsx +git commit -m "perf: defer Monaco/Mermaid loading behind next/dynamic with loading states" +``` + +--- + +## Self-Review Notes + +- **Spec coverage:** All 6 audit findings map 1:1 to a task (Finding 1 → Task 1, Finding 2 → Task 5, Findings 3-4 → Task 2, Finding 5 → Task 4, Finding 6 → Task 3). +- **Independence:** Tasks 1-5 touch disjoint files (only Task 1 and Task 5 both touch the `components/` tree, but different files within it) — safe to dispatch in parallel via subagent-driven-development. +- **No placeholders:** every step has literal code, exact commands, and expected output. From 11b2ffa4638bf606ce11ca63506094fdaaee8f9f Mon Sep 17 00:00:00 2001 From: Emp1500 Date: Mon, 13 Jul 2026 07:13:21 +0000 Subject: [PATCH 2/5] chore: drop unused next-themes/tw-animate-css deps, move shadcn/@types/three to devDependencies --- package-lock.json | 513 ++++++++++++++++++++++++++++++---------------- package.json | 6 +- 2 files changed, 337 insertions(+), 182 deletions(-) diff --git a/package-lock.json b/package-lock.json index adf87a9..3bb9b37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "@monaco-editor/react": "^4.7.0", "@supabase/ssr": "^0.12.0", "@supabase/supabase-js": "^2.108.2", - "@types/three": "^0.185.0", "@upstash/ratelimit": "^2.0.8", "@upstash/redis": "^1.38.0", "acorn-typescript": "^1.4.13", @@ -25,15 +24,12 @@ "mermaid": "^11.15.0", "nanoid": "^5.1.16", "next": "^16.2.10", - "next-themes": "^0.4.6", "react": "^18", "react-dom": "^18", "react-resizable-panels": "^4.11.2", - "shadcn": "^4.11.0", "tailwind-merge": "^3.6.0", "tailwindcss-animate": "^1.0.7", "three": "^0.185.0", - "tw-animate-css": "^1.4.0", "vaul": "^1.1.2", "zod": "^4.4.3" }, @@ -42,11 +38,13 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/three": "^0.185.1", "dotenv": "^17.4.2", "eslint": "^9", "eslint-config-next": "^16.2.10", "jest": "^30.4.2", "postcss": "^8", + "shadcn": "^4.13.0", "tailwindcss": "^3.4.1", "ts-jest": "^29.4.11", "typescript": "^5" @@ -81,6 +79,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", @@ -95,6 +94,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -104,6 +104,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -134,6 +135,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -146,6 +148,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -155,6 +158,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", @@ -171,6 +175,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -183,6 +188,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.29.7", @@ -199,6 +205,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -208,6 +215,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -217,6 +225,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", @@ -238,6 +247,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -247,6 +257,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -256,6 +267,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -269,6 +281,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -282,6 +295,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.29.7", @@ -299,6 +313,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -311,6 +326,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -320,6 +336,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.29.7", @@ -337,6 +354,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -350,6 +368,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -359,6 +378,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -368,6 +388,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -377,6 +398,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.29.7", @@ -390,6 +412,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -502,6 +525,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" @@ -627,6 +651,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" @@ -642,6 +667,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.29.7", @@ -658,6 +684,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", @@ -677,6 +704,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", @@ -705,6 +733,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -719,6 +748,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -737,6 +767,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -829,12 +860,14 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@dotenvx/dotenvx": { "version": "1.75.1", "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz", "integrity": "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@dotenvx/primitives": "^0.8.0", @@ -865,6 +898,7 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16" @@ -874,6 +908,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -883,6 +918,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -906,6 +942,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -923,6 +960,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -935,6 +973,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -944,6 +983,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -959,6 +999,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -971,6 +1012,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -983,6 +1025,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -992,6 +1035,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -1004,6 +1048,7 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -1018,9 +1063,10 @@ } }, "node_modules/@dotenvx/dotenvx/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1033,12 +1079,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, "license": "ISC" }, "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1048,6 +1096,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -1063,6 +1112,7 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/@dotenvx/primitives/-/primitives-0.8.0.tgz", "integrity": "sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@emnapi/core": { @@ -1271,6 +1321,7 @@ "version": "1.19.14", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18.14.1" @@ -2526,6 +2577,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2570,6 +2622,7 @@ "version": "1.29.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "dev": true, "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", @@ -2610,6 +2663,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -2626,6 +2680,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/@monaco-editor/loader": { @@ -3254,6 +3309,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, "license": "MIT" }, "node_modules/@sinclair/typebox": { @@ -3267,6 +3323,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3404,6 +3461,7 @@ "version": "0.27.0", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "dev": true, "license": "MIT", "dependencies": { "fast-glob": "^3.3.3", @@ -3415,15 +3473,17 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" } }, "node_modules/@ts-morph/common/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -3436,6 +3496,7 @@ "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.5" @@ -3451,6 +3512,7 @@ "version": "23.1.3", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "devOptional": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -3876,12 +3938,14 @@ "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "devOptional": true, "license": "MIT" }, "node_modules/@types/three": { - "version": "0.185.0", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.185.0.tgz", - "integrity": "sha512-O2Uy8Cj4Nonr8dWUUbifMdPe8B0Mq7EdOHb89S4+kjUw/KhbjTZrUuYlrQ1bpUKG+EP9QJnN7qNxbHGlGoLHMA==", + "version": "0.185.1", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.185.1.tgz", + "integrity": "sha512-db1xTb+EgYF2didW+eudSvVPtn75zo+fGsY8ShQrJY/B5ZBmC2Fiaykv3aImHAlCNEGuMPkPGXBJGLwzu5mC7A==", + "devOptional": true, "license": "MIT", "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", @@ -3903,12 +3967,14 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", + "dev": true, "license": "MIT" }, "node_modules/@types/webxr": { "version": "0.5.24", "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "devOptional": true, "license": "MIT" }, "node_modules/@types/yargs": { @@ -4577,6 +4643,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -4617,15 +4684,6 @@ "acorn": ">=8.9.0" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -4647,6 +4705,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -4664,6 +4723,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -4680,6 +4740,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/animejs": { @@ -4708,6 +4769,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4746,6 +4808,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4796,6 +4859,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/aria-hidden": { @@ -4984,6 +5048,7 @@ "version": "0.16.1", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -5013,6 +5078,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.12.0" @@ -5188,6 +5254,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -5212,6 +5279,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5222,9 +5290,10 @@ } }, "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5264,6 +5333,7 @@ "version": "4.28.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -5327,6 +5397,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" @@ -5342,6 +5413,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -5370,6 +5442,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5383,6 +5456,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5399,6 +5473,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5545,6 +5620,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" @@ -5560,6 +5636,7 @@ "version": "2.9.2", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5669,6 +5746,7 @@ "version": "13.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "dev": true, "license": "MIT" }, "node_modules/collect-v8-coverage": { @@ -5718,6 +5796,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.6.3", @@ -5742,6 +5821,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -5758,6 +5838,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -5775,18 +5856,21 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/conf/node_modules/json-schema-typed": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5800,6 +5884,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -5809,6 +5894,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -5828,6 +5914,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.6.0" @@ -5837,6 +5924,7 @@ "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, "license": "MIT", "dependencies": { "object-assign": "^4", @@ -5863,6 +5951,7 @@ "version": "9.0.2", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.1", @@ -5889,6 +5978,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6433,15 +6523,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -6506,6 +6587,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^3.0.0" @@ -6521,6 +6603,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6538,6 +6621,7 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -6559,6 +6643,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6568,6 +6653,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -6584,6 +6670,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6614,6 +6701,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6653,6 +6741,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -6694,6 +6783,7 @@ "version": "8.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -6718,6 +6808,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, "license": "MIT", "dependencies": { "is-obj": "^2.0.0" @@ -6733,6 +6824,7 @@ "version": "17.4.2", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -6745,6 +6837,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -6766,12 +6859,14 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.378", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.378.tgz", "integrity": "sha512-VinvOAuuPmdD1guEgGv5f2Qp7/vlfqOrUOMYNnOD4wj3pit8kRsQHzfIf6teyUGWo15Tg5+bOJaRunvyltpVWQ==", + "dev": true, "license": "ISC" }, "node_modules/emittery": { @@ -6798,6 +6893,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -6807,6 +6903,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", @@ -6820,6 +6917,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6829,6 +6927,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -6926,6 +7025,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6972,6 +7072,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -7043,6 +7144,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7052,6 +7154,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, "license": "MIT" }, "node_modules/escape-string-regexp": { @@ -7503,6 +7606,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -7562,6 +7666,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -7571,6 +7676,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" @@ -7583,6 +7689,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18.0.0" @@ -7592,6 +7699,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", @@ -7646,6 +7754,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -7689,6 +7798,7 @@ "version": "8.5.2", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "dev": true, "license": "MIT", "dependencies": { "ip-address": "^10.2.0" @@ -7707,6 +7817,7 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -7716,6 +7827,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -7761,9 +7873,10 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "dev": true, "funding": [ { "type": "github", @@ -7795,39 +7908,18 @@ "bser": "2.1.1" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/fflate": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "devOptional": true, "license": "MIT" }, "node_modules/figures": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, "license": "MIT", "dependencies": { "is-unicode-supported": "^2.0.0" @@ -7868,6 +7960,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -7956,22 +8049,11 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -7981,15 +8063,17 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/fs-extra": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", - "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -8068,6 +8152,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "dev": true, "license": "MIT" }, "node_modules/generator-function": { @@ -8084,6 +8169,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8103,6 +8189,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8115,6 +8202,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -8148,6 +8236,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -8170,6 +8259,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -8183,6 +8273,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, "license": "MIT", "dependencies": { "@sec-ant/readable-stream": "^0.4.1", @@ -8272,6 +8363,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8284,6 +8376,7 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "node_modules/hachure-fill": { @@ -8370,6 +8463,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8424,9 +8518,10 @@ } }, "node_modules/hono": { - "version": "4.12.27", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz", - "integrity": "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==", + "version": "4.12.30", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.30.tgz", + "integrity": "sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.9.0" @@ -8449,6 +8544,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -8465,23 +8561,11 @@ "url": "https://opencollective.com/express" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/human-signals": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -8512,6 +8596,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -8521,6 +8606,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -8589,6 +8675,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -8619,6 +8706,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -8628,6 +8716,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -8655,6 +8744,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -8799,6 +8889,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -8907,6 +8998,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -8919,6 +9011,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^3.0.0" @@ -8937,6 +9030,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9001,6 +9095,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9010,6 +9105,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9022,6 +9118,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, "license": "MIT" }, "node_modules/is-regex": { @@ -9047,6 +9144,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9088,6 +9186,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -9151,6 +9250,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -9209,6 +9309,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" @@ -9231,6 +9332,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -10182,6 +10284,7 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -10197,6 +10300,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, "funding": [ { "type": "github", @@ -10219,6 +10323,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -10238,6 +10343,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -10251,6 +10357,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -10277,6 +10384,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -10345,6 +10453,7 @@ "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" @@ -10458,6 +10567,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^5.3.0", @@ -10474,6 +10584,7 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -10486,6 +10597,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -10571,6 +10683,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10580,6 +10693,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -10589,6 +10703,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -10601,6 +10716,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -10645,6 +10761,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz", "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", + "devOptional": true, "license": "MIT" }, "node_modules/micromatch": { @@ -10664,6 +10781,7 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -10673,6 +10791,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -10689,6 +10808,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10698,6 +10818,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -10723,6 +10844,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10766,6 +10888,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -10824,6 +10947,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -10889,16 +11013,6 @@ } } }, - "node_modules/next-themes": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", - "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" - } - }, "node_modules/next/node_modules/nanoid": { "version": "3.3.15", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", @@ -10945,26 +11059,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, "node_modules/node-exports-info": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", @@ -10994,24 +11088,6 @@ "semver": "bin/semver.js" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -11023,6 +11099,7 @@ "version": "2.0.50", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -11041,6 +11118,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^4.0.0", @@ -11057,6 +11135,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11087,6 +11166,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11109,6 +11189,7 @@ "version": "1.1.33", "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -11208,6 +11289,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -11220,6 +11302,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -11229,6 +11312,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -11244,6 +11328,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11253,6 +11338,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "dev": true, "license": "MIT", "dependencies": { "default-browser": "^5.4.0", @@ -11291,6 +11377,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^5.3.0", @@ -11314,6 +11401,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11326,6 +11414,7 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -11338,12 +11427,14 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, "license": "MIT" }, "node_modules/ora/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -11361,6 +11452,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -11426,6 +11518,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11448,6 +11541,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -11460,6 +11554,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -11478,6 +11573,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -11490,6 +11586,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -11499,6 +11596,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, "license": "MIT" }, "node_modules/path-data-parser": { @@ -11531,6 +11629,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11563,6 +11662,7 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, "license": "MIT", "funding": { "type": "opencollective", @@ -11609,6 +11709,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.20.0" @@ -11687,6 +11788,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, "license": "MIT", "dependencies": { "find-up": "^3.0.0" @@ -11699,6 +11801,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -11711,6 +11814,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -11724,6 +11828,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -11739,6 +11844,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -11751,6 +11857,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -11981,6 +12088,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -12032,6 +12140,7 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, "license": "MIT", "dependencies": { "parse-ms": "^4.0.0" @@ -12047,6 +12156,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, "license": "MIT", "dependencies": { "kleur": "^3.0.3", @@ -12060,6 +12170,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12081,6 +12192,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -12121,6 +12233,7 @@ "version": "6.15.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1", @@ -12154,18 +12267,24 @@ "license": "MIT" }, "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/raw-body": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -12178,9 +12297,10 @@ } }, "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -12342,9 +12462,10 @@ } }, "node_modules/recast": { - "version": "0.23.11", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", - "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "version": "0.23.12", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.12.tgz", + "integrity": "sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA==", + "dev": true, "license": "MIT", "dependencies": { "ast-types": "^0.16.1", @@ -12415,6 +12536,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12477,6 +12599,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -12496,6 +12619,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, "license": "MIT", "dependencies": { "onetime": "^7.0.0", @@ -12512,6 +12636,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-function": "^5.0.0" @@ -12555,6 +12680,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -12571,6 +12697,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12682,6 +12809,7 @@ "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12694,6 +12822,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -12720,6 +12849,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -12788,12 +12918,14 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, "license": "ISC" }, "node_modules/shadcn": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.11.0.tgz", - "integrity": "sha512-UV0cchFea9hO7poV1CuEP0wvmYjpAqcxCKdy23bndl2Du2ARtDs8A4xdzfhUjDBeOW1nNpJ6lXmsEpsply2SfQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.13.0.tgz", + "integrity": "sha512-5fuJ4jI/GcPeA/iTL4cJivCZuYQGXz/N3bIzyd+Gd/FM6xUCy2MxGG+LaDQuw2cjNy9zGPSFPTEmI048UwPTZA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.0", @@ -12813,9 +12945,7 @@ "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", - "https-proxy-agent": "^7.0.6", "kleur": "^4.1.5", - "node-fetch": "^3.3.2", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", @@ -12826,18 +12956,23 @@ "tailwind-merge": "^3.0.1", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", + "undici": "^7.27.2", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" + }, + "engines": { + "node": ">=20.18.1" } }, "node_modules/shadcn/node_modules/commander": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -12847,6 +12982,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -12859,6 +12995,7 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -12872,6 +13009,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, "license": "MIT", "dependencies": { "json5": "^2.2.2", @@ -12886,6 +13024,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -12940,6 +13079,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -12952,6 +13092,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12961,6 +13102,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -12980,6 +13122,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -12996,6 +13139,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -13014,6 +13158,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -13033,6 +13178,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -13045,6 +13191,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, "license": "MIT" }, "node_modules/slash": { @@ -13061,6 +13208,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -13133,6 +13281,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -13142,6 +13291,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -13366,6 +13516,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "get-own-enumerable-keys": "^1.0.0", @@ -13383,6 +13534,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -13395,6 +13547,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -13421,6 +13574,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -13430,6 +13584,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -13544,9 +13699,10 @@ } }, "node_modules/systeminformation": { - "version": "5.31.11", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.11.tgz", - "integrity": "sha512-I6O7iaUj23AXRgCPDDnvi3xHvdOLp4+1YMbF+X194lJwY1NeWojgHJPhslVKcmTtrLTguRk3QJK+xEdTiI3P0w==", + "version": "5.31.16", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.16.tgz", + "integrity": "sha512-37NsFaeaqwYxanLgdJAGWj8OXIRgvSBsDXGhlC0uUoHyl9nf4HrNsZjqtQ9Gc99bj9FQpffzYccPVuQ6gpjfqg==", + "dev": true, "license": "MIT", "os": [ "darwin", @@ -13714,6 +13870,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, "license": "MIT" }, "node_modules/tinyexec": { @@ -13793,6 +13950,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.6" @@ -13909,6 +14067,7 @@ "version": "26.0.0", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", + "dev": true, "license": "MIT", "dependencies": { "@ts-morph/common": "~0.27.0", @@ -13934,15 +14093,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tw-animate-css": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", - "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Wombosvideo" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -13970,6 +14120,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, "license": "MIT", "dependencies": { "content-type": "^2.0.0", @@ -13988,6 +14139,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -14079,7 +14231,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -14156,6 +14308,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -14172,6 +14325,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -14184,6 +14338,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -14193,6 +14348,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -14240,6 +14396,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -14366,6 +14523,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "dev": true, "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -14375,6 +14533,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -14403,19 +14562,11 @@ "makeerror": "1.0.12" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -14638,6 +14789,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -14658,6 +14810,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "dev": true, "license": "MIT", "dependencies": { "is-wsl": "^3.1.0", @@ -14684,6 +14837,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yargs": { @@ -14751,9 +14905,10 @@ } }, "node_modules/yocto-spinner": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.0.tgz", - "integrity": "sha512-Yw0hUB6UA3o4YUgKy3oSe9a4cxoaZ9sBfYDw+JSxo6Id0KoJGoxzPA24qqUXYKBWABs/zDSGTz9kww7t3F0XGw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.1.tgz", + "integrity": "sha512-9cbFWLhbiZp+820O4pkHGNncI7+MrUGzBOjw8NMG+ewsY+aG0DdEXnr19Smxao32YOjLZRMdn1UtaxcrXOYOIg==", + "dev": true, "license": "MIT", "dependencies": { "yoctocolors": "^2.1.1" @@ -14769,6 +14924,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -14790,6 +14946,7 @@ "version": "3.25.2", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4" diff --git a/package.json b/package.json index 862fe05..b5aef22 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "@monaco-editor/react": "^4.7.0", "@supabase/ssr": "^0.12.0", "@supabase/supabase-js": "^2.108.2", - "@types/three": "^0.185.0", "@upstash/ratelimit": "^2.0.8", "@upstash/redis": "^1.38.0", "acorn-typescript": "^1.4.13", @@ -30,15 +29,12 @@ "mermaid": "^11.15.0", "nanoid": "^5.1.16", "next": "^16.2.10", - "next-themes": "^0.4.6", "react": "^18", "react-dom": "^18", "react-resizable-panels": "^4.11.2", - "shadcn": "^4.11.0", "tailwind-merge": "^3.6.0", "tailwindcss-animate": "^1.0.7", "three": "^0.185.0", - "tw-animate-css": "^1.4.0", "vaul": "^1.1.2", "zod": "^4.4.3" }, @@ -53,11 +49,13 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/three": "^0.185.1", "dotenv": "^17.4.2", "eslint": "^9", "eslint-config-next": "^16.2.10", "jest": "^30.4.2", "postcss": "^8", + "shadcn": "^4.13.0", "tailwindcss": "^3.4.1", "ts-jest": "^29.4.11", "typescript": "^5" From 2ac9754c3474192e8d1755f3ea5de30f3b2e75a8 Mon Sep 17 00:00:00 2001 From: Emp1500 Date: Mon, 13 Jul 2026 07:34:42 +0000 Subject: [PATCH 3/5] perf: parallelize flowchart+version reads in GET /api/flowcharts/[id] --- __tests__/flowcharts-get-route.test.ts | 49 ++++++++++++++++++++++++++ app/api/flowcharts/[id]/route.ts | 19 +++++----- 2 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 __tests__/flowcharts-get-route.test.ts diff --git a/__tests__/flowcharts-get-route.test.ts b/__tests__/flowcharts-get-route.test.ts new file mode 100644 index 0000000..03623f8 --- /dev/null +++ b/__tests__/flowcharts-get-route.test.ts @@ -0,0 +1,49 @@ +import { GET } from '@/app/api/flowcharts/[id]/route' + +const flowchartsQuery = { + select: jest.fn().mockReturnThis(), + eq: jest.fn().mockReturnThis(), + single: jest.fn(), +} +const versionsQuery = { + select: jest.fn().mockReturnThis(), + eq: jest.fn().mockReturnThis(), + order: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + single: jest.fn(), +} + +jest.mock('@/lib/supabase/server', () => ({ + createClient: jest.fn(async () => ({ + auth: { getUser: jest.fn(async () => ({ data: { user: { id: 'user-1' } }, error: null })) }, + from: (table: string) => (table === 'flowcharts' ? flowchartsQuery : versionsQuery), + })), +})) + +describe('GET /api/flowcharts/[id]', () => { + it('issues the flowchart and version lookups concurrently', async () => { + let flowchartResolved = false + let versionStartedBeforeFlowchartResolved = false + + flowchartsQuery.single.mockImplementation( + () => + new Promise(resolve => + setTimeout(() => { + flowchartResolved = true + resolve({ data: { id: 'fc-1', user_id: 'user-1' }, error: null }) + }, 20) + ) + ) + versionsQuery.single.mockImplementation(() => { + versionStartedBeforeFlowchartResolved = !flowchartResolved + return Promise.resolve({ data: { code: 'x', version_number: 3 }, error: null }) + }) + + const request = new Request('http://localhost/api/flowcharts/fc-1') + const response = await GET(request, { params: Promise.resolve({ id: 'fc-1' }) }) + const body = await response.json() + + expect(versionStartedBeforeFlowchartResolved).toBe(true) + expect(body).toMatchObject({ id: 'fc-1', code: 'x', version_number: 3 }) + }) +}) diff --git a/app/api/flowcharts/[id]/route.ts b/app/api/flowcharts/[id]/route.ts index fc94408..cef6c46 100644 --- a/app/api/flowcharts/[id]/route.ts +++ b/app/api/flowcharts/[id]/route.ts @@ -11,17 +11,18 @@ export async function GET(_req: Request, { params }: Params) { const { data: { user }, error: authErr } = await supabase.auth.getUser() if (authErr || !user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) - const { data: fc, error } = await supabase - .from('flowcharts').select('*').eq('id', id).eq('user_id', user.id).single() + const [{ data: fc, error }, versionRes] = await Promise.all([ + supabase.from('flowcharts').select('*').eq('id', id).eq('user_id', user.id).single(), + supabase + .from('flowchart_versions') + .select('code, version_number') + .eq('flowchart_id', id) + .order('version_number', { ascending: false }) + .limit(1) + .single(), + ]) if (error || !fc) return NextResponse.json({ error: 'Not found' }, { status: 404 }) - const versionRes = await supabase - .from('flowchart_versions') - .select('code, version_number') - .eq('flowchart_id', id) - .order('version_number', { ascending: false }) - .limit(1) - .single() const version = versionRes.data as { code: string; version_number: number } | null return NextResponse.json(Object.assign({}, fc, { code: version?.code ?? '', version_number: version?.version_number ?? 0 })) From 1e54153843b867c7bf6403c7368d5e41c41ed360 Mon Sep 17 00:00:00 2001 From: Emp1500 Date: Mon, 13 Jul 2026 09:30:22 +0000 Subject: [PATCH 4/5] refactor: replace any with precise AST types across the parser, drop file-wide any suppressions --- lib/parser/javascript.ts | 116 +++++++++++++++++++++++--------------- lib/parser/python.ts | 118 ++++++++++++++++++++++++++++----------- lib/parser/typescript.ts | 26 +++++++-- 3 files changed, 176 insertions(+), 84 deletions(-) diff --git a/lib/parser/javascript.ts b/lib/parser/javascript.ts index f5a6a6f..1c21367 100644 --- a/lib/parser/javascript.ts +++ b/lib/parser/javascript.ts @@ -1,12 +1,31 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import * as acorn from 'acorn' import { FlowchartGraph, TraversalContext, type BlockResult, type FlowchartNode } from './types' +// acorn-typescript (see ./typescript.ts) parses TS-only declarations that +// acorn's own types don't model since they're added by the plugin, not +// acorn core. This module's traversal (shared by convertJS and convertTS) +// only ever reads `.type` for these — they carry no runtime control flow. +interface TSTypeOnlyNode extends acorn.Node { + type: 'TSInterfaceDeclaration' | 'TSTypeAliasDeclaration' | 'TSDeclareFunction' | 'TSModuleDeclaration' +} + +// Any node this module's traversal may encounter: every real acorn AST +// shape (acorn.AnyNode, acorn's own union of all node interfaces) plus the +// TS-only declarations above. +type AstNode = acorn.AnyNode | TSTypeOnlyNode + +// A parse error thrown by acorn/acorn-typescript: a SyntaxError-shaped +// object with a non-standard `loc` position attached. +interface AcornParseError { + message: string + loc?: { line: number; column: number } | null +} + // ── Expression formatter ──────────────────────────────────────────────────── export function formatExpression(node: acorn.Node | null, maxLen = 60): string { if (!node) return '' - const n = node as any + const n = node as acorn.AnyNode let text = '' switch (n.type) { case 'Identifier': text = n.name; break @@ -17,12 +36,12 @@ export function formatExpression(node: acorn.Node | null, maxLen = 60): string { case 'UpdateExpression': text = n.prefix ? `${n.operator}${formatExpression(n.argument)}` : `${formatExpression(n.argument)}${n.operator}`; break case 'AssignmentExpression': text = `${formatExpression(n.left)} ${n.operator} ${formatExpression(n.right)}`; break case 'MemberExpression': text = n.computed ? `${formatExpression(n.object)}[${formatExpression(n.property)}]` : `${formatExpression(n.object)}.${formatExpression(n.property)}`; break - case 'CallExpression': text = `${formatExpression(n.callee)}(${n.arguments.map((a: any) => formatExpression(a)).join(', ')})`; break + case 'CallExpression': text = `${formatExpression(n.callee)}(${n.arguments.map(a => formatExpression(a)).join(', ')})`; break case 'ConditionalExpression': text = `${formatExpression(n.test)} ? ${formatExpression(n.consequent)} : ${formatExpression(n.alternate)}`; break - case 'ArrayExpression': text = `[${n.elements.map((e: any) => formatExpression(e)).join(', ')}]`; break + case 'ArrayExpression': text = `[${n.elements.map(e => formatExpression(e)).join(', ')}]`; break case 'ObjectExpression': text = '{...}'; break - case 'NewExpression': text = `new ${formatExpression(n.callee)}(${n.arguments.map((a: any) => formatExpression(a)).join(', ')})`; break - case 'SequenceExpression': text = n.expressions.map((e: any) => formatExpression(e)).join(', '); break + case 'NewExpression': text = `new ${formatExpression(n.callee)}(${n.arguments.map(a => formatExpression(a)).join(', ')})`; break + case 'SequenceExpression': text = n.expressions.map(e => formatExpression(e)).join(', '); break case 'ThisExpression': text = 'this'; break case 'TemplateLiteral': text = '`...`'; break case 'ArrowFunctionExpression': text = '() => {...}'; break @@ -43,14 +62,15 @@ export function parseJS(code: string): acorn.Program { allowReturnOutsideFunction: true, allowAwaitOutsideFunction: true, }) as acorn.Program - } catch (e: any) { - throw new Error(`JavaScript Parse Error at line ${e.loc?.line ?? '?'}: ${e.message}`) + } catch (e) { + const err = e as AcornParseError + throw new Error(`JavaScript Parse Error at line ${err.loc?.line ?? '?'}: ${err.message}`) } } // ── Helper functions ──────────────────────────────────────────────────────── -function processFunctionBody(label: string, endLabel: string, bodyStatements: any[], ctx: TraversalContext): BlockResult { +function processFunctionBody(label: string, endLabel: string, bodyStatements: acorn.Statement[], ctx: TraversalContext): BlockResult { const funcNode = ctx.graph.createNode('subroutine', label, 'rounded') const endNode = ctx.graph.createNode('process', endLabel, 'rounded') const fCtx = ctx.clone() @@ -67,16 +87,20 @@ function processFunctionBody(label: string, endLabel: string, bodyStatements: an return { entry: funcNode, exit: endNode } } -function isBlockFunction(n: any): boolean { +// Narrows to a function expression whose body is a BlockStatement (as +// opposed to a concise arrow body, e.g. `() => x`, which has no block to walk). +function isBlockFunction( + n: acorn.Expression | null | undefined +): n is (acorn.ArrowFunctionExpression | acorn.FunctionExpression) & { body: acorn.BlockStatement } { return !!n && (n.type === 'ArrowFunctionExpression' || n.type === 'FunctionExpression') && n.body?.type === 'BlockStatement' } -function functionLabel(prefix: string, fn: any): string { - const params = fn.params.map((p: any) => formatExpression(p)).join(', ') +function functionLabel(prefix: string, fn: acorn.ArrowFunctionExpression | acorn.FunctionExpression): string { + const params = fn.params.map(p => formatExpression(p)).join(', ') return fn.type === 'ArrowFunctionExpression' ? `${prefix} = (${params}) =>` : `${prefix} = function(${params})` } -function processClassJS(node: any, ctx: TraversalContext): BlockResult { +function processClassJS(node: acorn.ClassDeclaration | acorn.ClassExpression | acorn.AnonymousClassDeclaration, ctx: TraversalContext): BlockResult { const name = node.id?.name ?? 'anonymous' const base = node.superClass ? ` extends ${formatExpression(node.superClass)}` : '' const cls = ctx.graph.createNode('subroutine', `class ${name}${base}`, 'rounded') @@ -85,7 +109,7 @@ function processClassJS(node: any, ctx: TraversalContext): BlockResult { let r: BlockResult | null = null if (m.type === 'MethodDefinition' && m.value?.body) { const key = formatExpression(m.key) - const params = m.value.params.map((p: any) => formatExpression(p)).join(', ') + const params = m.value.params.map(p => formatExpression(p)).join(', ') let label = `${key}(${params})` if (m.kind === 'get') label = `get ${label}` if (m.kind === 'set') label = `set ${label}` @@ -107,7 +131,7 @@ function processClassJS(node: any, ctx: TraversalContext): BlockResult { // ── Statement handlers ─────────────────────────────────────────────────────── -export function processStatement(node: any, ctx: TraversalContext): BlockResult { +export function processStatement(node: AstNode | null, ctx: TraversalContext): BlockResult { if (!node) return { entry: null, exit: null } switch (node.type) { case 'FunctionDeclaration': return processFunction(node, ctx) @@ -151,15 +175,15 @@ export function processStatement(node: any, ctx: TraversalContext): BlockResult } } -function processFunction(node: any, ctx: TraversalContext): BlockResult { +function processFunction(node: acorn.FunctionDeclaration | acorn.AnonymousFunctionDeclaration, ctx: TraversalContext): BlockResult { const name = node.id?.name ?? 'anonymous' - const params = node.params.map((p: any) => formatExpression(p)).join(', ') + const params = node.params.map(p => formatExpression(p)).join(', ') return processFunctionBody(`function ${name}(${params})`, `end ${name}`, node.body.body, ctx) } -function processIf(node: any, ctx: TraversalContext): BlockResult { +function processIf(node: acorn.IfStatement, ctx: TraversalContext): BlockResult { const cond = ctx.graph.createNode('decision', formatExpression(node.test) + '?', 'diamond') - const merge = ctx.graph.createNode('merge' as any, '', 'circle') + const merge = ctx.graph.createNode('merge', '', 'circle') const trueBody = node.consequent.type === 'BlockStatement' ? node.consequent.body : [node.consequent] const trueCtx = ctx.clone(); trueCtx.currentNode = cond @@ -186,16 +210,16 @@ function processIf(node: any, ctx: TraversalContext): BlockResult { return { entry: cond, exit: merge } } -function processFor(node: any, ctx: TraversalContext): BlockResult { +function processFor(node: acorn.ForStatement, ctx: TraversalContext): BlockResult { let initNode: FlowchartNode | null = null if (node.init) { const label = node.init.type === 'VariableDeclaration' - ? node.init.declarations.map((d: any) => `${node.init.kind} ${formatExpression(d.id)} = ${formatExpression(d.init)}`).join(', ') + ? node.init.declarations.map(d => `${(node.init as acorn.VariableDeclaration).kind} ${formatExpression(d.id)} = ${formatExpression(d.init ?? null)}`).join(', ') : formatExpression(node.init) initNode = ctx.graph.createNode('process', label, 'rectangle') } const cond = ctx.graph.createNode('decision', (node.test ? formatExpression(node.test) : 'true') + '?', 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') const update = node.update ? ctx.graph.createNode('process', formatExpression(node.update), 'rectangle') : null if (initNode) ctx.graph.connect(initNode, cond) @@ -218,9 +242,9 @@ function processFor(node: any, ctx: TraversalContext): BlockResult { return { entry: initNode ?? cond, exit: after } } -function processWhile(node: any, ctx: TraversalContext): BlockResult { +function processWhile(node: acorn.WhileStatement, ctx: TraversalContext): BlockResult { const cond = ctx.graph.createNode('decision', formatExpression(node.test) + '?', 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') for (const l of ctx.pendingLabels) ctx.labeledTargets[l] = { break: after, continue: cond } ctx.pendingLabels = [] const lCtx = ctx.clone(); lCtx.currentNode = cond; lCtx.breakTarget = after; lCtx.continueTarget = cond @@ -232,10 +256,10 @@ function processWhile(node: any, ctx: TraversalContext): BlockResult { return { entry: cond, exit: after } } -function processDoWhile(node: any, ctx: TraversalContext): BlockResult { +function processDoWhile(node: acorn.DoWhileStatement, ctx: TraversalContext): BlockResult { const bodyStart = ctx.graph.createNode('process', 'do', 'rounded') const cond = ctx.graph.createNode('decision', formatExpression(node.test) + '?', 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') for (const l of ctx.pendingLabels) ctx.labeledTargets[l] = { break: after, continue: cond } ctx.pendingLabels = [] const lCtx = ctx.clone(); lCtx.currentNode = bodyStart; lCtx.breakTarget = after; lCtx.continueTarget = cond @@ -248,11 +272,11 @@ function processDoWhile(node: any, ctx: TraversalContext): BlockResult { return { entry: bodyStart, exit: after } } -function processForIn(node: any, ctx: TraversalContext): BlockResult { +function processForIn(node: acorn.ForInStatement | acorn.ForOfStatement, ctx: TraversalContext): BlockResult { const left = node.left.type === 'VariableDeclaration' ? `${node.left.kind} ${formatExpression(node.left.declarations[0].id)}` : formatExpression(node.left) const kw = node.type === 'ForOfStatement' ? 'of' : 'in' const cond = ctx.graph.createNode('decision', `${left} ${kw} ${formatExpression(node.right)}?`, 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') for (const l of ctx.pendingLabels) ctx.labeledTargets[l] = { break: after, continue: cond } ctx.pendingLabels = [] const lCtx = ctx.clone(); lCtx.currentNode = cond; lCtx.breakTarget = after; lCtx.continueTarget = cond @@ -263,9 +287,9 @@ function processForIn(node: any, ctx: TraversalContext): BlockResult { return { entry: cond, exit: after } } -function processSwitch(node: any, ctx: TraversalContext): BlockResult { +function processSwitch(node: acorn.SwitchStatement, ctx: TraversalContext): BlockResult { const sw = ctx.graph.createNode('decision', `switch (${formatExpression(node.discriminant)})`, 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') let fallthrough: FlowchartNode | null = null for (const l of ctx.pendingLabels) ctx.labeledTargets[l] = { break: after, continue: null } @@ -285,13 +309,13 @@ function processSwitch(node: any, ctx: TraversalContext): BlockResult { } if (fallthrough) ctx.graph.connect(fallthrough, after) - if (!node.cases.some((c: any) => !c.test)) ctx.graph.connect(sw, after, 'no match') + if (!node.cases.some(c => !c.test)) ctx.graph.connect(sw, after, 'no match') return { entry: sw, exit: after } } -function processTry(node: any, ctx: TraversalContext): BlockResult { +function processTry(node: acorn.TryStatement, ctx: TraversalContext): BlockResult { const tryNode = ctx.graph.createNode('process', 'try', 'rounded') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') // catch/finally nodes are created before the try body is walked so the // body's context can route throw statements to them @@ -312,7 +336,7 @@ function processTry(node: any, ctx: TraversalContext): BlockResult { if (finallyNode) { const fCtx = ctx.clone(); fCtx.currentNode = finallyNode - const fRes = processBlock(node.finalizer.body, fCtx) + const fRes = processBlock(node.finalizer!.body, fCtx) if (fRes.entry) ctx.graph.connect(finallyNode, fRes.entry) ctx.graph.connect(fRes.exit ?? finallyNode, after) } @@ -324,7 +348,7 @@ function processTry(node: any, ctx: TraversalContext): BlockResult { // clones from the outer ctx so a throw inside catch propagates outward, // not back into the same catch const cCtx = ctx.clone(); cCtx.currentNode = catchNode - const cRes = processBlock(node.handler.body.body, cCtx) + const cRes = processBlock(node.handler!.body.body, cCtx) if (cRes.entry) ctx.graph.connect(catchNode, cRes.entry) ctx.graph.connect(cRes.exit ?? catchNode, target) } @@ -332,36 +356,36 @@ function processTry(node: any, ctx: TraversalContext): BlockResult { return { entry: tryNode, exit: after } } -function processReturn(node: any, ctx: TraversalContext): BlockResult { +function processReturn(node: acorn.ReturnStatement, ctx: TraversalContext): BlockResult { const label = node.argument ? `return ${formatExpression(node.argument)}` : 'return' const n = ctx.graph.createNode('process', label, 'rectangle') if (ctx.returnTarget) ctx.graph.connect(n, ctx.returnTarget) return { entry: n, exit: null } } -function processBreak(node: any, ctx: TraversalContext): BlockResult { +function processBreak(node: acorn.BreakStatement, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', node.label ? `break ${node.label.name}` : 'break', 'rectangle') const target = node.label ? ctx.labeledTargets[node.label.name]?.break ?? ctx.breakTarget : ctx.breakTarget if (target) ctx.graph.connect(n, target) return { entry: n, exit: null } } -function processContinue(node: any, ctx: TraversalContext): BlockResult { +function processContinue(node: acorn.ContinueStatement, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', node.label ? `continue ${node.label.name}` : 'continue', 'rectangle') const target = node.label ? ctx.labeledTargets[node.label.name]?.continue ?? ctx.continueTarget : ctx.continueTarget if (target) ctx.graph.connect(n, target) return { entry: n, exit: null } } -function processThrow(node: any, ctx: TraversalContext): BlockResult { +function processThrow(node: acorn.ThrowStatement, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', `throw ${formatExpression(node.argument)}`, 'rectangle') if (ctx.throwTarget) ctx.graph.connect(n, ctx.throwTarget) return { entry: n, exit: null } } -function processVariable(node: any, ctx: TraversalContext): BlockResult { - if (!node.declarations.some((d: any) => isBlockFunction(d.init) || d.init?.type === 'ClassExpression')) { - const decls = node.declarations.map((d: any) => { +function processVariable(node: acorn.VariableDeclaration, ctx: TraversalContext): BlockResult { + if (!node.declarations.some(d => isBlockFunction(d.init) || d.init?.type === 'ClassExpression')) { + const decls = node.declarations.map(d => { const name = formatExpression(d.id) return d.init ? `${name} = ${formatExpression(d.init)}` : name }).join(', ') @@ -376,7 +400,7 @@ function processVariable(node: any, ctx: TraversalContext): BlockResult { const name = formatExpression(d.id) let r: BlockResult if (d.init?.type === 'ClassExpression') { - r = processClassJS({ ...d.init, id: d.init.id ?? d.id }, ctx) + r = processClassJS({ ...d.init, id: d.init.id ?? (d.id as acorn.Identifier) }, ctx) } else if (isBlockFunction(d.init)) { r = processFunctionBody(functionLabel(`${node.kind} ${name}`, d.init), `end ${name}`, d.init.body.body, ctx) } else { @@ -391,7 +415,7 @@ function processVariable(node: any, ctx: TraversalContext): BlockResult { return { entry: first, exit: prev } } -function processExpression(node: any, ctx: TraversalContext): BlockResult { +function processExpression(node: acorn.ExpressionStatement, ctx: TraversalContext): BlockResult { const expr = node.expression if (expr.type === 'AssignmentExpression' && expr.operator === '=' && isBlockFunction(expr.right)) { const target = formatExpression(expr.left) @@ -401,7 +425,7 @@ function processExpression(node: any, ctx: TraversalContext): BlockResult { return { entry: n, exit: n } } -export function processBlock(statements: any[], ctx: TraversalContext): BlockResult { +export function processBlock(statements: AstNode[], ctx: TraversalContext): BlockResult { if (!statements?.length) return { entry: null, exit: ctx.currentNode } let first: FlowchartNode | null = null let current = ctx.currentNode @@ -430,7 +454,7 @@ export function convertJS(code: string): FlowchartGraph { ctx.currentNode = start const ast = parseJS(code) - const r = processBlock((ast as any).body, ctx) + const r = processBlock(ast.body as AstNode[], ctx) graph.connect(start, r.entry ?? end) if (r.exit) graph.connect(r.exit, end) diff --git a/lib/parser/python.ts b/lib/parser/python.ts index 54b0600..5c0226d 100644 --- a/lib/parser/python.ts +++ b/lib/parser/python.ts @@ -1,10 +1,56 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import { FlowchartGraph, TraversalContext, type BlockResult, type FlowchartNode } from './types' import { toLogicalLines, topLevelIndexOf, splitTopLevel } from './python-lines' -// ── Tokenizer ──────────────────────────────────────────────────────────────── +// ── AST node shapes ────────────────────────────────────────────────────────── +// +// This is a hand-rolled, line-regex-based AST (not a real parser), so there's +// no upstream library type to lean on. Each node kind below mirrors exactly +// the object literals `parseLine` constructs and the fields the statement +// handlers below actually read/write. + +interface NodeBase { line: number } + +interface ProgramNode { type: 'Program'; body: PyNode[] } +interface FunctionDefNode extends NodeBase { type: 'FunctionDef'; name: string; params: string; body: PyNode[]; isAsync?: boolean } +interface ClassDefNode extends NodeBase { type: 'ClassDef'; name: string; bases: string; body: PyNode[] } +interface IfNode extends NodeBase { type: 'If'; test: string; body: PyNode[]; orelse: IfNode[]; _elseNode?: ElseNode } +interface ElifNode extends NodeBase { type: 'Elif'; test: string; body: PyNode[] } +interface ElseNode extends NodeBase { type: 'Else'; body: PyNode[] } +interface ForNode extends NodeBase { type: 'For'; target: string; iter: string; body: PyNode[]; isAsync?: boolean; orelse?: ElseNode } +interface WhileNode extends NodeBase { type: 'While'; test: string; body: PyNode[]; orelse?: ElseNode } +interface TryNode extends NodeBase { type: 'Try'; body: PyNode[]; handlers: ExceptHandlerNode[]; finalbody: FinallyNode | null; elsebody?: ElseNode } +interface ExceptHandlerNode extends NodeBase { type: 'ExceptHandler'; exceptionType: string; name: string; body: PyNode[] } +interface FinallyNode extends NodeBase { type: 'Finally'; body: PyNode[] } +interface WithNode extends NodeBase { type: 'With'; items: string; body: PyNode[]; isAsync?: boolean } +interface ReturnNode extends NodeBase { type: 'Return'; value: string } +interface BreakNode extends NodeBase { type: 'Break' } +interface ContinueNode extends NodeBase { type: 'Continue' } +interface PassNode extends NodeBase { type: 'Pass' } +interface RaiseNode extends NodeBase { type: 'Raise'; exception: string } +interface MatchNode extends NodeBase { type: 'Match'; subject: string; cases: CaseNode[]; body: PyNode[] } +interface CaseNode extends NodeBase { type: 'Case'; pattern: string; body: PyNode[] } +interface ExprNode extends NodeBase { type: 'Expr'; value: string } +// `parseLine` never actually produces these (no regex branch matches `assert` +// or `import`) — kept only so `processGeneric`'s defensive checks for them +// stay type-valid rather than provably-unreachable comparisons. +interface AssertNode extends NodeBase { type: 'Assert'; test: string } +interface ImportNode extends NodeBase { type: 'Import'; statement: string } + +type PyNode = + | ProgramNode | FunctionDefNode | ClassDefNode | IfNode | ElifNode | ElseNode + | ForNode | WhileNode | TryNode | ExceptHandlerNode | FinallyNode | WithNode + | ReturnNode | BreakNode | ContinueNode | PassNode | RaiseNode + | MatchNode | CaseNode | ExprNode | AssertNode | ImportNode + +// The subset of node kinds that open a block (i.e. carry a `.body` statement +// list) — used for the parser's indent stack, whose frames always point at +// one of these. +type BlockNode = + | ProgramNode | FunctionDefNode | ClassDefNode | IfNode | ElifNode | ElseNode + | ForNode | WhileNode | TryNode | ExceptHandlerNode | FinallyNode | WithNode + | MatchNode | CaseNode -interface PyNode { type: string; body?: PyNode[]; [key: string]: any } +// ── Tokenizer ──────────────────────────────────────────────────────────────── function parseLine(line: string, lineNum: number): PyNode | null { let m: RegExpMatchArray | null @@ -51,7 +97,7 @@ function parseLine(line: string, lineNum: number): PyNode | null { return { type: 'Expr', value: line, line: lineNum } } -function getLastIf(node: PyNode): PyNode { +function getLastIf(node: IfNode): IfNode { if (node.orelse?.length && node.orelse[node.orelse.length - 1].type === 'If') return getLastIf(node.orelse[node.orelse.length - 1]) return node @@ -59,9 +105,9 @@ function getLastIf(node: PyNode): PyNode { const COMPOUND = /^(?:async\s+)?(if|elif|else|for|while|def|class|try|except|finally|with|match|case)\b/ -export function parsePython(code: string): PyNode { - const ast: PyNode = { type: 'Program', body: [] } - const stack: Array<{ indent: number; node: PyNode; type: string }> = [{ indent: -1, node: ast, type: 'program' }] +export function parsePython(code: string): ProgramNode { + const ast: ProgramNode = { type: 'Program', body: [] } + const stack: Array<{ indent: number; node: BlockNode; type: string }> = [{ indent: -1, node: ast, type: 'program' }] for (const ll of toLogicalLines(code)) { const trimmed = ll.text @@ -75,8 +121,9 @@ export function parsePython(code: string): PyNode { if (COMPOUND.test(trimmed)) { const ci = topLevelIndexOf(trimmed, ':') if (ci !== -1 && ci < trimmed.length - 1) { - // inline suite: `if x: f(); g()` — parse header and remainder separately - node = parseLine(trimmed.slice(0, ci + 1), ll.lineNum) + // inline suite: `if x: f(); g()` — parse header and remainder separately. + // COMPOUND matched, so the header always parses to a block-opening kind. + node = parseLine(trimmed.slice(0, ci + 1), ll.lineNum) as BlockNode | null const rest = trimmed.slice(ci + 1).trim() if (node && rest) { node.body = splitTopLevel(rest, ';') @@ -97,7 +144,7 @@ export function parsePython(code: string): PyNode { const body = parent.node.body ?? [] const last = body[body.length - 1] if (last && node.type === 'Elif' && last.type === 'If') { - const nested: PyNode = { type: 'If', test: node.test, body: node.body ?? [], orelse: [] } + const nested: IfNode = { type: 'If', test: node.test, body: node.body ?? [], orelse: [], line: node.line } const tail = getLastIf(last) tail.orelse = tail.orelse ?? [] tail.orelse.push(nested) @@ -118,7 +165,7 @@ export function parsePython(code: string): PyNode { // Attach except/finally to most recent try if (node.type === 'ExceptHandler' || node.type === 'Finally') { const body = parent.node.body ?? [] - const tryNode = [...body].reverse().find((n: PyNode) => n.type === 'Try') + const tryNode = [...body].reverse().find((n): n is TryNode => n.type === 'Try') if (tryNode) { if (node.type === 'ExceptHandler') tryNode.handlers.push(node) else tryNode.finalbody = node @@ -130,7 +177,7 @@ export function parsePython(code: string): PyNode { // Attach case to most recent match if (node.type === 'Case') { const body = parent.node.body ?? [] - const matchNode = [...body].reverse().find((n: PyNode) => n.type === 'Match') + const matchNode = [...body].reverse().find((n): n is MatchNode => n.type === 'Match') if (matchNode) { matchNode.cases.push(node) if (isBlock) stack.push({ indent, node, type: 'Case' }) @@ -140,7 +187,10 @@ export function parsePython(code: string): PyNode { parent.node.body = parent.node.body ?? [] parent.node.body.push(node) - if (isBlock) stack.push({ indent, node, type: node.type }) + // isBlock is only set for If/For/While/FunctionDef/ClassDef/Try/With/Match + // headers (Elif/Else/ExceptHandler/Finally/Case were handled and + // `continue`d above), all of which are BlockNode kinds. + if (isBlock) stack.push({ indent, node: node as BlockNode, type: node.type }) } return ast @@ -167,7 +217,7 @@ function processStatement(node: PyNode, ctx: TraversalContext): BlockResult { } } -function processFunction(node: PyNode, ctx: TraversalContext): BlockResult { +function processFunction(node: FunctionDefNode, ctx: TraversalContext): BlockResult { const fn = ctx.graph.createNode('subroutine', `${node.isAsync ? 'async ' : ''}def ${node.name}(${node.params})`, 'rounded') const end = ctx.graph.createNode('process', `end ${node.name}`, 'rounded') const fCtx = ctx.clone(); fCtx.currentNode = fn; fCtx.returnTarget = end @@ -179,7 +229,7 @@ function processFunction(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: fn, exit: end } } -function processClass(node: PyNode, ctx: TraversalContext): BlockResult { +function processClass(node: ClassDefNode, ctx: TraversalContext): BlockResult { const label = node.bases ? `class ${node.name}(${node.bases})` : `class ${node.name}` const cls = ctx.graph.createNode('subroutine', label, 'rounded') const cCtx = ctx.clone(); cCtx.currentNode = cls @@ -188,9 +238,9 @@ function processClass(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: cls, exit: r.exit ?? cls } } -function processIf(node: PyNode, ctx: TraversalContext, sharedMerge?: FlowchartNode): BlockResult { +function processIf(node: IfNode, ctx: TraversalContext, sharedMerge?: FlowchartNode): BlockResult { const cond = ctx.graph.createNode('decision', node.test + '?', 'diamond') - const merge = sharedMerge ?? ctx.graph.createNode('merge' as any, '', 'circle') + const merge = sharedMerge ?? ctx.graph.createNode('merge', '', 'circle') const tCtx = ctx.clone(); tCtx.currentNode = cond const tRes = processBlock(node.body ?? [], tCtx) if (tRes.entry) { ctx.graph.connect(cond, tRes.entry, 'Yes'); if (tRes.exit) ctx.graph.connect(tRes.exit, merge) } @@ -219,9 +269,9 @@ function processIf(node: PyNode, ctx: TraversalContext, sharedMerge?: FlowchartN return { entry: cond, exit: merge } } -function processFor(node: PyNode, ctx: TraversalContext): BlockResult { +function processFor(node: ForNode, ctx: TraversalContext): BlockResult { const cond = ctx.graph.createNode('decision', `${node.target} in ${node.iter}?`, 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') const lCtx = ctx.clone(); lCtx.currentNode = cond; lCtx.breakTarget = after; lCtx.continueTarget = cond const r = processBlock(node.body ?? [], lCtx) if (r.entry) { ctx.graph.connect(cond, r.entry, 'Yes'); if (r.exit) ctx.graph.connect(r.exit, cond) } @@ -234,9 +284,9 @@ function processFor(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: cond, exit: after } } -function processWhile(node: PyNode, ctx: TraversalContext): BlockResult { +function processWhile(node: WhileNode, ctx: TraversalContext): BlockResult { const cond = ctx.graph.createNode('decision', node.test + '?', 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') const lCtx = ctx.clone(); lCtx.currentNode = cond; lCtx.breakTarget = after; lCtx.continueTarget = cond const r = processBlock(node.body ?? [], lCtx) if (r.entry) { ctx.graph.connect(cond, r.entry, 'Yes'); if (r.exit) ctx.graph.connect(r.exit, cond) } @@ -249,9 +299,9 @@ function processWhile(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: cond, exit: after } } -function processTry(node: PyNode, ctx: TraversalContext): BlockResult { +function processTry(node: TryNode, ctx: TraversalContext): BlockResult { const tryNode = ctx.graph.createNode('process', 'try', 'rounded') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') // handler nodes are created before the try body is walked so raises can // route to them @@ -300,7 +350,7 @@ function processTry(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: tryNode, exit: after } } -function processWith(node: PyNode, ctx: TraversalContext): BlockResult { +function processWith(node: WithNode, ctx: TraversalContext): BlockResult { const w = ctx.graph.createNode('process', `${node.isAsync ? 'async ' : ''}with ${node.items}`, 'rounded') const wCtx = ctx.clone(); wCtx.currentNode = w const r = processBlock(node.body ?? [], wCtx) @@ -308,9 +358,9 @@ function processWith(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: w, exit: r.exit ?? w } } -function processMatch(node: PyNode, ctx: TraversalContext): BlockResult { +function processMatch(node: MatchNode, ctx: TraversalContext): BlockResult { const match = ctx.graph.createNode('decision', `match ${node.subject}`, 'diamond') - const after = ctx.graph.createNode('merge' as any, '', 'circle') + const after = ctx.graph.createNode('merge', '', 'circle') for (const c of (node.cases ?? [])) { const label = c.pattern === '_' ? 'default' : `case ${c.pattern}` const caseN = ctx.graph.createNode('process', label, 'rectangle') @@ -324,29 +374,33 @@ function processMatch(node: PyNode, ctx: TraversalContext): BlockResult { return { entry: match, exit: after } } -function processReturn(node: PyNode, ctx: TraversalContext): BlockResult { +function processReturn(node: ReturnNode, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', node.value ? `return ${node.value}` : 'return', 'rectangle') if (ctx.returnTarget) ctx.graph.connect(n, ctx.returnTarget) return { entry: n, exit: null } } -function processBreak(node: PyNode, ctx: TraversalContext): BlockResult { +function processBreak(_node: BreakNode, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', 'break', 'rectangle') if (ctx.breakTarget) ctx.graph.connect(n, ctx.breakTarget) return { entry: n, exit: null } } -function processContinue(node: PyNode, ctx: TraversalContext): BlockResult { +function processContinue(_node: ContinueNode, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', 'continue', 'rectangle') if (ctx.continueTarget) ctx.graph.connect(n, ctx.continueTarget) return { entry: n, exit: null } } -function processRaise(node: PyNode, ctx: TraversalContext): BlockResult { +function processRaise(node: RaiseNode, ctx: TraversalContext): BlockResult { const n = ctx.graph.createNode('process', node.exception ? `raise ${node.exception}` : 'raise', 'rectangle') if (ctx.throwTarget) ctx.graph.connect(n, ctx.throwTarget) return { entry: n, exit: null } } function processGeneric(node: PyNode, ctx: TraversalContext): BlockResult { - let label = node.type === 'Assert' ? `assert ${node.test}` : node.type === 'Import' ? node.statement : node.value ?? node.type - if ((label ?? '').length > 60) label = label.substring(0, 57) + '...' + let label: string + if (node.type === 'Assert') label = `assert ${node.test}` + else if (node.type === 'Import') label = node.statement + else if ('value' in node) label = node.value + else label = node.type + if (label.length > 60) label = label.substring(0, 57) + '...' const n = ctx.graph.createNode('process', label, 'rectangle') return { entry: n, exit: n } } diff --git a/lib/parser/typescript.ts b/lib/parser/typescript.ts index 79bb7ff..35c6bdd 100644 --- a/lib/parser/typescript.ts +++ b/lib/parser/typescript.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import * as acorn from 'acorn' import * as acornTypescript from 'acorn-typescript' import { processBlock } from './javascript' @@ -7,9 +6,23 @@ import { FlowchartGraph, TraversalContext } from './types' // Under `import * as x`, TS's CJS interop helper can clobber `.default` with // the whole module object when the source has no `__esModule` marker — the // named `tsPlugin` export is unambiguous across bundlers (webpack vs ts-jest). +// eslint-disable-next-line @typescript-eslint/no-explicit-any -- targeted CJS-interop cast, see comment above const tsPlugin = (acornTypescript as any).tsPlugin as typeof import('acorn-typescript').tsPlugin -const TSParser = acorn.Parser.extend(tsPlugin() as any) +// acorn-typescript's plugin factory returns a parser mixin typed against its +// own internal `AcornParseClass` (see its middleware.d.ts), which acorn's +// `Parser.extend` signature doesn't structurally recognize — a real type +// mismatch between the two packages' own .d.ts files, not something this +// module can resolve without patching either library. +type ExtendPlugin = Parameters[0] +const TSParser = acorn.Parser.extend(tsPlugin() as unknown as ExtendPlugin) + +// A parse error thrown by acorn/acorn-typescript: a SyntaxError-shaped +// object with a non-standard `loc` position attached. +interface AcornParseError { + message: string + loc?: { line: number; column: number } | null +} function parseTSCode(code: string): acorn.Program { try { @@ -19,9 +32,10 @@ function parseTSCode(code: string): acorn.Program { locations: true, allowReturnOutsideFunction: true, allowAwaitOutsideFunction: true, - } as any) as unknown as acorn.Program - } catch (e: any) { - throw new Error(`TypeScript Parse Error at line ${e.loc?.line ?? '?'}: ${e.message}`) + } as acorn.Options) as unknown as acorn.Program + } catch (e) { + const err = e as AcornParseError + throw new Error(`TypeScript Parse Error at line ${err.loc?.line ?? '?'}: ${err.message}`) } } @@ -33,7 +47,7 @@ export function convertTS(code: string): FlowchartGraph { ctx.currentNode = start const ast = parseTSCode(code) - const r = processBlock((ast as any).body, ctx) + const r = processBlock(ast.body as Parameters[0], ctx) graph.connect(start, r.entry ?? end) if (r.exit) graph.connect(r.exit, end) From d7aa46467fb74867aa61a45554a7310eee180138 Mon Sep 17 00:00:00 2001 From: Emp1500 Date: Mon, 13 Jul 2026 09:50:33 +0000 Subject: [PATCH 5/5] perf: defer Monaco/Mermaid loading behind next/dynamic with loading states --- components/editor/CodeEditor.tsx | 8 +++++++- components/editor/FlowchartPanel.tsx | 24 +++++++++++++++++++----- components/share/ShareView.tsx | 7 ++++++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/components/editor/CodeEditor.tsx b/components/editor/CodeEditor.tsx index 49067ff..d0a177e 100644 --- a/components/editor/CodeEditor.tsx +++ b/components/editor/CodeEditor.tsx @@ -1,5 +1,6 @@ 'use client' -import MonacoEditor, { loader } from '@monaco-editor/react' +import dynamic from 'next/dynamic' +import { loader } from '@monaco-editor/react' import type { editor } from 'monaco-editor' import type { SupportedLanguage } from '@/lib/parser' @@ -8,6 +9,11 @@ import type { SupportedLanguage } from '@/lib/parser' // app's CSP (script-src 'self') blocks. loader.config({ paths: { vs: '/monaco/min/vs' } }) +const MonacoEditor = dynamic(() => import('@monaco-editor/react').then(m => m.default), { + ssr: false, + loading: () =>
Loading editor…
, +}) + interface Props { value: string language: SupportedLanguage diff --git a/components/editor/FlowchartPanel.tsx b/components/editor/FlowchartPanel.tsx index a09f327..8439f34 100644 --- a/components/editor/FlowchartPanel.tsx +++ b/components/editor/FlowchartPanel.tsx @@ -1,8 +1,19 @@ 'use client' import { useEffect, useRef, useState } from 'react' -import mermaid from 'mermaid' +import type MermaidType from 'mermaid' -mermaid.initialize({ startOnLoad: false, theme: 'dark', flowchart: { useMaxWidth: true, curve: 'basis' } }) +// Deferred so `mermaid` isn't bundled into the initial route chunk — it's +// only fetched once this panel actually mounts and renders a diagram. +let mermaidPromise: Promise | null = null +function loadMermaid() { + if (!mermaidPromise) { + mermaidPromise = import('mermaid').then(m => { + m.default.initialize({ startOnLoad: false, theme: 'dark', flowchart: { useMaxWidth: true, curve: 'basis' } }) + return m.default + }) + } + return mermaidPromise +} interface Props { mermaidCode: string @@ -16,10 +27,13 @@ export function FlowchartPanel({ mermaidCode, panelRef }: Props) { useEffect(() => { if (!mermaidCode) return + let cancelled = false const id = `mermaid-${Date.now()}-${idRef.current++}` - mermaid.render(id, mermaidCode) - .then(({ svg }) => { setSvg(svg); setError('') }) - .catch(err => setError(err.message)) + loadMermaid() + .then(mermaid => mermaid.render(id, mermaidCode)) + .then(({ svg }) => { if (!cancelled) { setSvg(svg); setError('') } }) + .catch(err => { if (!cancelled) setError(err.message) }) + return () => { cancelled = true } }, [mermaidCode]) return ( diff --git a/components/share/ShareView.tsx b/components/share/ShareView.tsx index acf1274..65917c2 100644 --- a/components/share/ShareView.tsx +++ b/components/share/ShareView.tsx @@ -1,7 +1,7 @@ 'use client' import { useEffect, useRef, useState } from 'react' import { useRouter } from 'next/navigation' -import MonacoEditor from '@monaco-editor/react' +import dynamic from 'next/dynamic' import { toPng } from 'html-to-image' import { codeToMermaid } from '@/lib/parser' import type { SupportedLanguage } from '@/lib/parser' @@ -10,6 +10,11 @@ import { EditorLayout } from '@/components/editor/EditorLayout' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' +const MonacoEditor = dynamic(() => import('@monaco-editor/react').then(m => m.default), { + ssr: false, + loading: () =>
Loading editor…
, +}) + interface Props { flowchart: { id: string; title: string; language: string; code: string; share_id: string | null } currentUserId: string | null