diff --git a/.agents/plans/bun-test/PLAN.md b/.agents/plans/bun-test/PLAN.md new file mode 100644 index 0000000..8ab81f2 --- /dev/null +++ b/.agents/plans/bun-test/PLAN.md @@ -0,0 +1,113 @@ +# Bun Test Coverage + +Generate tests targeting 100% coverage with `bun:test` across the monorepo. + +## Workflow + +1. **Identify target directory** - Determine which app (`share`, `server`, or `client`) needs tests +2. **Mirror file structure** - Create parallel `test/` directory matching source structure +3. **Generate test files** - Create `*.test.ts` for each source file +4. **Run coverage** - Execute `bun test --coverage` and identify gaps +5. **Fill gaps** - Add tests for uncovered branches, edge cases, and error paths +6. **Verify** - Confirm 100% coverage before completing + +## File Mirroring + +Given a source directory, create a parallel `test/` structure: + +``` +apps/server/src/ +├── index.ts +├── app/ +│ ├── admin/index.ts +│ └── user/record.ts +``` + +Becomes: + +``` +apps/server/test/ +├── index.test.ts +├── app/ +│ ├── admin/index.test.ts +│ └── user/record.test.ts +``` + +**Rules:** + +- One test file per source module (1:1 mapping) +- Place tests in a separate `test/` directory (not co-located) +- Preserve nested directory structure exactly +- Use `.test.ts` extension for all test files + +## Test Configuration + +Project uses `bunfig.toml`: + +```toml +[test] +coverage = true +coverageReporter = ["text", "lcov"] +retry = 2 +randomize = true +onlyFailures = true +``` + +**Run tests:** + +```bash +bun test # Run all tests +bun test --coverage # Run with coverage report +bun test apps/share/test/ # Run specific directory +bun test path/to/file.test.ts # Run single file +``` + +## Testing by App Type + +| App | Test Type | Key Tools | Reference | +| ------------- | --------------- | ----------------------------- | --------------------------------------------------- | +| `apps/share` | Unit | `bun:test`, Arktype helpers | [share-patterns.md](references/share-patterns.md) | +| `apps/server` | API/Integration | `bun:test`, `hono/testing` | [server-patterns.md](references/server-patterns.md) | +| `apps/client` | Component | `bun:test`, `@vue/test-utils` | [client-patterns.md](references/client-patterns.md) | + +## Achieving 100% Coverage + +Coverage means every branch, line, and function is exercised by at least one test. + +**Strategy:** + +1. Run `bun test --coverage` to identify gaps +2. Read the coverage report to find uncovered lines/branches +3. Add tests specifically targeting those gaps: + - **Branch coverage**: Test both true/false paths of conditionals + - **Edge cases**: Test null, undefined, empty, boundary values + - **Error paths**: Test catch blocks, error returns, validation failures + - **Default cases**: Test switch default, fallback values +4. Repeat until coverage reaches 100% + +**Test structure pattern:** + +```typescript +import { describe, test, expect } from 'bun:test'; + +describe('functionName', () => { + describe('valid inputs', () => { + test('should handle case X', () => { ... }); + test('should handle case Y', () => { ... }); + }); + + describe('invalid inputs', () => { + test('should handle error case A', () => { ... }); + test('should handle error case B', () => { ... }); + }); +}); +``` + +## Key Principles + +1. **Test behavior, not implementation** - Assert outputs and side effects, not internal state +2. **One assertion per test** when possible - Makes failures easier to diagnose +3. **Descriptive test names** - Explain what is being tested and expected result +4. **Boundary value testing** - Test min, max, just-outside-range values +5. **Mock external dependencies** - Isolate the unit under test +6. **Follow existing patterns** - Match the style of existing tests in `apps/share/test/` diff --git a/.agents/plans/bun-test/references/client-patterns.md b/.agents/plans/bun-test/references/client-patterns.md new file mode 100644 index 0000000..23ea8cd --- /dev/null +++ b/.agents/plans/bun-test/references/client-patterns.md @@ -0,0 +1,292 @@ +# Client Testing Patterns + +Patterns for testing `apps/client` - Vue 3 components, composables, and pages. + +## Table of Contents + +- [Test Setup](#test-setup) +- [Composable Testing](#composable-testing) +- [Component Testing](#component-testing) +- [Page Testing](#page-testing) +- [Mocking Dependencies](#mocking-dependencies) +- [Coverage Checklist](#coverage-checklist) + +## Test Setup + +```typescript +import { describe, test, expect, beforeEach } from 'bun:test'; +import { mount, shallowMount } from '@vue/test-utils'; +import { nextTick, ref } from 'vue'; +``` + +## Composable Testing + +### Simple composables (reactivity APIs only) + +Test directly without wrapper: + +```typescript +import { useCounter } from '../../src/composable/useCounter'; + +describe('useCounter', () => { + test('should initialize with 0', () => { + const { count } = useCounter(); + expect(count.value).toBe(0); + }); + + test('should increment', () => { + const { count, increment } = useCounter(); + increment(); + expect(count.value).toBe(1); + }); +}); +``` + +### Composables with lifecycle hooks or provide/inject + +Use `withSetup` helper: + +```typescript +import { createApp } from 'vue'; + +function withSetup(composable: () => T): [T, ReturnType] { + let result: T; + const app = createApp({ + setup() { + result = composable(); + return () => null; + }, + }); + app.mount(document.createElement('div')); + return [result!, app]; +} +``` + +Usage: + +```typescript +import { useAuth } from '../../src/composable/useAuth'; + +describe('useAuth', () => { + test('should provide auth state', () => { + const [result, app] = withSetup(() => useAuth()); + + expect(result.isAuthenticated.value).toBe(false); + expect(result.user.value).toBeNull(); + + app.unmount(); + }); + + test('should update on auth change', async () => { + const [result, app] = withSetup(() => useAuth()); + + // Simulate auth change + result.login({ id: 'user_123' }); + await nextTick(); + + expect(result.isAuthenticated.value).toBe(true); + + app.unmount(); + }); +}); +``` + +### Composables with TanStack Query + +Mock the query client: + +```typescript +import { useActivity } from '../../src/composable/useActivity'; + +describe('useActivity', () => { + test('should fetch activities', async () => { + const [result, app] = withSetup(() => useActivity()); + + expect(result.isLoading.value).toBe(true); + await nextTick(); + await new Promise((r) => setTimeout(r, 0)); + + expect(result.data.value).toBeDefined(); + + app.unmount(); + }); +}); +``` + +## Component Testing + +### Basic component testing + +```typescript +import MyComponent from '../../src/components/common/MyComponent.vue'; + +describe('MyComponent', () => { + test('should render with default props', () => { + const wrapper = mount(MyComponent); + expect(wrapper.text()).toContain('default content'); + }); + + test('should render with custom props', () => { + const wrapper = mount(MyComponent, { + props: { title: 'Custom Title' }, + }); + expect(wrapper.text()).toContain('Custom Title'); + }); +}); +``` + +### Testing user interactions + +```typescript +describe('user interactions', () => { + test('should emit event on click', async () => { + const wrapper = mount(MyComponent); + await wrapper.find('button').trigger('click'); + expect(wrapper.emitted('click')).toHaveLength(1); + }); + + test('should update on input', async () => { + const wrapper = mount(MyComponent); + const input = wrapper.find('input'); + await input.setValue('new value'); + expect(wrapper.emitted('update:modelValue')).toEqual([['new value']]); + }); +}); +``` + +### Testing conditional rendering + +```typescript +describe('conditional rendering', () => { + test('should show content when visible', () => { + const wrapper = mount(MyComponent, { props: { show: true } }); + expect(wrapper.find('.content').exists()).toBe(true); + }); + + test('should hide content when not visible', () => { + const wrapper = mount(MyComponent, { props: { show: false } }); + expect(wrapper.find('.content').exists()).toBe(false); + }); +}); +``` + +### Testing slots + +```typescript +describe('slots', () => { + test('should render default slot', () => { + const wrapper = mount(MyComponent, { + slots: { default: 'Slot content' }, + }); + expect(wrapper.text()).toContain('Slot content'); + }); +}); +``` + +## Page Testing + +Test pages with mocked router and API: + +```typescript +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import HomePage from '../../src/pages/Home.vue'; + +describe('HomePage', () => { + test('should render home page', () => { + const wrapper = mount(HomePage); + expect(wrapper.exists()).toBe(true); + }); +}); +``` + +## Mocking Dependencies + +### Mocking Hono RPC client + +```typescript +import { mock } from 'bun:test'; + +// Mock the API client +const mockApiClient = { + api: { + user: { + record: { + $get: mock(() => Promise.resolve({ ok: true, data: [] })), + $post: mock(() => Promise.resolve({ ok: true, data: { id: 1 } })), + }, + }, + }, +}; +``` + +### Mocking Clerk auth + +```typescript +// Mock Clerk +mockModule('@clerk/clerk-vue', () => ({ + useUser: () => ({ + isSignedIn: ref(true), + user: ref({ id: 'user_123', fullName: 'Test User' }), + }), + useAuth: () => ({ + isSignedIn: ref(true), + getToken: mock(() => Promise.resolve('mock-token')), + }), +})); +``` + +### Mocking Vue Router + +```typescript +import { createRouter, createWebHistory } from 'vue-router'; + +const mockRouter = { + push: mock(() => {}), + replace: mock(() => {}), + back: mock(() => {}), + currentRoute: { value: { path: '/' } }, +}; +``` + +## Coverage Checklist + +For each composable: + +- [ ] Initial state values +- [ ] State mutations (all methods that modify state) +- [ ] Computed values +- [ ] Lifecycle hooks (onMounted, onUnmounted) +- [ ] Error handling +- [ ] Edge cases (empty data, loading states) + +For each component: + +- [ ] Default rendering +- [ ] All prop variations +- [ ] User interactions (clicks, inputs, selections) +- [ ] Emitted events +- [ ] Conditional rendering (v-if, v-show) +- [ ] List rendering (v-for) +- [ ] Slot content +- [ ] Loading states +- [ ] Error states +- [ ] Empty states + +For each page: + +- [ ] Page renders +- [ ] Data fetching +- [ ] Navigation +- [ ] Form submissions +- [ ] Validation errors +- [ ] Success states + +## Running Tests + +```bash +cd /Users/hal/Repo/github.com/omu-aikido/record +bun test apps/client/test/ # Run all client tests +bun test apps/client/test/composable/useAuth.test.ts # Run single file +bun test --coverage # Run all with coverage +``` diff --git a/.agents/plans/bun-test/references/server-patterns.md b/.agents/plans/bun-test/references/server-patterns.md new file mode 100644 index 0000000..6c81f64 --- /dev/null +++ b/.agents/plans/bun-test/references/server-patterns.md @@ -0,0 +1,274 @@ +# Server Testing Patterns + +Patterns for testing `apps/server` - Hono API routes, middleware, and handlers on Cloudflare Workers. + +## Table of Contents + +- [Test Setup](#test-setup) +- [Route Testing with testClient](#route-testing-with-testclient) +- [Middleware Testing](#middleware-testing) +- [Mocking Dependencies](#mocking-dependencies) +- [Coverage Checklist](#coverage-checklist) + +## Test Setup + +```typescript +import { describe, test, expect, mock, beforeEach } from 'bun:test'; +import { testClient } from 'hono/testing'; +``` + +Import the app instance and create a test client: + +```typescript +import app from '../src/index'; + +const client = testClient(app); +``` + +**Note on type inference:** For `testClient` to infer route types, routes must be defined using chained methods directly on the Hono instance. If routes are defined separately, use string-based requests. + +## Route Testing with testClient + +### GET endpoints + +```typescript +describe('GET /api/endpoint', () => { + test('should return 200 with valid data', async () => { + const res = await client.api.endpoint.$get(); + expect(res.status).toBe(200); + const json = await res.json(); + expect(json).toEqual({ expected: 'data' }); + }); + + test('should return 401 without auth', async () => { + const res = await client.api.endpoint.$get( + {}, + { + headers: { + /* no auth header */ + }, + } + ); + expect(res.status).toBe(401); + }); +}); +``` + +### POST endpoints + +```typescript +describe('POST /api/endpoint', () => { + test('should create resource with valid input', async () => { + const res = await client.api.endpoint.$post({ + json: { field: 'value' }, + }); + expect(res.status).toBe(201); + }); + + test('should return 400 with invalid input', async () => { + const res = await client.api.endpoint.$post({ + json: { field: '' }, + }); + expect(res.status).toBe(400); + }); +}); +``` + +### DELETE endpoints + +```typescript +describe('DELETE /api/endpoint/:id', () => { + test('should delete resource', async () => { + const res = await client.api.endpoint[':id'].$delete({ + param: { id: '123' }, + }); + expect(res.status).toBe(200); + }); +}); +``` + +## Middleware Testing + +### Auth middleware + +```typescript +describe('signedIn middleware', () => { + test('should pass with valid auth', async () => { + const res = await client.api.protected.$get( + {}, + { + headers: { + Authorization: 'Bearer valid-token', + }, + } + ); + expect(res.status).toBe(200); + }); + + test('should reject without token', async () => { + const res = await client.api.protected.$get(); + expect(res.status).toBe(401); + }); +}); +``` + +### Admin middleware + +```typescript +describe('admin middleware', () => { + test('should allow admin access', async () => { + const res = await client.api.admin.$get( + {}, + { + headers: { + Authorization: 'Bearer admin-token', + 'X-Role': 'admin', + }, + } + ); + expect(res.status).toBe(200); + }); + + test('should reject non-admin', async () => { + const res = await client.api.admin.$get( + {}, + { + headers: { + Authorization: 'Bearer user-token', + 'X-Role': 'member', + }, + } + ); + expect(res.status).toBe(403); + }); +}); +``` + +### Error handler middleware + +```typescript +describe('errorHandler middleware', () => { + test('should return 500 for unhandled errors', async () => { + const res = await client.api.error.$get(); + expect(res.status).toBe(500); + const json = await res.json(); + expect(json).toHaveProperty('error'); + }); +}); +``` + +## Mocking Dependencies + +### Mocking Clerk authentication + +```typescript +import { mockModule } from 'bun:test'; + +// Mock Clerk client +mockModule('@clerk/backend', () => ({ + createClerkClient: () => ({ + users: { + getUser: mock(() => Promise.resolve({ id: 'user_123', role: 'admin' })), + updateUser: mock(() => Promise.resolve({ id: 'user_123' })), + }, + }), +})); +``` + +### Mocking Drizzle database + +```typescript +// Create mock database functions +const mockDb = { + select: mock(() => Promise.resolve([])), + insert: mock(() => Promise.resolve({})), + update: mock(() => Promise.resolve({})), + delete: mock(() => Promise.resolve({})), +}; + +// For each test, set up mock return values +mockDb.select.mockImplementation(() => Promise.resolve([{ id: 1, name: 'test' }])); +``` + +### Mocking Cloudflare bindings + +```typescript +// Mock Cloudflare environment +const mockEnv = { + TURSO_DB_URL: 'libsql://test.turso.io', + TURSO_DB_AUTH_TOKEN: 'test-token', + CLERK_SECRET_KEY: 'test-secret', +}; + +// Pass to app.request if needed +const res = await app.request('/api/test', {}, mockEnv); +``` + +## Webhook Testing + +```typescript +describe('POST /webhooks/clerk', () => { + test('should handle user.created event', async () => { + const payload = { + type: 'user.created', + data: { id: 'user_123', email_addresses: [{ email_address: 'test@example.com' }] }, + }; + + const res = await client.webhooks.clerk.$post({ + json: payload, + }); + expect(res.status).toBe(200); + }); + + test('should handle user.updated event', async () => { + const payload = { + type: 'user.updated', + data: { id: 'user_123', role: 'admin' }, + }; + + const res = await client.webhooks.clerk.$post({ + json: payload, + }); + expect(res.status).toBe(200); + }); + + test('should ignore unknown events', async () => { + const payload = { type: 'unknown.event', data: {} }; + + const res = await client.webhooks.clerk.$post({ + json: payload, + }); + expect(res.status).toBe(200); + }); +}); +``` + +## Coverage Checklist + +For each route file: + +- [ ] Happy path (valid request, expected response) +- [ ] Missing authentication +- [ ] Invalid request body (validation errors) +- [ ] Missing required parameters +- [ ] Resource not found (404) +- [ ] Database errors +- [ ] All HTTP methods (GET, POST, PUT, DELETE) +- [ ] Query parameters (valid, invalid, missing) +- [ ] Pagination parameters +- [ ] Sorting/filtering parameters + +For each middleware: + +- [ ] Pass-through case (valid request) +- [ ] Rejection case (invalid/missing auth) +- [ ] Error handling + +## Running Tests + +```bash +cd /Users/hal/Repo/github.com/omu-aikido/record +bun test apps/server/test/ # Run all server tests +bun test apps/server/test/app/user/record.test.ts # Run single file +bun test --coverage # Run all with coverage +``` diff --git a/.agents/plans/bun-test/references/share-patterns.md b/.agents/plans/bun-test/references/share-patterns.md new file mode 100644 index 0000000..970de75 --- /dev/null +++ b/.agents/plans/bun-test/references/share-patterns.md @@ -0,0 +1,212 @@ +# Share Testing Patterns + +Patterns for testing `apps/share` - shared TypeScript types, validations, and utilities. + +## Table of Contents + +- [Test Setup](#test-setup) +- [Arktype Schema Testing](#arktype-schema-testing) +- [Pure Function Testing](#pure-function-testing) +- [Class Testing](#class-testing) +- [Coverage Checklist](#coverage-checklist) + +## Test Setup + +```typescript +import { describe, test, expect } from 'bun:test'; +import { ArkErrors } from 'arktype'; + +// Helper for Arktype validation results +function isValid(result: unknown): boolean { + return !(result instanceof ArkErrors); +} +``` + +Import from `../index` (the share package re-exports all modules): + +```typescript +import { grade, translateGrade, Role, recordQuerySchema } from '../index'; +``` + +## Arktype Schema Testing + +Test both valid and invalid cases: + +```typescript +describe('schemaName', () => { + test('should accept valid input', () => { + const result = schemaName({ field: 'value' }); + expect(isValid(result)).toBe(true); + }); + + test('should reject missing required field', () => { + const result = schemaName({}); + expect(isValid(result)).toBe(false); + }); + + test('should reject wrong type', () => { + const result = schemaName({ field: 123 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject null/undefined', () => { + expect(isValid(schemaName(null))).toBe(false); + expect(isValid(schemaName(undefined))).toBe(false); + }); +}); +``` + +**Coverage checklist for schemas:** + +- [ ] All required fields present (valid case) +- [ ] Each required field missing (individual invalid cases) +- [ ] Each field with wrong type +- [ ] Optional fields omitted (still valid) +- [ ] Null and undefined inputs +- [ ] Nested object validation (if applicable) + +## Pure Function Testing + +Test all branches and edge cases: + +```typescript +describe('functionName()', () => { + describe('valid inputs', () => { + test('should handle normal case', () => { + expect(functionName('normal')).toBe('expected'); + }); + + test('should handle edge case', () => { + expect(functionName('')).toBe('fallback'); + }); + }); + + describe('invalid inputs', () => { + test('should return fallback for null', () => { + expect(functionName(null)).toBe('fallback'); + }); + + test('should return fallback for undefined', () => { + expect(functionName(undefined)).toBe('fallback'); + }); + }); +}); +``` + +**Example from grade.ts:** + +```typescript +describe('translateGrade()', () => { + describe('valid inputs', () => { + test('should translate all grade names', () => { + expect(translateGrade('無級')).toBe('無級'); + expect(translateGrade('五段')).toBe('五段'); + }); + + test('should translate numeric grades', () => { + expect(translateGrade(0)).toBe('無級'); + expect(translateGrade(-5)).toBe('五段'); + }); + }); + + describe('invalid inputs', () => { + test('should return 不明 for empty string', () => { + expect(translateGrade('')).toBe('不明'); + }); + + test('should return 不明 for out-of-range', () => { + expect(translateGrade(6)).toBe('不明'); + expect(translateGrade(-6)).toBe('不明'); + }); + }); +}); +``` + +**Coverage checklist for functions:** + +- [ ] All switch/case branches +- [ ] All if/else branches +- [ ] Default/fallback paths +- [ ] Null and undefined inputs +- [ ] Empty string/array inputs +- [ ] Boundary values (min, max, just outside range) +- [ ] Type coercion paths (string to number, etc.) + +## Class Testing + +Test static properties, static methods, and instance methods: + +```typescript +describe('ClassName static instances', () => { + test('should have PROPERTY value', () => { + expect(ClassName.PROPERTY.value).toBe('expected'); + }); +}); + +describe('ClassName.ALL', () => { + test('should contain all instances', () => { + expect(ClassName.ALL).toHaveLength(N); + expect(ClassName.ALL).toContain(ClassName.INSTANCE); + }); +}); + +describe('ClassName.parse()', () => { + test('should parse valid values', () => { + expect(ClassName.parse('valid')).toBe(ClassName.INSTANCE); + }); + + test('should return undefined for invalid values', () => { + expect(ClassName.parse('invalid')).toBeUndefined(); + expect(ClassName.parse(null)).toBeUndefined(); + }); +}); + +describe('ClassName.fromString()', () => { + test('should return correct instance', () => { + expect(ClassName.fromString('valid')).toBe(ClassName.INSTANCE); + }); + + test('should return null for invalid', () => { + expect(ClassName.fromString('invalid')).toBeNull(); + }); +}); + +describe('instance.toString()', () => { + test('should return string representation', () => { + expect(ClassName.INSTANCE.toString()).toBe('value'); + }); +}); + +describe('ClassName.compare()', () => { + test('should return 0 for same values', () => { + expect(ClassName.compare('a', 'a')).toBe(0); + }); + + test('should return negative when first has higher priority', () => { + expect(ClassName.compare('high', 'low')).toBeLessThan(0); + }); + + test('should return positive when first has lower priority', () => { + expect(ClassName.compare('low', 'high')).toBeGreaterThan(0); + }); +}); +``` + +**Coverage checklist for classes:** + +- [ ] All static properties +- [ ] ALL array contents and ordering +- [ ] Static methods with valid inputs +- [ ] Static methods with invalid inputs (null, undefined, wrong type) +- [ ] Instance methods +- [ ] Arktype type integration (if applicable) +- [ ] Comparison/sorting methods + +## Running Tests + +```bash +cd /Users/hal/Repo/github.com/omu-aikido/record +bun test apps/share/test/ # Run all share tests +bun test apps/share/test/grade.test.ts # Run single test file +bun test --coverage # Run all with coverage +``` diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c3156f3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: + push: + branches-ignore: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - run: bun install + - run: bun run lint + - run: bun run format + - run: bun run knip + - run: bunx turbo build diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml new file mode 100644 index 0000000..58e6391 --- /dev/null +++ b/.github/workflows/weekly-update.yml @@ -0,0 +1,27 @@ +name: Weekly Update and PR + +on: + schedule: + - cron: '0 0 * * 1' + +jobs: + update-and-pr: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - name: Update packages + run: bun update -r + - name: Commit changes + run: | + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions-[bot]" + git add . + git commit -m "Weekly update: $(date +'%Y-%m-%d')" + - name: Push to new branch + run: git push origin update-weekly + - name: Create pull request + run: gh pr create --title "Weekly update PR" --body "Automated weekly update PR" --base main --head update-weekly diff --git a/AGENTS.md b/AGENTS.md index fbf6bbe..928cd63 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,9 +62,9 @@ apps/ ### テスト -- `apps/share`: Unit テスト (Vitest) -- `apps/server`: API/Integration テスト -- `apps/client`: Component テスト +- `apps/share`: Unit テスト (`bun:test`) +- `apps/server`: Unitテスト・API/Integration テスト(`bun:test`, `hono/testing`,) +- `apps/client`: Composable テスト - Unit Test diff --git a/apps/client/package.json b/apps/client/package.json index c690098..bee7613 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -22,6 +22,7 @@ "vue-router": "5.0.4" }, "devDependencies": { + "@types/bun": "latest", "@vitejs/plugin-vue": "6.0.5", "@vue/tsconfig": "0.9.1", "vite": "8.0.3" diff --git a/apps/client/test/lib/honoClient.test.ts b/apps/client/test/lib/honoClient.test.ts new file mode 100644 index 0000000..e3e595c --- /dev/null +++ b/apps/client/test/lib/honoClient.test.ts @@ -0,0 +1,42 @@ +import { describe, test, expect } from 'bun:test'; +import honoClient from '../../src/lib/honoClient'; + +describe('honoClient', () => { + test('should be defined', () => { + expect(honoClient).toBeDefined(); + }); + + test('should have auth-status endpoint', () => { + expect(honoClient['auth-status']).toBeDefined(); + }); + + test('should have user endpoints', () => { + expect(honoClient.user).toBeDefined(); + expect(honoClient.user.clerk).toBeDefined(); + expect(honoClient.user.record).toBeDefined(); + }); + + test('should have clerk endpoints', () => { + expect(honoClient.user.clerk.profile).toBeDefined(); + expect(honoClient.user.clerk.account).toBeDefined(); + expect(honoClient.user.clerk.menu).toBeDefined(); + }); + + test('should have record endpoints', () => { + expect(honoClient.user.record).toBeDefined(); + }); + + test('should have admin endpoints', () => { + expect(honoClient.admin).toBeDefined(); + expect(honoClient.admin.dashboard).toBeDefined(); + expect(honoClient.admin.accounts).toBeDefined(); + expect(honoClient.admin.norms).toBeDefined(); + expect(honoClient.admin.users).toBeDefined(); + }); + + test('should support HTTP methods', () => { + // Methods like $get, $post, $patch, $delete are added by Hono client + expect(honoClient.user.clerk.profile.$get).toBeDefined(); + expect(honoClient.user.clerk.profile.$patch).toBeDefined(); + }); +}); diff --git a/apps/client/test/lib/queryKeys.test.ts b/apps/client/test/lib/queryKeys.test.ts new file mode 100644 index 0000000..562d74a --- /dev/null +++ b/apps/client/test/lib/queryKeys.test.ts @@ -0,0 +1,93 @@ +import { describe, test, expect } from 'bun:test'; +import { queryKeys } from '../../src/lib/queryKeys'; + +describe('queryKeys', () => { + test('should export queryKeys object', () => { + expect(queryKeys).toBeDefined(); + expect(typeof queryKeys).toBe('object'); + }); + + test('should have user namespace', () => { + expect(queryKeys.user).toBeDefined(); + }); + + test('should have user record query keys', () => { + expect(queryKeys.user.record).toBeDefined(); + expect(queryKeys.user.record.count).toBeDefined(); + expect(queryKeys.user.record.ranking).toBeDefined(); + }); + + test('should generate record query keys', () => { + const key1 = queryKeys.user.record(); + expect(Array.isArray(key1)).toBe(true); + expect(key1[0]).toBe('user'); + expect(key1[1]).toBe('record'); + }); + + test('should have user clerk query keys', () => { + expect(queryKeys.user.clerk).toBeDefined(); + expect(queryKeys.user.clerk.profile).toBeDefined(); + expect(queryKeys.user.clerk.account).toBeDefined(); + expect(queryKeys.user.clerk.menu).toBeDefined(); + }); + + test('should generate profile query keys', () => { + const profileKey = queryKeys.user.clerk.profile(); + expect(Array.isArray(profileKey)).toBe(true); + expect(profileKey[0]).toBe('user'); + expect(profileKey[1]).toBe('clerk'); + expect(profileKey[2]).toBe('profile'); + }); + + test('should generate count query keys', () => { + const countKey = queryKeys.user.record.count(); + expect(Array.isArray(countKey)).toBe(true); + expect(countKey[0]).toBe('user'); + expect(countKey[1]).toBe('record'); + expect(countKey[2]).toBe('count'); + }); + + test('should generate ranking query keys', () => { + const rankingKey = queryKeys.user.record.ranking(); + expect(Array.isArray(rankingKey)).toBe(true); + expect(rankingKey[0]).toBe('user'); + expect(rankingKey[1]).toBe('record'); + expect(rankingKey[2]).toBe('ranking'); + }); + + test('should have admin query keys', () => { + expect(queryKeys.admin).toBeDefined(); + expect(queryKeys.admin.dashboard).toBeDefined(); + expect(queryKeys.admin.accounts).toBeDefined(); + expect(queryKeys.admin.norms).toBeDefined(); + expect(queryKeys.admin.users).toBeDefined(); + }); + + test('should support query parameters in record', () => { + const keyWithParams = queryKeys.user.record({ query: { startDate: '2024-01-01' } }); + expect(Array.isArray(keyWithParams)).toBe(true); + expect(keyWithParams[0]).toBe('user'); + expect(keyWithParams[1]).toBe('record'); + // ensure the params object is included in the generated key + expect(keyWithParams).toContainEqual( + expect.objectContaining({ query: expect.objectContaining({ startDate: '2024-01-01' }) }) + ); + }); + + test('should support pagination in users query', () => { + const userKey = queryKeys.admin.users('user_123'); + expect(Array.isArray(userKey)).toBe(true); + }); + + test('should generate consistent keys for same parameters', () => { + const key1 = queryKeys.user.record(); + const key2 = queryKeys.user.record(); + expect(key1).toEqual(key2); + }); + + test('should generate different keys for different parameters', () => { + const key1 = queryKeys.user.record({ query: { startDate: '2024-01-01' } }); + const key2 = queryKeys.user.record({ query: { startDate: '2024-02-01' } }); + expect(key1).not.toEqual(key2); + }); +}); diff --git a/apps/client/tsconfig.test.json b/apps/client/tsconfig.test.json new file mode 100644 index 0000000..cd453f6 --- /dev/null +++ b/apps/client/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["bun"] + }, + "include": ["src/**/*.ts", "src/**/*.vue", "env.d.ts", "test/**/*.ts"] +} diff --git a/apps/server/src/app/user/clerk.ts b/apps/server/src/app/user/clerk.ts index 1c47ae0..64a8e99 100644 --- a/apps/server/src/app/user/clerk.ts +++ b/apps/server/src/app/user/clerk.ts @@ -12,9 +12,9 @@ import { AccountMetadata, Role, updateAccountSchema } from 'share'; export const clerk = new Hono<{ Bindings: Env }>() // .get('/account', async (c) => { const auth = getAuth(c); - if (!auth || !auth.userId) throw new Error('Not Authenticated'); + if (!auth || !auth.userId) return c.json({ error: 'Not Authenticated' }, 401); const user = await getUser(c); - if (!user) throw new Error('User not found'); + if (!user) return c.json({ error: 'User not found' }, 404); return c.json(user, 200); }) .patch( @@ -27,7 +27,7 @@ export const clerk = new Hono<{ Bindings: Env }>() // }), async (c) => { const auth = getAuth(c); - if (!auth || !auth.userId) throw new Error('Not Authenticated'); + if (!auth || !auth.userId) return c.json({ error: 'Not Authenticated' }, 401); const body = c.req.valid('form'); @@ -70,18 +70,18 @@ export const clerk = new Hono<{ Bindings: Env }>() // } catch (error) { const err = error instanceof Error ? error : new Error(String(error)); notify(c, err, { statusCode: 500 }); - throw new Error('Failed to update account', { cause: error }); + return c.json({ error: 'Failed to update account' }, 500); } } ) .get('/profile', async (c) => { const auth = getAuth(c); - if (!auth || !auth.userId) throw new Error('Not Authenticated'); + if (!auth || !auth.userId) return c.json({ error: 'Not Authenticated' }, 401); const profile = await getProfile(c); - if (!profile) throw new Error('Profile not found'); + if (!profile) return c.json({ error: 'Profile not found' }, 404); return c.json({ profile: { id: auth.userId, ...profile } }, 200); }) @@ -97,25 +97,26 @@ export const clerk = new Hono<{ Bindings: Env }>() // const reqData = c.req.valid('json'); const profile = await getProfile(c); - if (!profile) throw new Error('Profile not found'); + if (!profile) return c.json({ error: 'Profile not found' }, 404); const newUserData = await patchProfile(c, { role: profile.role, ...reqData, }); - if (Object.keys(newUserData.publicMetadata).length === 0) throw new Error('Failed to update user data.'); + if (Object.keys(newUserData.publicMetadata).length === 0) + return c.json({ error: 'Failed to update user data.' }, 500); const newProfile = AccountMetadata(newUserData.publicMetadata); - if (newProfile instanceof ArkErrors) throw new Error('Invalid profile data'); + if (newProfile instanceof ArkErrors) return c.json({ error: 'Invalid profile data' }, 400); return c.json({ profile: { id: newUserData.id, ...newProfile } }, 200); } ) .get('/menu', async (c) => { const auth = getAuth(c); - if (!auth || !auth.userId) throw new Error('Not Authenticated'); + if (!auth || !auth.userId) return c.json({ error: 'Not Authenticated' }, 401); const profile = await getProfile(c); const role = profile ? Role.parse(profile.role) : undefined; diff --git a/apps/server/tsconfig.test.json b/apps/server/tsconfig.test.json new file mode 100644 index 0000000..ba9cf26 --- /dev/null +++ b/apps/server/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["bun", "node", "./env.d.ts"] + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/apps/share/package.json b/apps/share/package.json index 2492a5b..8956155 100644 --- a/apps/share/package.json +++ b/apps/share/package.json @@ -5,8 +5,7 @@ "exports": { ".": "./index.ts", "./hono": { - "types": "./src/hono.d.ts", - "default": "./src/empty.js" + "types": "./src/hono.d.ts" } }, "scripts": {}, diff --git a/apps/share/src/account.ts b/apps/share/src/account.ts index 3f1300a..51718a6 100644 --- a/apps/share/src/account.ts +++ b/apps/share/src/account.ts @@ -11,8 +11,8 @@ export const AccountMetadata = type({ }); export const AccountInfo = type({ - firstName: 'string?', - lastName: 'string?', - username: 'string?', - profileImage: 'unknown?', + firstName: '(string | undefined)?', + lastName: '(string | undefined)?', + username: '(string | undefined)?', + profileImage: '(unknown)?', }); diff --git a/apps/share/test/account.test.ts b/apps/share/test/account.test.ts new file mode 100644 index 0000000..c5e8fcc --- /dev/null +++ b/apps/share/test/account.test.ts @@ -0,0 +1,175 @@ +import { describe, test, expect } from 'bun:test'; +import { ArkErrors } from 'arktype'; +import { AccountMetadata, AccountInfo } from '../index'; + +function isValid(result: unknown): boolean { + return !(result instanceof ArkErrors); +} + +describe('AccountMetadata', () => { + test('should accept valid full object', () => { + const result = AccountMetadata({ + role: 'admin', + grade: 3, + getGradeAt: '2024-01-01', + joinedAt: 2024, + year: 'b1', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept valid string grade', () => { + const result = AccountMetadata({ + role: 'member', + grade: '2', + getGradeAt: null, + joinedAt: '2024', + year: 'm1', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept valid numeric grade within range', () => { + expect(isValid(AccountMetadata({ role: 'member', grade: -5, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 5, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + }); + + test('should accept valid year formats', () => { + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b4' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'm1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'm2' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'd1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'd2' }))).toBe( + true + ); + }); + + test('should accept valid roles', () => { + expect(isValid(AccountMetadata({ role: 'admin', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'captain', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + expect( + isValid(AccountMetadata({ role: 'vice-captain', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' })) + ).toBe(true); + expect( + isValid(AccountMetadata({ role: 'treasurer', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' })) + ).toBe(true); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + }); + + test('should accept getGradeAt as null or empty string', () => { + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + expect(isValid(AccountMetadata({ role: 'member', grade: 0, getGradeAt: '', joinedAt: 2024, year: 'b1' }))).toBe( + true + ); + }); + + test('should accept getGradeAt as valid date string', () => { + const result = AccountMetadata({ + role: 'member', + grade: 0, + getGradeAt: '2024-06-15', + joinedAt: 2024, + year: 'b1', + }); + expect(isValid(result)).toBe(true); + }); + + test('should reject invalid role', () => { + const result = AccountMetadata({ + role: 'invalid', + grade: 0, + getGradeAt: null, + joinedAt: 2024, + year: 'b1', + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid year format', () => { + const result = AccountMetadata({ + role: 'member', + grade: 0, + getGradeAt: null, + joinedAt: 2024, + year: 'x5', + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid joinedAt (out of range)', () => { + const result = AccountMetadata({ + role: 'member', + grade: 0, + getGradeAt: null, + joinedAt: 2019, + year: 'b1', + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject grade out of range', () => { + expect(isValid(AccountMetadata({ role: 'member', grade: 6, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + false + ); + expect(isValid(AccountMetadata({ role: 'member', grade: -6, getGradeAt: null, joinedAt: 2024, year: 'b1' }))).toBe( + false + ); + }); +}); + +describe('AccountInfo', () => { + test('should accept valid full object', () => { + const result = AccountInfo({ + firstName: 'John', + lastName: 'Doe', + username: 'johndoe', + profileImage: 'https://example.com/image.png', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept empty object', () => { + const result = AccountInfo({}); + expect(isValid(result)).toBe(true); + }); + + test('should accept partial fields', () => { + expect(isValid(AccountInfo({ firstName: 'John' }))).toBe(true); + expect(isValid(AccountInfo({ lastName: 'Doe' }))).toBe(true); + expect(isValid(AccountInfo({ username: 'johndoe' }))).toBe(true); + }); + + test('should accept undefined values for optional fields', () => { + expect(isValid(AccountInfo({ firstName: undefined }))).toBe(true); + }); + + test('should reject null values for optional string fields', () => { + expect(isValid(AccountInfo({ firstName: null }))).toBe(false); + }); +}); diff --git a/apps/share/test/admin.test.ts b/apps/share/test/admin.test.ts new file mode 100644 index 0000000..7a9084d --- /dev/null +++ b/apps/share/test/admin.test.ts @@ -0,0 +1,145 @@ +import { describe, test, expect } from 'bun:test'; +import { ArkErrors } from 'arktype'; +import { AdminUser } from '../index'; + +function isValid(result: unknown): boolean { + return !(result instanceof ArkErrors); +} + +describe('AdminUser', () => { + test('should accept valid full object with nested profile', () => { + const result = AdminUser({ + id: 'user_123', + firstName: 'John', + lastName: 'Doe', + imageUrl: 'https://example.com/image.png', + emailAddress: 'john@example.com', + profile: { + role: 'admin', + roleLabel: '管理者', + grade: 3, + gradeLabel: '三級', + year: 'b1', + yearLabel: '1回生', + joinedAt: 2024, + getGradeAt: '2024-01-01', + }, + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept null for firstName and lastName', () => { + const result = AdminUser({ + id: 'user_123', + firstName: null, + lastName: null, + imageUrl: 'https://example.com/image.png', + emailAddress: null, + profile: { + role: 'member', + roleLabel: '部員', + grade: 0, + gradeLabel: '無級', + year: 'b1', + yearLabel: '1回生', + joinedAt: null, + getGradeAt: null, + }, + }); + expect(isValid(result)).toBe(true); + }); + + test('should reject missing required fields', () => { + const result = AdminUser({ + firstName: 'John', + lastName: 'Doe', + imageUrl: 'https://example.com/image.png', + emailAddress: 'john@example.com', + profile: { + role: 'admin', + roleLabel: '管理者', + grade: 3, + gradeLabel: '三級', + year: 'b1', + yearLabel: '1回生', + joinedAt: 2024, + getGradeAt: '2024-01-01', + }, + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject missing profile', () => { + const result = AdminUser({ + id: 'user_123', + firstName: 'John', + lastName: 'Doe', + imageUrl: 'https://example.com/image.png', + emailAddress: 'john@example.com', + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid types in profile', () => { + const result = AdminUser({ + id: 'user_123', + firstName: 'John', + lastName: 'Doe', + imageUrl: 'https://example.com/image.png', + emailAddress: 'john@example.com', + profile: { + role: 123, + roleLabel: '管理者', + grade: 'three', + gradeLabel: '三級', + year: 'b1', + yearLabel: '1回生', + joinedAt: '2024', + getGradeAt: '2024-01-01', + }, + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid id type', () => { + const result = AdminUser({ + id: 123, + firstName: 'John', + lastName: 'Doe', + imageUrl: 'https://example.com/image.png', + emailAddress: 'john@example.com', + profile: { + role: 'admin', + roleLabel: '管理者', + grade: 3, + gradeLabel: '三級', + year: 'b1', + yearLabel: '1回生', + joinedAt: 2024, + getGradeAt: '2024-01-01', + }, + }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid imageUrl type', () => { + const result = AdminUser({ + id: 'user_123', + firstName: 'John', + lastName: 'Doe', + imageUrl: 123, + emailAddress: 'john@example.com', + profile: { + role: 'admin', + roleLabel: '管理者', + grade: 3, + gradeLabel: '三級', + year: 'b1', + yearLabel: '1回生', + joinedAt: 2024, + getGradeAt: '2024-01-01', + }, + }); + expect(isValid(result)).toBe(false); + }); +}); diff --git a/apps/share/test/clerkClient.test.ts b/apps/share/test/clerkClient.test.ts new file mode 100644 index 0000000..e083b90 --- /dev/null +++ b/apps/share/test/clerkClient.test.ts @@ -0,0 +1,55 @@ +import { describe, test, expect } from 'bun:test'; +import { ArkErrors } from 'arktype'; +import { updateAccountSchema } from '../index'; + +function isValid(result: unknown): boolean { + return !(result instanceof ArkErrors); +} + +describe('updateAccountSchema', () => { + test('should accept valid full object', () => { + const result = updateAccountSchema({ + firstName: 'John', + lastName: 'Doe', + username: 'johndoe', + profileImage: 'https://example.com/image.png', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept empty object', () => { + const result = updateAccountSchema({}); + expect(isValid(result)).toBe(true); + }); + + test('should accept partial fields', () => { + expect(isValid(updateAccountSchema({ firstName: 'John' }))).toBe(true); + expect(isValid(updateAccountSchema({ lastName: 'Doe' }))).toBe(true); + expect(isValid(updateAccountSchema({ username: 'johndoe' }))).toBe(true); + expect(isValid(updateAccountSchema({ profileImage: 'data:image/png;base64,...' }))).toBe(true); + }); + + test('should accept omitting optional fields', () => { + expect(isValid(updateAccountSchema({}))).toBe(true); + expect(isValid(updateAccountSchema({ lastName: 'Doe' }))).toBe(true); + }); + + test('should reject null values for optional string fields', () => { + expect(isValid(updateAccountSchema({ firstName: null }))).toBe(false); + expect(isValid(updateAccountSchema({ lastName: null }))).toBe(false); + expect(isValid(updateAccountSchema({ username: null }))).toBe(false); + }); + + test('should accept any type for profileImage', () => { + expect(isValid(updateAccountSchema({ profileImage: 'string' }))).toBe(true); + expect(isValid(updateAccountSchema({ profileImage: 123 }))).toBe(true); + expect(isValid(updateAccountSchema({ profileImage: null }))).toBe(true); + expect(isValid(updateAccountSchema({ profileImage: {} }))).toBe(true); + }); + + test('should reject non-string types for string fields', () => { + expect(isValid(updateAccountSchema({ firstName: 123 }))).toBe(false); + expect(isValid(updateAccountSchema({ lastName: true }))).toBe(false); + expect(isValid(updateAccountSchema({ username: {} }))).toBe(false); + }); +}); diff --git a/apps/share/test/grade.test.ts b/apps/share/test/grade.test.ts new file mode 100644 index 0000000..d2b9d14 --- /dev/null +++ b/apps/share/test/grade.test.ts @@ -0,0 +1,123 @@ +import { describe, test, expect } from 'bun:test'; +import { grade, translateGrade, timeForNextGrade } from '../index'; + +describe('grade array', () => { + test('should have 11 entries', () => { + expect(grade).toHaveLength(11); + }); + + test('should contain correct grade definitions', () => { + expect(grade).toContainEqual({ name: '無級', grade: 0 }); + expect(grade).toContainEqual({ name: '五級', grade: 5 }); + expect(grade).toContainEqual({ name: '四級', grade: 4 }); + expect(grade).toContainEqual({ name: '三級', grade: 3 }); + expect(grade).toContainEqual({ name: '二級', grade: 2 }); + expect(grade).toContainEqual({ name: '一級', grade: 1 }); + expect(grade).toContainEqual({ name: '初段', grade: -1 }); + expect(grade).toContainEqual({ name: '二段', grade: -2 }); + expect(grade).toContainEqual({ name: '三段', grade: -3 }); + expect(grade).toContainEqual({ name: '四段', grade: -4 }); + expect(grade).toContainEqual({ name: '五段', grade: -5 }); + }); +}); + +describe('translateGrade()', () => { + describe('valid grade names', () => { + test('should translate kyū grades', () => { + expect(translateGrade('無級')).toBe('無級'); + expect(translateGrade('五級')).toBe('五級'); + expect(translateGrade('四級')).toBe('四級'); + expect(translateGrade('三級')).toBe('三級'); + expect(translateGrade('二級')).toBe('二級'); + expect(translateGrade('一級')).toBe('一級'); + }); + + test('should translate dan grades', () => { + expect(translateGrade('初段')).toBe('初段'); + expect(translateGrade('二段')).toBe('二段'); + expect(translateGrade('三段')).toBe('三段'); + expect(translateGrade('四段')).toBe('四段'); + expect(translateGrade('五段')).toBe('五段'); + }); + }); + + describe('valid numeric grades', () => { + test('should translate numeric grades to names', () => { + expect(translateGrade(0)).toBe('無級'); + expect(translateGrade(5)).toBe('五級'); + expect(translateGrade(4)).toBe('四級'); + expect(translateGrade(3)).toBe('三級'); + expect(translateGrade(2)).toBe('二級'); + expect(translateGrade(1)).toBe('一級'); + expect(translateGrade(-1)).toBe('初段'); + expect(translateGrade(-2)).toBe('二段'); + expect(translateGrade(-3)).toBe('三段'); + expect(translateGrade(-4)).toBe('四段'); + expect(translateGrade(-5)).toBe('五段'); + }); + + test('should translate numeric string grades', () => { + expect(translateGrade('0')).toBe('無級'); + expect(translateGrade('5')).toBe('五級'); + expect(translateGrade('-1')).toBe('初段'); + expect(translateGrade('-5')).toBe('五段'); + }); + }); + + describe('invalid inputs', () => { + test('should return 不明 for empty string', () => { + expect(translateGrade('')).toBe('不明'); + }); + + test('should return 不明 for out-of-range numbers', () => { + expect(translateGrade(6)).toBe('不明'); + expect(translateGrade(-6)).toBe('不明'); + expect(translateGrade(100)).toBe('不明'); + }); + + test('should return 不明 for non-numeric strings', () => { + expect(translateGrade('foo')).toBe('不明'); + expect(translateGrade('abc')).toBe('不明'); + }); + }); +}); + +describe('timeForNextGrade()', () => { + test('should return 40 for 無級 (0)', () => { + expect(timeForNextGrade(0)).toBe(40); + expect(timeForNextGrade('0')).toBe(40); + }); + + test('should return 60 for 五級 and 四級 (5, 4)', () => { + expect(timeForNextGrade(5)).toBe(60); + expect(timeForNextGrade(4)).toBe(60); + }); + + test('should return 80 for 三級 and 二級 (3, 2)', () => { + expect(timeForNextGrade(3)).toBe(80); + expect(timeForNextGrade(2)).toBe(80); + }); + + test('should return 100 for 一級 (1)', () => { + expect(timeForNextGrade(1)).toBe(100); + expect(timeForNextGrade('1')).toBe(100); + }); + + test('should return 200 for 初段 (-1)', () => { + expect(timeForNextGrade(-1)).toBe(200); + expect(timeForNextGrade('-1')).toBe(200); + }); + + test('should return 300 for higher dan grades (-2 to -5)', () => { + expect(timeForNextGrade(-2)).toBe(300); + expect(timeForNextGrade(-3)).toBe(300); + expect(timeForNextGrade(-4)).toBe(300); + expect(timeForNextGrade(-5)).toBe(300); + }); + + test('should return 300 for unknown grades', () => { + expect(timeForNextGrade(6)).toBe(300); + expect(timeForNextGrade(-6)).toBe(300); + expect(timeForNextGrade('foo')).toBe(300); + }); +}); diff --git a/apps/share/test/records.test.ts b/apps/share/test/records.test.ts new file mode 100644 index 0000000..d5cbbfd --- /dev/null +++ b/apps/share/test/records.test.ts @@ -0,0 +1,233 @@ +import { describe, test, expect } from 'bun:test'; +import { ArkErrors } from 'arktype'; +import { + recordQuerySchema, + createActivitySchema, + deleteActivitiesSchema, + paginationSchema, + rankingQuerySchema, +} from '../index'; + +function isValid(result: unknown): boolean { + return !(result instanceof ArkErrors); +} + +describe('recordQuerySchema', () => { + test('should accept empty object', () => { + const result = recordQuerySchema({}); + expect(isValid(result)).toBe(true); + }); + + test('should accept valid userId format', () => { + const result = recordQuerySchema({ userId: 'user_abcdefghijklmnopqrstuvwxyz1' }); + expect(isValid(result)).toBe(true); + }); + + test('should accept valid date formats', () => { + const result = recordQuerySchema({ + startDate: '2024-01-01', + endDate: '2024-12-31', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept all valid fields together', () => { + const result = recordQuerySchema({ + userId: 'user_abcdefghijklmnopqrstuvwxyz1', + startDate: '2024-01-01', + endDate: '2024-12-31', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept valid date formats', () => { + const result = recordQuerySchema({ + startDate: '2024-01-01', + endDate: '2024-12-31', + }); + expect(isValid(result)).toBe(true); + }); + + test('should accept all valid fields together', () => { + const result = recordQuerySchema({ + userId: 'user_abcdefghijklmnopqrstuvwxyz1', + startDate: '2024-01-01', + endDate: '2024-12-31', + }); + expect(isValid(result)).toBe(true); + }); + + test('should reject invalid userId format', () => { + const result = recordQuerySchema({ userId: 'invalid' }); + expect(isValid(result)).toBe(false); + }); + + test('should reject userId without user_ prefix', () => { + const result = recordQuerySchema({ userId: 'abcdefghijklmnopqrstuvwxyz1234567' }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid date formats', () => { + const result = recordQuerySchema({ startDate: '01-01-2024' }); + expect(isValid(result)).toBe(false); + }); + + test('should reject non-date strings', () => { + const result = recordQuerySchema({ startDate: 'not-a-date' }); + expect(isValid(result)).toBe(false); + }); +}); + +describe('paginationSchema', () => { + test('should accept valid page and perPage', () => { + const result = paginationSchema({ page: 1, perPage: 10 }); + expect(isValid(result)).toBe(true); + }); + + test('should accept large valid values', () => { + const result = paginationSchema({ page: 100, perPage: 100 }); + expect(isValid(result)).toBe(true); + }); + + test('should accept missing perPage', () => { + const result = paginationSchema({ page: 1 }); + expect(isValid(result)).toBe(true); + }); + + test('should reject page=0', () => { + const result = paginationSchema({ page: 0 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject negative page', () => { + const result = paginationSchema({ page: -1 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject perPage > 100', () => { + const result = paginationSchema({ page: 1, perPage: 101 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject perPage < 1', () => { + const result = paginationSchema({ page: 1, perPage: 0 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject missing page', () => { + const result = paginationSchema({}); + expect(isValid(result)).toBe(false); + }); +}); + +describe('rankingQuerySchema', () => { + test('should accept empty object', () => { + const result = rankingQuerySchema({}); + expect(isValid(result)).toBe(true); + }); + + test('should accept valid year', () => { + const result = rankingQuerySchema({ year: 2024 }); + expect(isValid(result)).toBe(true); + }); + + test('should accept boundary years', () => { + expect(isValid(rankingQuerySchema({ year: 1900 }))).toBe(true); + expect(isValid(rankingQuerySchema({ year: 2099 }))).toBe(true); + }); + + test('should accept valid month', () => { + const result = rankingQuerySchema({ month: 6 }); + expect(isValid(result)).toBe(true); + }); + + test('should accept boundary months', () => { + expect(isValid(rankingQuerySchema({ month: 1 }))).toBe(true); + expect(isValid(rankingQuerySchema({ month: 12 }))).toBe(true); + }); + + test('should accept valid period values', () => { + expect(isValid(rankingQuerySchema({ period: 'monthly' }))).toBe(true); + expect(isValid(rankingQuerySchema({ period: 'annual' }))).toBe(true); + expect(isValid(rankingQuerySchema({ period: 'fiscal' }))).toBe(true); + }); + + test('should reject invalid year (1899)', () => { + const result = rankingQuerySchema({ year: 1899 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid year (2100)', () => { + const result = rankingQuerySchema({ year: 2100 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid month (0)', () => { + const result = rankingQuerySchema({ month: 0 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid month (13)', () => { + const result = rankingQuerySchema({ month: 13 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject invalid period string', () => { + const result = rankingQuerySchema({ period: 'weekly' }); + expect(isValid(result)).toBe(false); + }); +}); + +describe('deleteActivitiesSchema', () => { + test('should accept valid ids array', () => { + const result = deleteActivitiesSchema({ ids: ['a', 'b'] }); + expect(isValid(result)).toBe(true); + }); + + test('should accept empty ids array', () => { + const result = deleteActivitiesSchema({ ids: [] }); + expect(isValid(result)).toBe(true); + }); + + test('should reject non-array ids', () => { + const result = deleteActivitiesSchema({ ids: 'not-array' }); + expect(isValid(result)).toBe(false); + }); + + test('should reject missing ids', () => { + const result = deleteActivitiesSchema({}); + expect(isValid(result)).toBe(false); + }); + + test('should reject array with non-string elements', () => { + const result = deleteActivitiesSchema({ ids: [1, 2] }); + expect(isValid(result)).toBe(false); + }); +}); + +describe('createActivitySchema', () => { + test('should accept valid date and period', () => { + const result = createActivitySchema({ date: '2024-01-01', period: 1.5 }); + expect(isValid(result)).toBe(true); + }); + + test('should reject missing date', () => { + const result = createActivitySchema({ period: 1.5 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject missing period', () => { + const result = createActivitySchema({ date: '2024-01-01', period: 0 }); + expect(isValid(result)).toBe(false); + }); + + test('should reject non-positive period', () => { + const result = createActivitySchema({ date: '2024-01-01', period: -1 }); + expect(isValid(result)).toBe(false); + }); + + test('should accept valid date string', () => { + const result = createActivitySchema({ date: '2024-01-01', period: 1.5 }); + expect(isValid(result)).toBe(true); + }); +}); diff --git a/apps/share/test/role.test.ts b/apps/share/test/role.test.ts new file mode 100644 index 0000000..69d604d --- /dev/null +++ b/apps/share/test/role.test.ts @@ -0,0 +1,158 @@ +import { describe, test, expect } from 'bun:test'; +import { Role } from '../index'; + +describe('Role static instances', () => { + test('should have ADMIN role', () => { + expect(Role.ADMIN.role).toBe('admin'); + expect(Role.ADMIN.ja).toBe('管理者'); + }); + + test('should have CAPTAIN role', () => { + expect(Role.CAPTAIN.role).toBe('captain'); + expect(Role.CAPTAIN.ja).toBe('主将'); + }); + + test('should have VICE_CAPTAIN role', () => { + expect(Role.VICE_CAPTAIN.role).toBe('vice-captain'); + expect(Role.VICE_CAPTAIN.ja).toBe('副主将'); + }); + + test('should have TREASURER role', () => { + expect(Role.TREASURER.role).toBe('treasurer'); + expect(Role.TREASURER.ja).toBe('会計'); + }); + + test('should have MEMBER role', () => { + expect(Role.MEMBER.role).toBe('member'); + expect(Role.MEMBER.ja).toBe('部員'); + }); +}); + +describe('Role.ALL', () => { + test('should contain all 5 roles', () => { + expect(Role.ALL).toHaveLength(5); + expect(Role.ALL).toContain(Role.ADMIN); + expect(Role.ALL).toContain(Role.CAPTAIN); + expect(Role.ALL).toContain(Role.VICE_CAPTAIN); + expect(Role.ALL).toContain(Role.TREASURER); + expect(Role.ALL).toContain(Role.MEMBER); + }); + + test('should have correct ordering', () => { + expect(Role.ALL[0]).toBe(Role.ADMIN); + expect(Role.ALL[1]).toBe(Role.CAPTAIN); + expect(Role.ALL[2]).toBe(Role.VICE_CAPTAIN); + expect(Role.ALL[3]).toBe(Role.TREASURER); + expect(Role.ALL[4]).toBe(Role.MEMBER); + }); +}); + +describe('Role.parse()', () => { + test('should parse valid role strings', () => { + expect(Role.parse('admin')).toBe(Role.ADMIN); + expect(Role.parse('captain')).toBe(Role.CAPTAIN); + expect(Role.parse('vice-captain')).toBe(Role.VICE_CAPTAIN); + expect(Role.parse('treasurer')).toBe(Role.TREASURER); + expect(Role.parse('member')).toBe(Role.MEMBER); + }); + + test('should return undefined for null', () => { + expect(Role.parse(null)).toBeUndefined(); + }); + + test('should return undefined for undefined', () => { + expect(Role.parse(undefined)).toBeUndefined(); + }); + + test('should return undefined for random strings', () => { + expect(Role.parse('foo')).toBeUndefined(); + expect(Role.parse('unknown')).toBeUndefined(); + expect(Role.parse('')).toBeUndefined(); + }); + + test('should return undefined for numbers', () => { + expect(Role.parse(1)).toBeUndefined(); + expect(Role.parse(0)).toBeUndefined(); + }); +}); + +describe('Role.fromString()', () => { + test('should return correct Role instances', () => { + expect(Role.fromString('admin')).toBe(Role.ADMIN); + expect(Role.fromString('captain')).toBe(Role.CAPTAIN); + expect(Role.fromString('vice-captain')).toBe(Role.VICE_CAPTAIN); + expect(Role.fromString('treasurer')).toBe(Role.TREASURER); + expect(Role.fromString('member')).toBe(Role.MEMBER); + }); + + test('should return null for invalid strings', () => { + expect(Role.fromString('foo')).toBeNull(); + expect(Role.fromString('')).toBeNull(); + expect(Role.fromString('unknown')).toBeNull(); + }); +}); + +describe('Role.toString()', () => { + test('should return the role string', () => { + expect(Role.ADMIN.toString()).toBe('admin'); + expect(Role.CAPTAIN.toString()).toBe('captain'); + expect(Role.VICE_CAPTAIN.toString()).toBe('vice-captain'); + expect(Role.TREASURER.toString()).toBe('treasurer'); + expect(Role.MEMBER.toString()).toBe('member'); + }); +}); + +describe('Role.isManagement()', () => { + test('should return true for management roles', () => { + expect(Role.ADMIN.isManagement()).toBe(true); + expect(Role.CAPTAIN.isManagement()).toBe(true); + expect(Role.VICE_CAPTAIN.isManagement()).toBe(true); + expect(Role.TREASURER.isManagement()).toBe(true); + }); + + test('should return false for MEMBER', () => { + expect(Role.MEMBER.isManagement()).toBe(false); + }); +}); + +describe('Role.compare()', () => { + test('should return 0 for same roles', () => { + expect(Role.compare('admin', 'admin')).toBe(0); + expect(Role.compare('member', 'member')).toBe(0); + }); + + test('should return negative when first role has higher priority', () => { + expect(Role.compare('admin', 'captain')).toBeLessThan(0); + expect(Role.compare('captain', 'member')).toBeLessThan(0); + expect(Role.compare('admin', 'member')).toBeLessThan(0); + }); + + test('should return positive when first role has lower priority', () => { + expect(Role.compare('member', 'admin')).toBeGreaterThan(0); + expect(Role.compare('captain', 'admin')).toBeGreaterThan(0); + expect(Role.compare('treasurer', 'vice-captain')).toBeGreaterThan(0); + }); + + test('should handle invalid roles as member', () => { + expect(Role.compare('invalid', 'member')).toBe(0); + expect(Role.compare('admin', 'invalid')).toBeLessThan(0); + }); +}); + +describe('Role.type', () => { + test('should exist as arktype schema', () => { + expect(Role.type).toBeDefined(); + expect(typeof Role.type).toBe('function'); + }); + + test('should validate valid role strings', () => { + const result = Role.type('admin'); + expect(result).toBe('admin'); + }); + + test('should reject invalid role strings', () => { + const { ArkErrors } = require('arktype'); + const result = Role.type('invalid'); + expect(result instanceof ArkErrors).toBe(true); + }); +}); diff --git a/apps/share/test/year.test.ts b/apps/share/test/year.test.ts new file mode 100644 index 0000000..d967684 --- /dev/null +++ b/apps/share/test/year.test.ts @@ -0,0 +1,99 @@ +import { describe, test, expect } from 'bun:test'; +import { year, translateYear } from '../index'; + +describe('year array', () => { + test('should have 8 entries', () => { + expect(year).toHaveLength(8); + }); + + test('should contain correct undergraduate years', () => { + expect(year).toContainEqual({ name: '1回生', year: 'b1' }); + expect(year).toContainEqual({ name: '2回生', year: 'b2' }); + expect(year).toContainEqual({ name: '3回生', year: 'b3' }); + expect(year).toContainEqual({ name: '4回生', year: 'b4' }); + }); + + test('should contain correct graduate years', () => { + expect(year).toContainEqual({ name: '修士1年', year: 'm1' }); + expect(year).toContainEqual({ name: '修士2年', year: 'm2' }); + expect(year).toContainEqual({ name: '博士1年', year: 'd1' }); + expect(year).toContainEqual({ name: '博士2年', year: 'd2' }); + }); +}); + +describe('translateYear()', () => { + describe('valid year codes', () => { + test('should translate b1-b4 to undergraduate labels', () => { + expect(translateYear('b1')).toBe('1回生'); + expect(translateYear('b2')).toBe('2回生'); + expect(translateYear('b3')).toBe('3回生'); + expect(translateYear('b4')).toBe('4回生'); + }); + + test('should translate m1-m2 to master labels', () => { + expect(translateYear('m1')).toBe('修士1年'); + expect(translateYear('m2')).toBe('修士2年'); + }); + + test('should translate d1-d2 to doctoral labels', () => { + expect(translateYear('d1')).toBe('博士1年'); + expect(translateYear('d2')).toBe('博士2年'); + }); + + test('should be case insensitive', () => { + expect(translateYear('B1')).toBe('1回生'); + expect(translateYear('M1')).toBe('修士1年'); + expect(translateYear('D2')).toBe('博士2年'); + }); + }); + + describe('valid Japanese labels', () => { + test('should translate undergraduate labels', () => { + expect(translateYear('1回生')).toBe('1回生'); + expect(translateYear('2回生')).toBe('2回生'); + expect(translateYear('3回生')).toBe('3回生'); + expect(translateYear('4回生')).toBe('4回生'); + }); + + test('should translate graduate labels', () => { + expect(translateYear('修士1年')).toBe('修士1年'); + expect(translateYear('修士2年')).toBe('修士2年'); + expect(translateYear('博士1年')).toBe('博士1年'); + expect(translateYear('博士2年')).toBe('博士2年'); + }); + }); + + describe('valid UI labels', () => { + test('should translate undergraduate UI labels', () => { + expect(translateYear('学部 1年')).toBe('1回生'); + expect(translateYear('学部 2年')).toBe('2回生'); + expect(translateYear('学部 3年')).toBe('3回生'); + expect(translateYear('学部 4年')).toBe('4回生'); + }); + + test('should translate graduate UI labels', () => { + expect(translateYear('修士 1年')).toBe('修士1年'); + expect(translateYear('修士 2年')).toBe('修士2年'); + expect(translateYear('博士 1年')).toBe('博士1年'); + expect(translateYear('博士 2年')).toBe('博士2年'); + }); + }); + + describe('invalid inputs', () => { + test('should return 不明 for empty string', () => { + expect(translateYear('')).toBe('不明'); + }); + + test('should return 不明 for whitespace-only string', () => { + expect(translateYear(' ')).toBe('不明'); + }); + + test('should return 不明 for unknown strings', () => { + expect(translateYear('foo')).toBe('不明'); + expect(translateYear('x5')).toBe('不明'); + expect(translateYear('b5')).toBe('不明'); + expect(translateYear('m3')).toBe('不明'); + expect(translateYear('d3')).toBe('不明'); + }); + }); +}); diff --git a/apps/share/tsconfig.json b/apps/share/tsconfig.json new file mode 100644 index 0000000..ffd11ea --- /dev/null +++ b/apps/share/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": "." + }, + "include": ["index.ts", "src/**/*.ts"] +} diff --git a/apps/share/tsconfig.test.json b/apps/share/tsconfig.test.json new file mode 100644 index 0000000..ed1c267 --- /dev/null +++ b/apps/share/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["bun"] + }, + "include": ["index.ts", "src/**/*.ts", "test/**/*.ts"] +} diff --git a/bun.lock b/bun.lock index 47f0477..fd1805e 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "record", "devDependencies": { + "knip": "latest", "oxfmt": "latest", "oxlint": "latest", "turbo": "2.9.3", @@ -27,6 +28,7 @@ "vue-router": "5.0.4", }, "devDependencies": { + "@types/bun": "latest", "@vitejs/plugin-vue": "6.0.5", "@vue/tsconfig": "0.9.1", "vite": "8.0.3", @@ -310,47 +312,93 @@ "@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="], - "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.115.0", "", { "os": "android", "cpu": "arm" }, "sha512-VoB2rhgoqgYf64d6Qs5emONQW8ASiTc0xp+aUE4JUhxjX+0pE3gblTYDO0upcN5vt9UlBNmUhAwfSifkfre7nw=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.115.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lWRX75u+gqfB4TF3pWCHuvhaeneAmRl2b2qNBcl4S6yJ0HtnT4VXOMEZrq747i4Zby1ZTxj6mtOe678Bg8gRLw=="], + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.115.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ii/oOZjfGY1aszXTy29Z5DRyCEnBOrAXDVCvfdfXFQsOZlbbOa7NMHD7D+06YFe5qdxfmbWAYv4yn6QJi/0d2g=="], + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.115.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-R/sW/p8l77wglbjpMcF+h/3rWbp9zk1mRP3U14mxTYIC2k3m+aLBpXXgk2zksqf9qKk5mcc4GIYsuCn9l8TgDg=="], + "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.121.0", "", { "os": "android", "cpu": "arm" }, "sha512-n07FQcySwOlzap424/PLMtOkbS7xOu8nsJduKL8P3COGHKgKoDYXwoAHCbChfgFpHnviehrLWIPX0lKGtbEk/A=="], - "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.115.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-CSJ5ldNm9wIGGkhaIJeGmxRMZbgxThRN+X1ufYQQUNi5jZDV/U3C2QDMywpP93fczNBj961hXtcUPO/oVGq4Pw=="], + "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.121.0", "", { "os": "android", "cpu": "arm64" }, "sha512-/Dd1xIXboYAicw+twT2utxPD7bL8qh7d3ej0qvaYIMj3/EgIrGR+tSnjCUkiCT6g6uTC0neSS4JY8LxhdSU/sA=="], - "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.115.0", "", { "os": "linux", "cpu": "arm" }, "sha512-uWFwssE5dHfQ8lH+ktrsD9JA49+Qa0gtxZHUs62z1e91NgGz6O7jefHGI6aygNyKNS45pnnBSDSP/zV977MsOQ=="], + "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.121.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-A0jNEvv7QMtCO1yk205t3DWU9sWUjQ2KNF0hSVO5W9R9r/R1BIvzG01UQAfmtC0dQm7sCrs5puixurKSfr2bRQ=="], - "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.115.0", "", { "os": "linux", "cpu": "arm" }, "sha512-fZbqt8y/sKQ+v6bBCuv/mYYFoC0+fZI3mGDDEemmDOhT78+aUs2+4ZMdbd2btlXmnLaScl37r8IRbhnok5Ka9w=="], + "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.121.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-SsHzipdxTKUs3I9EOAPmnIimEeJOemqRlRDOp9LIj+96wtxZejF51gNibmoGq8KoqbT1ssAI5po/E3J+vEtXGA=="], - "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.115.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-1ej/MjuTY9tJEunU/hUPIFmgH5PqgMQoRjNOvOkibtJ3Zqlw/+Lc+HGHDNET8sjbgIkWzdhX+p4J96A5CPdbag=="], + "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.121.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-v1APOTkCp+RWOIDAHRoaeW/UoaHF15a60E8eUL6kUQXh+i4K7PBwq2Wi7jm8p0ymID5/m/oC1w3W31Z/+r7HQw=="], - "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.115.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-HjsZbJPH9mMd4swJRywVMsDZsJX0hyKb1iNHo5ijRl5yhtbO3lj7ImSrrL1oZ1VEg0te4iKmDGGz/6YPLd1G8w=="], + "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.121.0", "", { "os": "linux", "cpu": "arm" }, "sha512-PmqPQuqHZyFVWA4ycr0eu4VnTMmq9laOHZd+8R359w6kzuNZPvmmunmNJ8ybkm769A0nCoVp3TJ6dUz7B3FYIQ=="], - "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.115.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-zhhePoBrd7kQx3oClX/W6NldsuCbuMqaN9rRsY+6/WoorAb4j490PG/FjqgAXscWp2uSW2WV9L+ksn0wHrvsrg=="], + "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.121.0", "", { "os": "linux", "cpu": "arm" }, "sha512-vF24htj+MOH+Q7y9A8NuC6pUZu8t/C2Fr/kDOi2OcNf28oogr2xadBPXAbml802E8wRAVfbta6YLDQTearz+jw=="], - "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.115.0", "", { "os": "linux", "cpu": "none" }, "sha512-t/IRojvUE9XrKu+/H1b8YINug+7Q6FLls5rsm2lxB5mnS8GN/eYAYrPgHkcg9/1SueRDSzGpDYu3lGWTObk1zw=="], + "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.121.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-wjH8cIG2Lu/3d64iZpbYr73hREMgKAfu7fqpXjgM2S16y2zhTfDIp8EQjxO8vlDtKP5Rc7waZW72lh8nZtWrpA=="], - "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.115.0", "", { "os": "linux", "cpu": "none" }, "sha512-79jBHSSh/YpQRAmvYoaCfpyToRbJ/HBrdB7hxK2ku2JMehjopTVo+xMJss/RV7/ZYqeezgjvKDQzapJbgcjVZA=="], + "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.121.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qT663J/W8yQFw3dtscbEi9LKJevr20V7uWs2MPGTnvNZ3rm8anhhE16gXGpxDOHeg9raySaSHKhd4IGa3YZvuw=="], - "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.115.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-nA1TpxkhNTIOMMyiSSsa7XIVJVoOU/SsVrHIz3gHvWweB5PHCQfO7w+Lb2EP0lBWokv7HtA/KbF7aLDoXzmuMw=="], + "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.121.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-mYNe4NhVvDBbPkAP8JaVS8lC1dsoJZWH5WCjpw5E+sjhk1R08wt3NnXYUzum7tIiWPfgQxbCMcoxgeemFASbRw=="], - "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.115.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9iVX789DoC3SaOOG+X6NcF/tVChgLp2vcHffzOC2/Z1JTPlz6bMG2ogvcW6/9s0BG2qvhNQImd+gbWYeQbOwVw=="], + "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.121.0", "", { "os": "linux", "cpu": "none" }, "sha512-+QiFoGxhAbaI/amqX567784cDyyuZIpinBrJNxUzb+/L2aBRX67mN6Jv40pqduHf15yYByI+K5gUEygCuv0z9w=="], - "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.115.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RmQmk+mjCB0nMNfEYhaCxwofLo1Z95ebHw1AGvRiWGCd4zhCNOyskgCbMogIcQzSB3SuEKWgkssyaiQYVAA4hQ=="], + "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.121.0", "", { "os": "linux", "cpu": "none" }, "sha512-9ykEgyTa5JD/Uhv2sttbKnCfl2PieUfOjyxJC/oDL2UO0qtXOtjPLl7H8Kaj5G7p3hIvFgu3YWvAxvE0sqY+hQ=="], - "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.115.0", "", { "os": "none", "cpu": "arm64" }, "sha512-viigraWWQhhDvX5aGq+wrQq58k00Xq3MHz/0R4AFMxGlZ8ogNonpEfNc73Q5Ly87Z6sU9BvxEdG0dnYTfVnmew=="], + "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.121.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-DB1EW5VHZdc1lIRjOI3bW/wV6R6y0xlfvdVrqj6kKi7Ayu2U3UqUBdq9KviVkcUGd5Oq+dROqvUEEFRXGAM7EQ=="], - "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.115.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-IzGCrMwXhpb4kTXy/8lnqqqwjI7eOvy+r9AhVw+hsr8t1ecBBEHprcNy0aKatFHN6hsX7UMHHQmBAQjVvL/p1A=="], + "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.121.0", "", { "os": "linux", "cpu": "x64" }, "sha512-s4lfobX9p4kPTclvMiH3gcQUd88VlnkMTF6n2MTMDAyX5FPNRhhRSFZK05Ykhf8Zy5NibV4PbGR6DnK7FGNN6A=="], - "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.115.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-/ym+Absk/TLFvbhh3se9XYuI1D7BrUVHw4RaG/2dmWKgBenrZHaJsgnRb7NJtaOyjEOLIPtULx1wDdVL0SX2eg=="], + "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.121.0", "", { "os": "linux", "cpu": "x64" }, "sha512-P9KlyTpuBuMi3NRGpJO8MicuGZfOoqZVRP1WjOecwx8yk4L/+mrCRNc5egSi0byhuReblBF2oVoDSMgV9Bj4Hw=="], - "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.115.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-AQSZjIR+b+Te7uaO/hGTMjT8/oxlYrvKrOTi4KTHF/O6osjHEatUQ3y6ZW2+8+lJxy20zIcGz6iQFmFq/qDKkg=="], + "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.121.0", "", { "os": "none", "cpu": "arm64" }, "sha512-R+4jrWOfF2OAPPhj3Eb3U5CaKNAH9/btMveMULIrcNW/hjfysFQlF8wE0GaVBr81dWz8JLgQlsxwctoL78JwXw=="], - "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.115.0", "", { "os": "win32", "cpu": "x64" }, "sha512-oxUl82N+fIO9jIaXPph8SPPHQXrA08BHokBBJW8ct9F/x6o6bZE6eUAhUtWajbtvFhL8UYcCWRMba+kww6MBlA=="], + "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.121.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-5TFISkPTymKvsmIlKasPVTPuWxzCcrT8pM+p77+mtQbIZDd1UC8zww4CJcRI46kolmgrEX6QpKO8AvWMVZ+ifw=="], - "@oxc-project/types": ["@oxc-project/types@0.122.0", "", {}, "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA=="], + "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.121.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V0pxh4mql4XTt3aiEtRNUeBAUFOw5jzZNxPABLaOKAWrVzSr9+XUaB095lY7jqMf5t8vkfh8NManGB28zanYKw=="], + + "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.121.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-4Ob1qvYMPnlF2N9rdmKdkQFdrq16QVcQwBsO8yiPZXof0fHKFF+LmQV501XFbi7lHyrKm8rlJRfQ/M8bZZPVLw=="], + + "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.121.0", "", { "os": "win32", "cpu": "x64" }, "sha512-BOp1KCzdboB1tPqoCPXgntgFs0jjeSyOXHzgxVFR7B/qfr3F8r4YDacHkTOUNXtDgM8YwKnkf3rE5gwALYX7NA=="], + + "@oxc-project/types": ["@oxc-project/types@0.121.0", "", {}, "sha512-CGtOARQb9tyv7ECgdAlFxi0Fv7lmzvmlm2rpD/RdijOO9rfk/JvB1CjT8EnoD+tjna/IYgKKw3IV7objRb+aYw=="], + + "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="], + + "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.19.1", "", { "os": "android", "cpu": "arm64" }, "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA=="], + + "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.19.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ=="], + + "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.19.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ=="], + + "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.19.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw=="], + + "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A=="], + + "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ=="], + + "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig=="], + + "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew=="], + + "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.19.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ=="], + + "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w=="], + + "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw=="], + + "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.19.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA=="], + + "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ=="], + + "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw=="], + + "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.19.1", "", { "os": "none", "cpu": "arm64" }, "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA=="], + + "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.19.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg=="], + + "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.19.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ=="], + + "@oxc-resolver/binding-win32-ia32-msvc": ["@oxc-resolver/binding-win32-ia32-msvc@11.19.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA=="], + + "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.19.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw=="], "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.43.0", "", { "os": "android", "cpu": "arm" }, "sha512-CgU2s+/9hHZgo0IxVxrbMPrMj+tJ6VM3mD7Mr/4oiz4FNTISLoCvRmB5nk4wAAle045RtRjd86m673jwPyb1OQ=="], @@ -502,6 +550,8 @@ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/mssql": ["@types/mssql@9.1.11", "", { "dependencies": { "@types/node": "*", "tarn": "^3.0.1", "tedious": "*" } }, "sha512-vcujgrDbDezCxNDO4KY6gjwduLYOKfrexpRUwhoysRvcXZ3+IgZ/PMYFDgh8c3cQIxZ6skAwYo+H6ibMrBWPjQ=="], @@ -608,10 +658,14 @@ "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], @@ -678,18 +732,30 @@ "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="], + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "formatly": ["formatly@0.3.0", "", { "dependencies": { "fd-package-json": "^2.0.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w=="], + "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "get-tsconfig": ["get-tsconfig@4.13.7", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q=="], + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], "gzip-size": ["gzip-size@6.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="], @@ -710,8 +776,14 @@ "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], @@ -736,6 +808,8 @@ "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "knip": ["knip@6.3.0", "", { "dependencies": { "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", "formatly": "^0.3.0", "get-tsconfig": "4.13.7", "jiti": "^2.6.0", "minimist": "^1.2.8", "oxc-parser": "^0.121.0", "oxc-resolver": "^11.19.1", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.6.1", "strip-json-comments": "5.0.3", "unbash": "^2.2.0", "yaml": "^2.8.2", "zod": "^4.1.11" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-g6dVPoTw6iNm3cubC5IWxVkVsd0r5hXhTBTbAGIEQN53GdA2ZM/slMTPJ7n5l8pBebNQPHpxjmKxuR4xVQ2/hQ=="], + "libsql": ["libsql@0.5.29", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.29", "@libsql/darwin-x64": "0.5.29", "@libsql/linux-arm-gnueabihf": "0.5.29", "@libsql/linux-arm-musleabihf": "0.5.29", "@libsql/linux-arm64-gnu": "0.5.29", "@libsql/linux-arm64-musl": "0.5.29", "@libsql/linux-x64-gnu": "0.5.29", "@libsql/linux-x64-musl": "0.5.29", "@libsql/win32-x64-msvc": "0.5.29" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg=="], "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], @@ -786,8 +860,14 @@ "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "miniflare": ["miniflare@4.20260401.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260401.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-lngHPzZFN9sxYG/mhzvnWiBMNVAN5MsO/7g32ttJ07rymtiK/ZBalODTKb8Od+BQdlU5DOR4CjVt9NydjnUyYg=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], @@ -812,7 +892,9 @@ "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], - "oxc-parser": ["oxc-parser@0.115.0", "", { "dependencies": { "@oxc-project/types": "^0.115.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.115.0", "@oxc-parser/binding-android-arm64": "0.115.0", "@oxc-parser/binding-darwin-arm64": "0.115.0", "@oxc-parser/binding-darwin-x64": "0.115.0", "@oxc-parser/binding-freebsd-x64": "0.115.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.115.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.115.0", "@oxc-parser/binding-linux-arm64-gnu": "0.115.0", "@oxc-parser/binding-linux-arm64-musl": "0.115.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.115.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.115.0", "@oxc-parser/binding-linux-riscv64-musl": "0.115.0", "@oxc-parser/binding-linux-s390x-gnu": "0.115.0", "@oxc-parser/binding-linux-x64-gnu": "0.115.0", "@oxc-parser/binding-linux-x64-musl": "0.115.0", "@oxc-parser/binding-openharmony-arm64": "0.115.0", "@oxc-parser/binding-wasm32-wasi": "0.115.0", "@oxc-parser/binding-win32-arm64-msvc": "0.115.0", "@oxc-parser/binding-win32-ia32-msvc": "0.115.0", "@oxc-parser/binding-win32-x64-msvc": "0.115.0" } }, "sha512-2w7Xn3CbS/zwzSY82S5WLemrRu3CT57uF7Lx8llrE/2bul6iMTcJE4Rbls7GDNbLn3ttATI68PfOz2Pt3KZ2cQ=="], + "oxc-parser": ["oxc-parser@0.121.0", "", { "dependencies": { "@oxc-project/types": "^0.121.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.121.0", "@oxc-parser/binding-android-arm64": "0.121.0", "@oxc-parser/binding-darwin-arm64": "0.121.0", "@oxc-parser/binding-darwin-x64": "0.121.0", "@oxc-parser/binding-freebsd-x64": "0.121.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.121.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.121.0", "@oxc-parser/binding-linux-arm64-gnu": "0.121.0", "@oxc-parser/binding-linux-arm64-musl": "0.121.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.121.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.121.0", "@oxc-parser/binding-linux-riscv64-musl": "0.121.0", "@oxc-parser/binding-linux-s390x-gnu": "0.121.0", "@oxc-parser/binding-linux-x64-gnu": "0.121.0", "@oxc-parser/binding-linux-x64-musl": "0.121.0", "@oxc-parser/binding-openharmony-arm64": "0.121.0", "@oxc-parser/binding-wasm32-wasi": "0.121.0", "@oxc-parser/binding-win32-arm64-msvc": "0.121.0", "@oxc-parser/binding-win32-ia32-msvc": "0.121.0", "@oxc-parser/binding-win32-x64-msvc": "0.121.0" } }, "sha512-ek9o58+SCv6AV7nchiAcUJy1DNE2CC5WRdBcO0mF+W4oRjNQfPO7b3pLjTHSFECpHkKGOZSQxx3hk8viIL5YCg=="], + + "oxc-resolver": ["oxc-resolver@11.19.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.19.1", "@oxc-resolver/binding-android-arm64": "11.19.1", "@oxc-resolver/binding-darwin-arm64": "11.19.1", "@oxc-resolver/binding-darwin-x64": "11.19.1", "@oxc-resolver/binding-freebsd-x64": "11.19.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-musl": "11.19.1", "@oxc-resolver/binding-openharmony-arm64": "11.19.1", "@oxc-resolver/binding-wasm32-wasi": "11.19.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" } }, "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg=="], "oxc-walker": ["oxc-walker@0.7.0", "", { "dependencies": { "magic-regexp": "^0.10.0" }, "peerDependencies": { "oxc-parser": ">=0.98.0" } }, "sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A=="], @@ -842,6 +924,8 @@ "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], @@ -854,12 +938,16 @@ "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], "rolldown": ["rolldown@1.0.0-rc.12", "", { "dependencies": { "@oxc-project/types": "=0.122.0", "@rolldown/pluginutils": "1.0.0-rc.12" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-x64": "1.0.0-rc.12", "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A=="], "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], @@ -876,6 +964,8 @@ "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], + "smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], @@ -886,6 +976,8 @@ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], "svix": ["svix@1.90.0", "", { "dependencies": { "standardwebhooks": "1.0.0", "uuid": "^10.0.0" } }, "sha512-ljkZuyy2+IBEoESkIpn8sLM+sxJHQcPxlZFxU+nVDhltNfUMisMBzWX/UR8SjEnzoI28ZjCzMbmYAPwSTucoMw=="], @@ -902,6 +994,8 @@ "tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], @@ -918,6 +1012,8 @@ "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + "unbash": ["unbash@2.2.0", "", {}, "sha512-X2wH19RAPZE3+ldGicOkoj/SIA83OIxcJ6Cuaw23hf8Xc6fQpvZXY0SftE2JgS0QhYLUG4uwodSI3R53keyh7w=="], + "unconfig": ["unconfig@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "defu": "^6.1.4", "jiti": "^2.6.1", "quansync": "^1.0.0", "unconfig-core": "7.5.0" } }, "sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA=="], "unconfig-core": ["unconfig-core@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w=="], @@ -946,6 +1042,8 @@ "vue-router": ["vue-router@5.0.4", "", { "dependencies": { "@babel/generator": "^7.28.6", "@vue-macros/common": "^3.1.1", "@vue/devtools-api": "^8.0.6", "ast-walker-scope": "^0.8.3", "chokidar": "^5.0.0", "json5": "^2.2.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "muggle-string": "^0.4.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "scule": "^1.3.0", "tinyglobby": "^0.2.15", "unplugin": "^3.0.0", "unplugin-utils": "^0.3.1", "yaml": "^2.8.2" }, "peerDependencies": { "@pinia/colada": ">=0.21.2", "@vue/compiler-sfc": "^3.5.17", "pinia": "^3.0.4", "vue": "^3.5.0" }, "optionalPeers": ["@pinia/colada", "@vue/compiler-sfc", "pinia"] }, "sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg=="], + "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -968,6 +1066,8 @@ "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + "@azure/msal-node/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], "@clerk/shared/@tanstack/query-core": ["@tanstack/query-core@5.90.16", "", {}, "sha512-MvtWckSVufs/ja463/K4PyJeqT+HMlJWtw6PrCpywznd2NSgO3m4KwO9RqbFqGg6iDE8vVMFWMeQI4Io3eEYww=="], @@ -982,6 +1082,8 @@ "@quansync/fs/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], + "@unocss/transformer-attributify-jsx/oxc-parser": ["oxc-parser@0.115.0", "", { "dependencies": { "@oxc-project/types": "^0.115.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.115.0", "@oxc-parser/binding-android-arm64": "0.115.0", "@oxc-parser/binding-darwin-arm64": "0.115.0", "@oxc-parser/binding-darwin-x64": "0.115.0", "@oxc-parser/binding-freebsd-x64": "0.115.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.115.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.115.0", "@oxc-parser/binding-linux-arm64-gnu": "0.115.0", "@oxc-parser/binding-linux-arm64-musl": "0.115.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.115.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.115.0", "@oxc-parser/binding-linux-riscv64-musl": "0.115.0", "@oxc-parser/binding-linux-s390x-gnu": "0.115.0", "@oxc-parser/binding-linux-x64-gnu": "0.115.0", "@oxc-parser/binding-linux-x64-musl": "0.115.0", "@oxc-parser/binding-openharmony-arm64": "0.115.0", "@oxc-parser/binding-wasm32-wasi": "0.115.0", "@oxc-parser/binding-win32-arm64-msvc": "0.115.0", "@oxc-parser/binding-win32-ia32-msvc": "0.115.0", "@oxc-parser/binding-win32-x64-msvc": "0.115.0" } }, "sha512-2w7Xn3CbS/zwzSY82S5WLemrRu3CT57uF7Lx8llrE/2bul6iMTcJE4Rbls7GDNbLn3ttATI68PfOz2Pt3KZ2cQ=="], + "cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="], @@ -990,9 +1092,11 @@ "magic-regexp/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], + "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], - "oxc-parser/@oxc-project/types": ["@oxc-project/types@0.115.0", "", {}, "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw=="], + "rolldown/@oxc-project/types": ["@oxc-project/types@0.122.0", "", {}, "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA=="], "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.12", "", {}, "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw=="], @@ -1010,6 +1114,48 @@ "@hono/clerk-auth/@clerk/shared/csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.115.0", "", { "os": "android", "cpu": "arm" }, "sha512-VoB2rhgoqgYf64d6Qs5emONQW8ASiTc0xp+aUE4JUhxjX+0pE3gblTYDO0upcN5vt9UlBNmUhAwfSifkfre7nw=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.115.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lWRX75u+gqfB4TF3pWCHuvhaeneAmRl2b2qNBcl4S6yJ0HtnT4VXOMEZrq747i4Zby1ZTxj6mtOe678Bg8gRLw=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.115.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ii/oOZjfGY1aszXTy29Z5DRyCEnBOrAXDVCvfdfXFQsOZlbbOa7NMHD7D+06YFe5qdxfmbWAYv4yn6QJi/0d2g=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.115.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-R/sW/p8l77wglbjpMcF+h/3rWbp9zk1mRP3U14mxTYIC2k3m+aLBpXXgk2zksqf9qKk5mcc4GIYsuCn9l8TgDg=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.115.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-CSJ5ldNm9wIGGkhaIJeGmxRMZbgxThRN+X1ufYQQUNi5jZDV/U3C2QDMywpP93fczNBj961hXtcUPO/oVGq4Pw=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.115.0", "", { "os": "linux", "cpu": "arm" }, "sha512-uWFwssE5dHfQ8lH+ktrsD9JA49+Qa0gtxZHUs62z1e91NgGz6O7jefHGI6aygNyKNS45pnnBSDSP/zV977MsOQ=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.115.0", "", { "os": "linux", "cpu": "arm" }, "sha512-fZbqt8y/sKQ+v6bBCuv/mYYFoC0+fZI3mGDDEemmDOhT78+aUs2+4ZMdbd2btlXmnLaScl37r8IRbhnok5Ka9w=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.115.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-1ej/MjuTY9tJEunU/hUPIFmgH5PqgMQoRjNOvOkibtJ3Zqlw/+Lc+HGHDNET8sjbgIkWzdhX+p4J96A5CPdbag=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.115.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-HjsZbJPH9mMd4swJRywVMsDZsJX0hyKb1iNHo5ijRl5yhtbO3lj7ImSrrL1oZ1VEg0te4iKmDGGz/6YPLd1G8w=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.115.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-zhhePoBrd7kQx3oClX/W6NldsuCbuMqaN9rRsY+6/WoorAb4j490PG/FjqgAXscWp2uSW2WV9L+ksn0wHrvsrg=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.115.0", "", { "os": "linux", "cpu": "none" }, "sha512-t/IRojvUE9XrKu+/H1b8YINug+7Q6FLls5rsm2lxB5mnS8GN/eYAYrPgHkcg9/1SueRDSzGpDYu3lGWTObk1zw=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.115.0", "", { "os": "linux", "cpu": "none" }, "sha512-79jBHSSh/YpQRAmvYoaCfpyToRbJ/HBrdB7hxK2ku2JMehjopTVo+xMJss/RV7/ZYqeezgjvKDQzapJbgcjVZA=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.115.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-nA1TpxkhNTIOMMyiSSsa7XIVJVoOU/SsVrHIz3gHvWweB5PHCQfO7w+Lb2EP0lBWokv7HtA/KbF7aLDoXzmuMw=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.115.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9iVX789DoC3SaOOG+X6NcF/tVChgLp2vcHffzOC2/Z1JTPlz6bMG2ogvcW6/9s0BG2qvhNQImd+gbWYeQbOwVw=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.115.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RmQmk+mjCB0nMNfEYhaCxwofLo1Z95ebHw1AGvRiWGCd4zhCNOyskgCbMogIcQzSB3SuEKWgkssyaiQYVAA4hQ=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.115.0", "", { "os": "none", "cpu": "arm64" }, "sha512-viigraWWQhhDvX5aGq+wrQq58k00Xq3MHz/0R4AFMxGlZ8ogNonpEfNc73Q5Ly87Z6sU9BvxEdG0dnYTfVnmew=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.115.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-IzGCrMwXhpb4kTXy/8lnqqqwjI7eOvy+r9AhVw+hsr8t1ecBBEHprcNy0aKatFHN6hsX7UMHHQmBAQjVvL/p1A=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.115.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-/ym+Absk/TLFvbhh3se9XYuI1D7BrUVHw4RaG/2dmWKgBenrZHaJsgnRb7NJtaOyjEOLIPtULx1wDdVL0SX2eg=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.115.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-AQSZjIR+b+Te7uaO/hGTMjT8/oxlYrvKrOTi4KTHF/O6osjHEatUQ3y6ZW2+8+lJxy20zIcGz6iQFmFq/qDKkg=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.115.0", "", { "os": "win32", "cpu": "x64" }, "sha512-oxUl82N+fIO9jIaXPph8SPPHQXrA08BHokBBJW8ct9F/x6o6bZE6eUAhUtWajbtvFhL8UYcCWRMba+kww6MBlA=="], + + "@unocss/transformer-attributify-jsx/oxc-parser/@oxc-project/types": ["@oxc-project/types@0.115.0", "", {}, "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw=="], + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], diff --git a/knip.json b/knip.json index 57f2657..7bb174f 100644 --- a/knip.json +++ b/knip.json @@ -5,7 +5,7 @@ "apps/server": {}, "apps/share": {} }, - "ignoreFiles": [".direnv/**", "./**/env.d.ts"], + "ignoreFiles": [".direnv/**", "./**/env.d.ts", "**/test/**"], "ignoreDependencies": ["@vue/tsconfig"], "ignoreBinaries": ["turso"] } diff --git a/package.json b/package.json index 777ea21..b14cdea 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,12 @@ "build": "turbo build", "dev": "bunx turbo dev", "format": "oxfmt --write .", - "knip": "bunx knip", + "knip": "knip", "lint": "oxlint .", "lint:fix": "oxlint --fix ." }, "devDependencies": { + "knip": "latest", "oxfmt": "latest", "oxlint": "latest", "turbo": "2.9.3"