diff --git a/.gitea/README.md b/.gitea/README.md new file mode 100644 index 0000000..8471c1f --- /dev/null +++ b/.gitea/README.md @@ -0,0 +1,562 @@ +# Gitea Actions CI/CD Setup + +This document describes the CI/CD pipeline configuration for the GlyphDiff project using Gitea Actions (GitHub Actions compatible). + +## Table of Contents + +- [Overview](#overview) +- [Workflow Files](#workflow-files) +- [Workflow Triggers](#workflow-triggers) +- [Setup Instructions](#setup-instructions) +- [Self-Hosted Runner Setup](#self-hosted-runner-setup) +- [Caching Strategy](#caching-strategy) +- [Environment Variables](#environment-variables) +- [Troubleshooting](#troubleshooting) + +## Overview + +The CI/CD pipeline consists of four main workflows: + +1. **Lint** - Code quality checks (oxlint, dprint formatting) +2. **Test** - Type checking and E2E tests (Playwright) +3. **Build** - Production build verification +4. **Deploy** - Deployment automation (optional/template) + +All workflows are designed to run on both push and pull request events, with appropriate branch filtering and concurrency controls. + +## Workflow Files + +### `.gitea/workflows/lint.yml` + +**Purpose**: Run code quality checks to ensure code style and formatting standards. + +**Checks performed**: + +- `oxlint` - Fast JavaScript/TypeScript linter +- `dprint check` - Code formatting verification + +**Triggers**: + +- Push to `main`, `develop`, `feature/*` branches +- Pull requests to `main` or `develop` +- Manual workflow dispatch + +**Cache**: Node modules and Yarn cache + +**Concurrency**: Cancels in-progress runs for the same branch when a new commit is pushed. + +--- + +### `.gitea/workflows/test.yml` + +**Purpose**: Run type checking and end-to-end tests. + +**Jobs**: + +#### 1. `type-check` job + +- `tsc --noEmit` - TypeScript type checking +- `svelte-check --threshold warning` - Svelte component type checking + +#### 2. `e2e-tests` job + +- Installs Playwright browsers with system dependencies +- Runs E2E tests using Playwright +- Uploads test report artifacts (retained for 7 days) +- Uploads screenshots on test failure for debugging + +**Triggers**: Same as lint workflow + +**Cache**: Node modules and Yarn cache + +**Artifacts**: + +- `playwright-report` - Test execution report +- `playwright-screenshots` - Screenshots from failed tests + +--- + +### `.gitea/workflows/build.yml` + +**Purpose**: Verify that the production build completes successfully. + +**Steps**: + +1. Checkout repository +2. Setup Node.js v20 with Yarn caching +3. Install dependencies with `--frozen-lockfile` +4. Run `svelte-kit sync` to prepare SvelteKit +5. Build the project with `NODE_ENV=production` +6. Upload build artifacts (`.svelte-kit/output`, `.svelte-kit/build`) +7. Run the preview server and verify it responds (health check) + +**Triggers**: + +- Push to `main` or `develop` branches +- Pull requests to `main` or `develop` +- Manual workflow dispatch + +**Cache**: Node modules and Yarn cache + +**Artifacts**: + +- `build-artifacts` - Compiled SvelteKit output (retained for 7 days) + +--- + +### `.gitea/workflows/deploy.yml` + +**Purpose**: Automated deployment pipeline (template configuration). + +**Current state**: Placeholder configuration. Uncomment and customize one of the deployment examples. + +**Pre-deployment checks**: + +- Must pass linting workflow +- Must pass testing workflow +- Must pass build workflow + +**Deployment examples included**: + +1. **Docker container registry** - Build and push Docker image +2. **SSH deployment** - Deploy to server via SSH +3. **Vercel** - Deploy to Vercel platform + +**Triggers**: + +- Push to `main` branch +- Manual workflow dispatch with environment selection (staging/production) + +**Secrets required** (configure in Gitea): + +- For Docker: `REGISTRY_URL`, `REGISTRY_USERNAME`, `REGISTRY_PASSWORD` +- For SSH: `DEPLOY_HOST`, `DEPLOY_USER`, `DEPLOY_SSH_KEY` +- For Vercel: `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID` + +## Workflow Triggers + +### Branch-Specific Behavior + +| Workflow | Push Triggers | PR Triggers | Runs on Merge | +| -------- | ------------------------------ | -------------------- | ------------- | +| Lint | `main`, `develop`, `feature/*` | To `main`, `develop` | Yes | +| Test | `main`, `develop`, `feature/*` | To `main`, `develop` | Yes | +| Build | `main`, `develop` | To `main`, `develop` | Yes | +| Deploy | `main` only | None | Yes | + +### Concurrency Strategy + +All workflows use concurrency groups based on the workflow name and branch reference: + +```yaml +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true # or false for deploy workflow +``` + +This ensures: + +- For lint/test/build: New commits cancel in-progress runs (saves resources) +- For deploy: Prevents concurrent deployments (ensures safety) + +## Setup Instructions + +### Step 1: Verify Gitea Actions is Enabled + +1. Navigate to your Gitea instance +2. Go to **Site Administration** → **Actions** +3. Ensure Actions is enabled +4. Configure default runner settings if needed + +### Step 2: Configure Repository Settings + +1. Go to your repository in Gitea +2. Click **Settings** → **Actions** +3. Enable Actions for the repository if not already enabled +4. Set appropriate permissions for read/write access + +### Step 3: Push Workflows to Repository + +The workflow files are already in `.gitea/workflows/`. Commit and push them: + +```bash +git add .gitea/workflows/ +git commit -m "Add Gitea Actions CI/CD workflows" +git push origin main +``` + +### Step 4: Verify Workflows Run + +1. Navigate to **Actions** tab in your repository +2. You should see the workflows trigger on the next push +3. Click into a workflow run to view logs and status + +### Step 5: Configure Secrets (Optional - for deployment) + +1. Go to repository **Settings** → **Secrets** → **Actions** +2. Click **Add New Secret** +3. Add secrets required for your deployment method + +Example secrets for SSH deployment: + +``` +DEPLOY_HOST=your-server.com +DEPLOY_USER=deploy +DEPLOY_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY----- +... +-----END OPENSSH PRIVATE KEY----- +``` + +## Self-Hosted Runner Setup + +### Option 1: Using Gitea's Built-in Act Runner (Recommended) + +Gitea provides `act_runner` (compatible with GitHub Actions runner). + +#### Install act_runner + +On Linux (Debian/Ubuntu): + +```bash +wget -O /usr/local/bin/act_runner https://gitea.com/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64 +chmod +x /usr/local/bin/act_runner +``` + +Verify installation: + +```bash +act_runner --version +``` + +#### Register the Runner + +1. In Gitea, navigate to repository **Settings** → **Actions** → **Runners** +2. Click **New Runner** +3. Copy the registration token +4. Run the registration command: + +```bash +act_runner register \ + --instance https://your-gitea-instance.com \ + --token YOUR_REGISTRATION_TOKEN \ + --name "linux-runner-1" \ + --labels ubuntu-latest,linux,docker \ + --no-interactive +``` + +#### Start the Runner as a Service + +Create a systemd service file at `/etc/systemd/system/gitea-runner.service`: + +```ini +[Unit] +Description=Gitea Actions Runner +After=network.target + +[Service] +Type=simple +User=git +WorkingDirectory=/var/lib/gitea-runner +ExecStart=/usr/local/bin/act_runner daemon +Restart=always +RestartSec=5s + +[Install] +WantedBy=multi-user.target +``` + +Enable and start the service: + +```bash +sudo systemctl daemon-reload +sudo systemctl enable gitea-runner +sudo systemctl start gitea-runner +``` + +#### Check Runner Status + +```bash +sudo systemctl status gitea-runner +``` + +Verify in Gitea: The runner should appear as **Online** with the `ubuntu-latest` label. + +### Option 2: Using Self-Hosted Runners with Docker + +If you prefer Docker-based execution: + +#### Install Docker + +```bash +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh +sudo usermod -aG docker $USER +``` + +#### Configure Runner to Use Docker + +Ensure the runner has access to the Docker socket: + +```bash +sudo usermod -aG docker act_runner_user +``` + +The workflows will now run containers inside the runner's Docker environment. + +### Option 3: Using External Runners (GitHub Actions Runner Compatible) + +If you want to use standard GitHub Actions runners: + +```bash +# Download and configure GitHub Actions runner +mkdir actions-runner && cd actions-runner +curl -o actions-runner-linux-x64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz +tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz + +# Configure to point to Gitea instance +./config.sh --url https://your-gitea-instance.com --token YOUR_TOKEN +``` + +## Caching Strategy + +### Node.js and Yarn Cache + +All workflows use `actions/setup-node@v4` with built-in caching: + +```yaml +- name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' +``` + +This caches: + +- `node_modules` directory +- Yarn cache directory (`~/.yarn/cache`) +- Reduces installation time from minutes to seconds on subsequent runs + +### Playwright Cache + +Playwright browsers are installed fresh each time. To cache Playwright (optional optimization): + +```yaml +- name: Cache Playwright binaries + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-playwright- +``` + +## Environment Variables + +### Default Environment Variables + +The workflows use the following environment variables: + +```bash +NODE_ENV=production # For build workflow +NODE_VERSION=20 # Node.js version used across all workflows +``` + +### Custom Environment Variables + +To add custom environment variables: + +1. Go to repository **Settings** → **Variables** → **Actions** +2. Click **Add New Variable** +3. Add variable name and value +4. Set scope (environment, repository, or organization) + +Example for feature flags: + +``` +ENABLE_ANALYTICS=false +API_URL=https://api.example.com +``` + +Access in workflow: + +```yaml +env: + API_URL: ${{ vars.API_URL }} + ENABLE_ANALYTICS: ${{ vars.ENABLE_ANALYTICS }} +``` + +## Troubleshooting + +### Workflows Not Running + +**Symptoms**: Workflows don't appear or don't trigger + +**Solutions**: + +1. Verify Actions is enabled in Gitea site administration +2. Check repository Settings → Actions is enabled +3. Verify workflow files are in `.gitea/workflows/` directory +4. Check workflow YAML syntax (no indentation errors) + +### Runner Offline + +**Symptoms**: Runner shows as **Offline** or **Idle** + +**Solutions**: + +1. Check runner service status: `sudo systemctl status gitea-runner` +2. Review runner logs: `journalctl -u gitea-runner -f` +3. Verify network connectivity to Gitea instance +4. Restart runner: `sudo systemctl restart gitea-runner` + +### Linting Fails with Formatting Errors + +**Symptoms**: `dprint check` fails on CI but passes locally + +**Solutions**: + +1. Ensure dprint configuration (`dprint.json`) is committed +2. Run `yarn dprint fmt` locally before committing +3. Consider adding auto-fix workflow (see below) + +### Playwright Tests Timeout + +**Symptoms**: E2E tests fail with timeout errors + +**Solutions**: + +1. Check `playwright.config.ts` timeout settings +2. Ensure preview server starts before tests run (built into config) +3. Increase timeout in workflow: + ```yaml + - name: Run Playwright tests + run: yarn test:e2e + env: + PLAYWRIGHT_TIMEOUT: 60000 + ``` + +### Build Fails with Out of Memory + +**Symptoms**: Build fails with memory allocation errors + +**Solutions**: + +1. Increase Node.js memory limit: + ```yaml + - name: Build project + run: yarn build + env: + NODE_OPTIONS: --max-old-space-size=4096 + ``` +2. Ensure runner has sufficient RAM (minimum 2GB recommended) + +### Permission Denied on Runner + +**Symptoms**: Runner can't access repository or secrets + +**Solutions**: + +1. Verify runner has read access to repository +2. Check secret names match exactly in workflow +3. Ensure runner user has file system permissions + +### Yarn Install Fails with Lockfile Conflict + +**Symptoms**: `yarn install --frozen-lockfile` fails + +**Solutions**: + +1. Ensure `yarn.lock` is up-to-date locally +2. Run `yarn install` and commit updated `yarn.lock` +3. Do not use `--frozen-lockfile` if using different platforms (arm64 vs amd64) + +### Slow Workflow Execution + +**Symptoms**: Workflows take too long to complete + +**Solutions**: + +1. Verify caching is working (check logs for "Cache restored") +2. Use `--frozen-lockfile` for faster dependency resolution +3. Consider matrix strategy for parallel execution (not currently used) +4. Optimize Playwright tests (reduce test count, increase timeouts only if needed) + +## Best Practices + +### 1. Keep Dependencies Updated + +Regularly update action versions: + +```yaml +- uses: actions/checkout@v4 # Update from v3 to v4 when available +- uses: actions/setup-node@v4 +``` + +### 2. Use Frozen Lockfile + +Always use `--frozen-lockfile` in CI to ensure reproducible builds: + +```bash +yarn install --frozen-lockfile +``` + +### 3. Monitor Workflow Status + +Set up notifications for workflow failures: + +- Email notifications in Gitea user settings +- Integrate with Slack/Mattermost for team alerts +- Use status badges in README + +### 4. Test Locally Before Pushing + +Run the same checks locally: + +```bash +yarn lint # oxlint +yarn dprint check # Formatting check +yarn tsc --noEmit # Type check +yarn test:e2e # E2E tests +yarn build # Build +``` + +### 5. Leverage Git Hooks + +The project uses lefthook for pre-commit/pre-push checks. This catches issues before they reach CI: + +```bash +# Pre-commit: Format code, lint staged files +# Pre-push: Full type check, format check, full lint +``` + +## Additional Resources + +- [Gitea Actions Documentation](https://docs.gitea.com/usage/actions/overview) +- [Gitea act_runner Documentation](https://docs.gitea.com/usage/actions/act-runner) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +- [SvelteKit Deployment Guide](https://kit.svelte.dev/docs/adapters) +- [Playwright CI/CD Guide](https://playwright.dev/docs/ci) + +## Status Badges + +Add status badges to your README.md: + +```markdown +![Lint](https://your-gitea-instance.com/username/glyphdiff/actions/badges/workflow/lint.yml/badge.svg) +![Test](https://your-gitea-instance.com/username/glyphdiff/actions/badges/workflow/test.yml/badge.svg) +![Build](https://your-gitea-instance.com/username/glyphdiff/actions/badges/workflow/build.yml/badge.svg) +``` + +## Next Steps + +1. **Customize deployment**: Modify `deploy.yml` with your deployment strategy +2. **Add notifications**: Set up workflow failure notifications +3. **Optimize caching**: Add Playwright cache if needed +4. **Add badges**: Include status badges in README +5. **Schedule tasks**: Add periodic tests or dependency updates (optional) + +--- + +**Last Updated**: December 30, 2025 +**Version**: 1.0.0 diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..64d1182 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,32 @@ +name: Build +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install + run: yarn install --frozen-lockfile --prefer-offline + + - name: Build Svelte App + run: yarn build + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: dist/ + retention-days: 7 diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..0ef1c15 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,42 @@ +name: Deploy Pipeline +on: + push: + branches: [main] + workflow_dispatch: + inputs: + environment: + description: 'Target' + required: true + default: 'production' + type: choice + options: [staging, production] + +jobs: + pipeline: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install + run: yarn install --frozen-lockfile --prefer-offline + + - name: Validation + run: | + yarn oxlint . + yarn svelte-check + + - name: Build for Production + run: yarn build + env: + NODE_ENV: production + + - name: Deploy Step + run: | + echo "Deploying dist/ to ${{ github.event.inputs.environment || 'production' }}..." + # EXAMPLE: rsync -avz dist/ user@your-vps:/var/www/html/ diff --git a/.gitea/workflows/lint.yml b/.gitea/workflows/lint.yml new file mode 100644 index 0000000..bb9c2c3 --- /dev/null +++ b/.gitea/workflows/lint.yml @@ -0,0 +1,48 @@ +name: Lint + +on: + push: + branches: + - main + - develop + - feature/* + pull_request: + branches: + - main + - develop + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint Code + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Persistent Yarn Cache + uses: actions/cache@v4 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies + run: yarn install --frozen-lockfile --prefer-offline diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml new file mode 100644 index 0000000..63b0077 --- /dev/null +++ b/.gitea/workflows/test.yml @@ -0,0 +1,69 @@ +name: Test +on: + push: + branches: [main, develop, "feature/*"] + pull_request: + branches: [main, develop] + workflow_dispatch: + +jobs: + test: + name: Svelte Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install + run: yarn install --frozen-lockfile --prefer-offline + + - name: Type Check + run: yarn svelte-check --threshold warning + + - name: Lint + run: yarn oxlint . + + # e2e-tests: + # name: E2E Tests (Playwright) + # runs-on: ubuntu-latest + # + # steps: + # - name: Checkout repository + # uses: actions/checkout@v4 + # + # - name: Setup Node.js + # uses: actions/setup-node@v4 + # with: + # node-version: '20' + # cache: 'yarn' + # + # - name: Install dependencies + # run: yarn install --frozen-lockfile + # + # - name: Install Playwright browsers + # run: yarn playwright install --with-deps + # + # - name: Run Playwright tests + # run: yarn test:e2e + # + # - name: Upload Playwright report + # if: always() + # uses: actions/upload-artifact@v4 + # with: + # name: playwright-report + # path: playwright-report/ + # retention-days: 7 + # + # - name: Upload Playwright screenshots (on failure) + # if: failure() + # uses: actions/upload-artifact@v4 + # with: + # name: playwright-screenshots + # path: test-results/ + # retention-days: 7 + # + # Note: E2E tests are disabled until Playwright setup is complete. + # Uncomment this job section when Playwright tests are ready to run. diff --git a/.gitignore b/.gitignore index d19106e..7e94f3d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ node_modules .wrangler /.svelte-kit /build +/dist # OS .DS_Store diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 7f625d0..ef90f75 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..ddd2d2c --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + glyphdiff + + +
+ + + diff --git a/lefthook.yml b/lefthook.yml index 4f98201..668f877 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -20,7 +20,9 @@ pre-push: run: yarn svelte-check --threshold warning format-check: - run: yarn dprint check + glob: "*.{ts,js,svelte,json,md}" + run: yarn dprint check {push_files} lint-full: - run: yarn oxlint . + glob: "*.{ts,js,svelte}" + run: yarn oxlint {push_files} diff --git a/package.json b/package.json index 77078a6..43560de 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,12 @@ "version": "0.0.1", "type": "module", "scripts": { - "dev": "vite dev", + "dev": "vite", "build": "vite build", "preview": "vite preview", - "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "prepare": "svelte-check --tsconfig ./tsconfig.json || echo ''", + "check": "svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", "lint": "oxlint", "format": "dprint fmt", "format:check": "dprint check", @@ -19,8 +19,6 @@ "devDependencies": { "@lucide/svelte": "^0.562.0", "@playwright/test": "^1.57.0", - "@sveltejs/adapter-auto": "^7.0.0", - "@sveltejs/kit": "^2.49.1", "@sveltejs/vite-plugin-svelte": "^6.2.1", "@tailwindcss/vite": "^4.1.18", "clsx": "^2.1.1", diff --git a/playwright.config.ts b/playwright.config.ts index 999bd03..e6c534f 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,6 +1,6 @@ import { defineConfig } from '@playwright/test'; export default defineConfig({ - webServer: { command: 'npm run build && npm run preview', port: 4173 }, + webServer: { command: 'yarn build && yarn preview', port: 4173 }, testDir: 'e2e', }); diff --git a/src/App.svelte b/src/App.svelte new file mode 100644 index 0000000..c447756 --- /dev/null +++ b/src/App.svelte @@ -0,0 +1,20 @@ + + + + + + +
+ +
+ + diff --git a/src/ambient.d.ts b/src/ambient.d.ts new file mode 100644 index 0000000..68c306f --- /dev/null +++ b/src/ambient.d.ts @@ -0,0 +1,20 @@ +declare module '*.svelte' { + import type { ComponentType } from 'svelte'; + const component: ComponentType; + export default component; +} + +declare module '*.svg' { + const content: string; + export default content; +} + +declare module '*.png' { + const content: string; + export default content; +} + +declare module '*.jpg' { + const content: string; + export default content; +} diff --git a/src/app.d.ts b/src/app.d.ts deleted file mode 100644 index d76242a..0000000 --- a/src/app.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -// See https://svelte.dev/docs/kit/types#app.d.ts -// for information about these interfaces -declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface PageState {} - // interface Platform {} - } -} - -export {}; diff --git a/src/app.html b/src/app.html deleted file mode 100644 index 1966776..0000000 --- a/src/app.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/src/lib/types/collection.ts b/src/lib/types/collection.ts new file mode 100644 index 0000000..79d4960 --- /dev/null +++ b/src/lib/types/collection.ts @@ -0,0 +1,21 @@ +/** + * Generic collection API response model + * Use this for APIs that return collections of items + * + * @template T - The type of items in the collection array + * @template K - The key used to access the collection array in the response + */ +export type CollectionApiModel = Record & { + /** + * Number of items returned in the current page/response + */ + count: number; + /** + * Total number of items available across all pages + */ + count_total: number; + /** + * Indicates if there are more items available beyond this page + */ + has_more: boolean; +}; diff --git a/src/lib/types/common.ts b/src/lib/types/common.ts new file mode 100644 index 0000000..2c1f8c8 --- /dev/null +++ b/src/lib/types/common.ts @@ -0,0 +1,37 @@ +/** + * Model of response with error + */ +export interface ApiErrorResponse { + /** + * Error text + */ + error: string; + /** + * Status + */ + status: number; + /** + * Status text + */ + statusText: string; +} + +/** + * Model of response with success + */ +export interface ApiSuccessResponse { + /** + * Data + */ + data: T; + /** + * Status + */ + status: number; + /** + * Status text + */ + statusText: string; +} + +export type ApiResponse = ApiErrorResponse | ApiSuccessResponse; diff --git a/src/lib/types/fontshare_fonts.ts b/src/lib/types/fontshare_fonts.ts new file mode 100644 index 0000000..9a407bf --- /dev/null +++ b/src/lib/types/fontshare_fonts.ts @@ -0,0 +1,439 @@ +import type { CollectionApiModel } from './collection'; + +/** + * Model of Fontshare API response + * @see https://fontshare.com + */ +export type FontshareApiModel = CollectionApiModel; + +/** + * Individual font metadata from Fontshare API + */ +export interface FontshareFont { + /** + * Unique identifier for the font + * UUID v4 format (e.g., "20e9fcdc-1e41-4559-a43d-1ede0adc8896") + */ + id: string; + + /** + * Display name of the font family + * Examples: "Satoshi", "General Sans", "Clash Display" + */ + name: string; + + /** + * Native/localized name of the font (if available) + * Often null for Latin-script fonts + */ + native_name: string | null; + + /** + * URL-friendly identifier for the font + * Used in URLs: e.g., "satoshi", "general-sans", "clash-display" + */ + slug: string; + + /** + * Font category classification + * Examples: "Sans", "Serif", "Display", "Script" + */ + category: string; + + /** + * Script/writing system supported by the font + * Examples: "latin", "arabic", "devanagari" + */ + script: string; + + /** + * Font publisher/foundry information + */ + publisher: FontsharePublisher; + + /** + * Array of designers who created this font + * Multiple designers may have collaborated on a single font + */ + designers: FontshareDesigner[]; + + /** + * Related font families (if any) + * Often null, as fonts are typically independent + */ + related_families: string | null; + + /** + * Whether to display publisher as the designer instead of individual designers + */ + display_publisher_as_designer: boolean; + + /** + * Whether trial downloads are enabled for this font + */ + trials_enabled: boolean; + + /** + * Whether to show Latin-specific metrics + */ + show_latin_metrics: boolean; + + /** + * Type of license for this font + * Examples: "itf_ffl" (ITF Free Font License) + */ + license_type: string; + + /** + * Comma-separated list of languages supported by this font + * Example: "Afar, Afrikaans, Albanian, Aranese, Aromanian, Aymara, ..." + */ + languages: string; + + /** + * ISO 8601 timestamp when the font was added to Fontshare + * Format: "2021-03-12T20:49:05Z" + */ + inserted_at: string; + + /** + * HTML-formatted story/description about the font + * Contains marketing text, design philosophy, and usage recommendations + */ + story: string; + + /** + * Version of the font family + * Format: "1.0", "1.2", etc. + */ + version: string; + + /** + * Total number of times this font has been viewed + */ + views: number; + + /** + * Number of views in the recent time period + */ + views_recent: number; + + /** + * Whether this font is marked as "hot"/trending + */ + is_hot: boolean; + + /** + * Whether this font is marked as new + */ + is_new: boolean; + + /** + * Whether this font is in the shortlisted collection + */ + is_shortlisted: boolean | null; + + /** + * Whether this font is marked as top/popular + */ + is_top: boolean; + + /** + * Variable font axes (for variable fonts) + * Empty array [] for static fonts + */ + axes: FontshareAxis[]; + + /** + * Tags/categories for this font + * Examples: ["Magazines", "Branding", "Logos", "Posters"] + */ + font_tags: FontshareTag[]; + + /** + * OpenType features available in this font + */ + features: FontshareFeature[]; + + /** + * Array of available font styles/variants + * Each style represents a different font file (weight, italic, variable) + */ + styles: FontshareStyle[]; +} + +/** + * Publisher/foundry information + */ +export interface FontsharePublisher { + /** + * Description/bio of the publisher + * Example: "Indian Type Foundry (ITF) creates retail and custom multilingual fonts..." + */ + bio: string; + + /** + * Publisher email (if available) + */ + email: string | null; + + /** + * Unique publisher identifier + * UUID format + */ + id: string; + + /** + * Publisher links (social media, website, etc.) + */ + links: FontshareLink[]; + + /** + * Publisher name + * Example: "Indian Type Foundry" + */ + name: string; +} + +/** + * Designer information + */ +export interface FontshareDesigner { + /** + * Designer bio/description + */ + bio: string; + + /** + * Designer links (Twitter, website, etc.) + */ + links: FontshareLink[]; + + /** + * Designer name + */ + name: string; +} + +/** + * Link information + */ +export interface FontshareLink { + /** + * Name of the link platform/site + * Examples: "Twitter", "GitHub", "Website" + */ + name: string; + + /** + * URL of the link (may be null) + */ + url: string | null; +} + +/** + * Font tag/category + */ +export interface FontshareTag { + /** + * Tag name + * Examples: "Magazines", "Branding", "Logos", "Posters" + */ + name: string; +} + +/** + * OpenType feature + */ +export interface FontshareFeature { + /** + * Feature name (descriptive name or null) + * Examples: "Alternate t", "All Alternates", or null + */ + name: string | null; + + /** + * Whether this feature is on by default + */ + on_by_default: boolean; + + /** + * OpenType feature tag (4-character code) + * Examples: "ss01", "frac", "liga", "aalt", "case" + */ + tag: string; +} + +/** + * Variable font axis (for variable fonts) + * Defines the range and properties of a variable font axis (e.g., weight) + */ +export interface FontshareAxis { + /** + * Name of the axis + * Example: "wght" (weight axis) + */ + name: string; + + /** + * CSS property name for the axis + * Example: "wght" + */ + property: string; + + /** + * Default value for the axis + * Example: 420.0, 650.0, 700.0 + */ + range_default: number; + + /** + * Minimum value for the axis + * Example: 300.0, 100.0, 200.0 + */ + range_left: number; + + /** + * Maximum value for the axis + * Example: 900.0, 700.0, 800.0 + */ + range_right: number; +} + +/** + * Individual font style/variant + * Each style represents a single downloadable font file + */ +export interface FontshareStyle { + /** + * Unique identifier for this style + * UUID format + */ + id: string; + + /** + * Whether this is the default style for the font family + * Typically, one style per font is marked as default + */ + default: boolean; + + /** + * CDN URL to the font file + * Protocol-relative URL: "//cdn.fontshare.com/wf/..." + * Note: URL starts with "//" (protocol-relative), may need protocol prepended + */ + file: string; + + /** + * Whether this style is italic + * false for upright, true for italic styles + */ + is_italic: boolean; + + /** + * Whether this is a variable font + * Variable fonts have adjustable axes (weight, slant, etc.) + */ + is_variable: boolean; + + /** + * Typography properties for this style + * Contains measurements like cap height, x-height, ascenders/descenders + * May be empty object {} for some styles + */ + properties: FontshareStyleProperties | Record; + + /** + * Weight information for this style + */ + weight: FontshareWeight; +} + +/** + * Typography/measurement properties for a font style + */ +export interface FontshareStyleProperties { + /** + * Distance from baseline to the top of ascenders + * Example: 1010, 990, 1000 + */ + ascending_leading: number | null; + + /** + * Height of uppercase letters (cap height) + * Example: 710, 680, 750 + */ + cap_height: number | null; + + /** + * Distance from baseline to the bottom of descenders (negative value) + * Example: -203, -186, -220 + */ + descending_leading: number | null; + + /** + * Body height of the font + * Often null in Fontshare data + */ + body_height: number | null; + + /** + * Maximum character width in the font + * Example: 1739, 1739, 1739 + */ + max_char_width: number | null; + + /** + * Height of lowercase x-height + * Example: 480, 494, 523 + */ + x_height: number | null; + + /** + * Maximum Y coordinate (top of ascenders) + * Example: 1010, 990, 1026 + */ + y_max: number | null; + + /** + * Minimum Y coordinate (bottom of descenders) + * Example: -240, -250, -280 + */ + y_min: number | null; +} + +/** + * Weight information for a font style + */ +export interface FontshareWeight { + /** + * Display label for the weight + * Examples: "Light", "Regular", "Bold", "Variable", "Variable Italic" + */ + label: string; + + /** + * Internal name for the weight + * Examples: "Light", "Regular", "Bold", "Variable", "VariableItalic" + */ + name: string; + + /** + * Native/localized name for the weight (if available) + * Often null for Latin-script fonts + */ + native_name: string | null; + + /** + * Numeric weight value + * Examples: 300, 400, 700, 0 (for variable fonts), 1, 2 + * Note: This matches the `weight` property + */ + number: number; + + /** + * Numeric weight value (duplicate of `number`) + * Appears to be redundant with `number` field + */ + weight: number; +} diff --git a/src/lib/types/google_fonts.ts b/src/lib/types/google_fonts.ts new file mode 100644 index 0000000..6dd253c --- /dev/null +++ b/src/lib/types/google_fonts.ts @@ -0,0 +1,104 @@ +/** + * Model of google fonts api response + */ +export interface GoogleFontsApiModel { + /** + * Array of font items returned by the Google Fonts API + * Contains all font families matching the requested query parameters + */ + items: FontItem[]; +} + +export interface FontItem { + /** + * Font family name (e.g., "Roboto", "Open Sans", "Lato") + * This is the name used in CSS font-family declarations + */ + family: string; + + /** + * Font category classification (e.g., "sans-serif", "serif", "display", "handwriting", "monospace") + * Useful for grouping and filtering fonts by style + */ + category: string; + + /** + * Available font variants for this font family + * Array of strings representing available weights and styles + * Examples: ["regular", "italic", "100", "200", "300", "400", "500", "600", "700", "800", "900", "100italic", "900italic"] + * The keys in the `files` object correspond to these variant values + */ + variants: FontVariant[]; + + /** + * Supported character subsets for this font + * Examples: ["latin", "latin-ext", "cyrillic", "greek", "arabic", "devanagari", "vietnamese", "hebrew", "thai", etc.] + * Determines which character sets are included in the font files + */ + subsets: string[]; + + /** + * Font version identifier + * Format: "v" followed by version number (e.g., "v31", "v20", "v1") + * Used to track font updates and cache busting + */ + version: string; + + /** + * Last modification date of the font + * Format: ISO 8601 date string (e.g., "2024-01-15", "2023-12-01") + * Indicates when the font was last updated by the font foundry + */ + lastModified: string; + + /** + * Mapping of font variants to their downloadable URLs + * Keys correspond to values in the `variants` array + * Examples: + * - "regular" → "https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me4W..." + * - "700" → "https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlf..." + * - "700italic" → "https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzA..." + */ + files: FontFiles; + + /** + * URL to the font menu preview image + * Typically a PNG showing the font family name in the font + * Example: "https://fonts.gstatic.com/l/font?kit=KFOmCnqEu92Fr1Me4W...&s=i2" + */ + menu: string; +} + +/** + * Standard font weights that can appear in Google Fonts API + */ +export type FontWeight = '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + +/** + * Italic variant format: e.g., "100italic", "400italic", "700italic" + */ +export type FontWeightItalic = `${FontWeight}italic`; + +/** + * All possible font variants in Google Fonts API + * - Numeric weights: "400", "700", etc. + * - Italic variants: "400italic", "700italic", etc. + * - Legacy names: "regular", "italic", "bold", "bolditalic" + */ +export type FontVariant = + | FontWeight + | FontWeightItalic + | 'regular' + | 'italic' + | 'bold' + | 'bolditalic'; + +/** + * Google Fonts API file mapping + * Dynamic keys that match the variants array + * + * Examples: + * - { "regular": "...", "italic": "...", "700": "...", "700italic": "..." } + * - { "400": "...", "400italic": "...", "900": "..." } + */ +export type FontFiles = Partial>; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..631bd81 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,6 @@ +import { mount } from 'svelte'; +import App from './App.svelte'; + +mount(App, { + target: document.getElementById('app')!, +}); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte deleted file mode 100644 index a611c7d..0000000 --- a/src/routes/+layout.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - -{@render children()} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte deleted file mode 100644 index 0bb4a48..0000000 --- a/src/routes/+page.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -

Welcome to SvelteKit

-

- Visit svelte.dev/docs/kit to read the documentation -

- diff --git a/src/routes/Page.svelte b/src/routes/Page.svelte new file mode 100644 index 0000000..b355f9e --- /dev/null +++ b/src/routes/Page.svelte @@ -0,0 +1,9 @@ + + +

Welcome to Svelte + Vite

+

+ Visit svelte.dev/docs to read the documentation +

+ diff --git a/svelte.config.js b/svelte.config.js index 37afe3a..6d1da96 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,7 +1,5 @@ -import adapter from '@sveltejs/adapter-auto'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; -/** @type {import('@sveltejs/kit').Config} */ const config = { // Consult https://svelte.dev/docs/kit/integrations // for more information about preprocessors @@ -10,13 +8,6 @@ const config = { compilerOptions: { runes: true, }, - - kit: { - // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. - // If your environment is not supported, or you settled on a specific environment, switch out the adapter. - // See https://svelte.dev/docs/kit/adapters for more information about adapters. - adapter: adapter(), - }, }; export default config; diff --git a/tsconfig.json b/tsconfig.json index 672ded3..c27aaed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,12 @@ { - "extends": "./.svelte-kit/tsconfig.json", "compilerOptions": { - "rewriteRelativeImportExtensions": true, + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ESNext", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + + /* Strictness & Safety */ + "strict": true, "allowJs": true, "checkJs": true, "esModuleInterop": true, @@ -9,13 +14,24 @@ "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true, - "strict": true, - "moduleResolution": "bundler" + "isolatedModules": true, + "verbatimModuleSyntax": true, + + /* Path Aliases */ + "baseUrl": ".", + "paths": { + "$lib/*": ["./src/lib/*"] + } }, - "exclude": ["./src/lib/components/ui"] - // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias - // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files - // - // To make changes to top-level options such as include and exclude, we recommend extending - // the generated config; see https://svelte.dev/docs/kit/configuration#typescript + "include": [ + "src/**/*.ts", + "src/**/*.js", + "src/**/*.svelte", + "src/**/*.d.ts" + ], + "exclude": [ + "node_modules", + "dist", + "./src/lib/components/ui" + ] } diff --git a/vite.config.ts b/vite.config.ts index f8b704b..2730f4a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,15 @@ -import { sveltekit } from '@sveltejs/kit/vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; import tailwindcss from '@tailwindcss/vite'; import { defineConfig } from 'vite'; export default defineConfig({ - plugins: [sveltekit(), tailwindcss()], + plugins: [svelte(), tailwindcss()], + resolve: { + alias: { + $lib: '/src/lib', + }, + }, + build: { + outDir: 'dist', + }, }); diff --git a/yarn.lock b/yarn.lock index 33074cd..9871ec3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -357,13 +357,13 @@ __metadata: linkType: hard "@napi-rs/wasm-runtime@npm:^1.1.0": - version: 1.1.0 - resolution: "@napi-rs/wasm-runtime@npm:1.1.0" + version: 1.1.1 + resolution: "@napi-rs/wasm-runtime@npm:1.1.1" dependencies: "@emnapi/core": "npm:^1.7.1" "@emnapi/runtime": "npm:^1.7.1" "@tybys/wasm-util": "npm:^0.10.1" - checksum: 10c0/ee351052123bfc635c4cef03ac273a686522394ccd513b1e5b7b3823cecd6abb4a31f23a3a962933192b87eb7b7c3eb3def7748bd410edc66f932d90cf44e9ab + checksum: 10c0/04d57b67e80736e41fe44674a011878db0a8ad893f4d44abb9d3608debb7c174224cba2796ed5b0c1d367368159f3ca6be45f1c59222f70e32ddc880f803d447 languageName: node linkType: hard @@ -456,13 +456,6 @@ __metadata: languageName: node linkType: hard -"@polka/url@npm:^1.0.0-next.24": - version: 1.0.0-next.29 - resolution: "@polka/url@npm:1.0.0-next.29" - checksum: 10c0/0d58e081844095cb029d3c19a659bfefd09d5d51a2f791bc61eba7ea826f13d6ee204a8a448c2f5a855c17df07b37517373ff916dd05801063c0568ae9937684 - languageName: node - linkType: hard - "@rollup/rollup-android-arm-eabi@npm:4.54.0": version: 4.54.0 resolution: "@rollup/rollup-android-arm-eabi@npm:4.54.0" @@ -617,13 +610,6 @@ __metadata: languageName: node linkType: hard -"@standard-schema/spec@npm:^1.0.0": - version: 1.1.0 - resolution: "@standard-schema/spec@npm:1.1.0" - checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526 - languageName: node - linkType: hard - "@sveltejs/acorn-typescript@npm:^1.0.5": version: 1.0.8 resolution: "@sveltejs/acorn-typescript@npm:1.0.8" @@ -633,46 +619,6 @@ __metadata: languageName: node linkType: hard -"@sveltejs/adapter-auto@npm:^7.0.0": - version: 7.0.0 - resolution: "@sveltejs/adapter-auto@npm:7.0.0" - peerDependencies: - "@sveltejs/kit": ^2.0.0 - checksum: 10c0/928393d4e366a0094bec5e09c70e44c3c7b5f17687f1735f71eb305e1ae640c64cd9f7d8f80d8b31dcaa235ae2b07e0f021a9204b5cec895d5bd8035064c9195 - languageName: node - linkType: hard - -"@sveltejs/kit@npm:^2.49.1": - version: 2.49.2 - resolution: "@sveltejs/kit@npm:2.49.2" - dependencies: - "@standard-schema/spec": "npm:^1.0.0" - "@sveltejs/acorn-typescript": "npm:^1.0.5" - "@types/cookie": "npm:^0.6.0" - acorn: "npm:^8.14.1" - cookie: "npm:^0.6.0" - devalue: "npm:^5.3.2" - esm-env: "npm:^1.2.2" - kleur: "npm:^4.1.5" - magic-string: "npm:^0.30.5" - mrmime: "npm:^2.0.0" - sade: "npm:^1.8.1" - set-cookie-parser: "npm:^2.6.0" - sirv: "npm:^3.0.0" - peerDependencies: - "@opentelemetry/api": ^1.0.0 - "@sveltejs/vite-plugin-svelte": ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 - svelte: ^4.0.0 || ^5.0.0-next.0 - vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 - peerDependenciesMeta: - "@opentelemetry/api": - optional: true - bin: - svelte-kit: svelte-kit.js - checksum: 10c0/05bf6d0d9fb87d894d1a5667f0473d8e83a4584f5c80850ed9eef1d1c8982236ea0d703bbd83befdff30c729d102fc67f2839014d900edb15f6b449ee059b9aa - languageName: node - linkType: hard - "@sveltejs/vite-plugin-svelte-inspector@npm:^5.0.0": version: 5.0.1 resolution: "@sveltejs/vite-plugin-svelte-inspector@npm:5.0.1" @@ -875,13 +821,6 @@ __metadata: languageName: node linkType: hard -"@types/cookie@npm:^0.6.0": - version: 0.6.0 - resolution: "@types/cookie@npm:0.6.0" - checksum: 10c0/5b326bd0188120fb32c0be086b141b1481fec9941b76ad537f9110e10d61ee2636beac145463319c71e4be67a17e85b81ca9e13ceb6e3bb63b93d16824d6c149 - languageName: node - linkType: hard - "@types/estree@npm:1.0.8, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" @@ -896,7 +835,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.12.1, acorn@npm:^8.14.1": +"acorn@npm:^8.12.1": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -968,13 +907,6 @@ __metadata: languageName: node linkType: hard -"cookie@npm:^0.6.0": - version: 0.6.0 - resolution: "cookie@npm:0.6.0" - checksum: 10c0/f2318b31af7a31b4ddb4a678d024514df5e705f9be5909a192d7f116cfb6d45cbacf96a473fa733faa95050e7cff26e7832bb3ef94751592f1387b71c8956686 - languageName: node - linkType: hard - "debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.1": version: 4.4.3 resolution: "debug@npm:4.4.3" @@ -1001,7 +933,7 @@ __metadata: languageName: node linkType: hard -"devalue@npm:^5.3.2, devalue@npm:^5.5.0": +"devalue@npm:^5.5.0": version: 5.6.1 resolution: "devalue@npm:5.6.1" checksum: 10c0/4dca0e800336003fd1e268c142adfe78f3539cda7384b4f69762a93e0dfc33e223b580251da0a6da4be44962958fcba5eadf122f9720e09f437b28904af9c43e @@ -1168,7 +1100,7 @@ __metadata: languageName: node linkType: hard -"esm-env@npm:^1.2.1, esm-env@npm:^1.2.2": +"esm-env@npm:^1.2.1": version: 1.2.2 resolution: "esm-env@npm:1.2.2" checksum: 10c0/3d25c973f2fd69c25ffff29c964399cea573fe10795ecc1d26f6f957ce0483d3254e1cceddb34bf3296a0d7b0f1d53a28992f064ba509dfe6366751e752c4166 @@ -1267,8 +1199,6 @@ __metadata: dependencies: "@lucide/svelte": "npm:^0.562.0" "@playwright/test": "npm:^1.57.0" - "@sveltejs/adapter-auto": "npm:^7.0.0" - "@sveltejs/kit": "npm:^2.49.1" "@sveltejs/vite-plugin-svelte": "npm:^6.2.1" "@tailwindcss/vite": "npm:^4.1.18" clsx: "npm:^2.1.1" @@ -1368,13 +1298,6 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^4.1.5": - version: 4.1.5 - resolution: "kleur@npm:4.1.5" - checksum: 10c0/e9de6cb49657b6fa70ba2d1448fd3d691a5c4370d8f7bbf1c2f64c24d461270f2117e1b0afe8cb3114f13bbd8e51de158c2a224953960331904e636a5e4c0f2a - languageName: node - linkType: hard - "lefthook-darwin-arm64@npm:2.0.13": version: 2.0.13 resolution: "lefthook-darwin-arm64@npm:2.0.13" @@ -1620,7 +1543,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.11, magic-string@npm:^0.30.17, magic-string@npm:^0.30.21, magic-string@npm:^0.30.5": +"magic-string@npm:^0.30.11, magic-string@npm:^0.30.17, magic-string@npm:^0.30.21": version: 0.30.21 resolution: "magic-string@npm:0.30.21" dependencies: @@ -1740,13 +1663,6 @@ __metadata: languageName: node linkType: hard -"mrmime@npm:^2.0.0": - version: 2.0.1 - resolution: "mrmime@npm:2.0.1" - checksum: 10c0/af05afd95af202fdd620422f976ad67dc18e6ee29beb03dd1ce950ea6ef664de378e44197246df4c7cdd73d47f2e7143a6e26e473084b9e4aa2095c0ad1e1761 - languageName: node - linkType: hard - "ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -2020,7 +1936,7 @@ __metadata: languageName: node linkType: hard -"sade@npm:^1.7.4, sade@npm:^1.8.1": +"sade@npm:^1.7.4": version: 1.8.1 resolution: "sade@npm:1.8.1" dependencies: @@ -2045,24 +1961,6 @@ __metadata: languageName: node linkType: hard -"set-cookie-parser@npm:^2.6.0": - version: 2.7.2 - resolution: "set-cookie-parser@npm:2.7.2" - checksum: 10c0/4381a9eb7ee951dfe393fe7aacf76b9a3b4e93a684d2162ab35594fa4053cc82a4d7d7582bf397718012c9adcf839b8cd8f57c6c42901ea9effe33c752da4a45 - languageName: node - linkType: hard - -"sirv@npm:^3.0.0": - version: 3.0.2 - resolution: "sirv@npm:3.0.2" - dependencies: - "@polka/url": "npm:^1.0.0-next.24" - mrmime: "npm:^2.0.0" - totalist: "npm:^3.0.0" - checksum: 10c0/5930e4397afdb14fbae13751c3be983af4bda5c9aadec832607dc2af15a7162f7d518c71b30e83ae3644b9a24cea041543cc969e5fe2b80af6ce8ea3174b2d04 - languageName: node - linkType: hard - "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -2205,13 +2103,6 @@ __metadata: languageName: node linkType: hard -"totalist@npm:^3.0.0": - version: 3.0.1 - resolution: "totalist@npm:3.0.1" - checksum: 10c0/4bb1fadb69c3edbef91c73ebef9d25b33bbf69afe1e37ce544d5f7d13854cda15e47132f3e0dc4cafe300ddb8578c77c50a65004d8b6e97e77934a69aa924863 - languageName: node - linkType: hard - "tslib@npm:^2.4.0": version: 2.8.1 resolution: "tslib@npm:2.8.1"