diff --git a/.env.example b/.env.example index 9194c4d..b5ac4cd 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,19 @@ -# Leave empty for local environment / no api authentication -API_URL=http://localhost:3000 - # Set to production NODE_ENV=development +# OFFLINE or ONLINE, change editor mode beetween local execution and online execution +PUBLIC_MODE=OFFLINE + +# Project Manager +PUBLIC_PM_URL=https://projects.nanoforge.eu + +# Api params (required if PUBLIC_MODE=ONLINE) +API_URL=http://localhost:3000 +API_KEY=test + +# Fs root dir read/write projects (leave empty to select current directory) (if you use relative path, it will be /) +FS_ROOT= + # Leaving this empty will generate a new unique random session secret at start SESSION_SECRET= diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 41961b7..8273a67 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -30,6 +30,9 @@ jobs: - name: Prepare uses: ./.github/actions/prepare + env: + PUBLIC_MODE: ${{ vars.PUBLIC_MODE }} + PUBLIC_PM_URL: ${{ vars.PUBLIC_PM_URL }} - name: Release packages uses: ./node_modules/@nanoforge-dev/actions/dist/create-release-pr diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 69e84c1..8e92df5 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -21,6 +21,9 @@ jobs: - name: Prepare uses: ./.github/actions/prepare + env: + PUBLIC_MODE: ${{ vars.PUBLIC_MODE }} + PUBLIC_PM_URL: ${{ vars.PUBLIC_PM_URL }} - name: Create release tag uses: ./node_modules/@nanoforge-dev/actions/dist/create-release-tag diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0faa30a..1bd5b12 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,9 @@ jobs: - name: Prepare uses: ./.github/actions/prepare + env: + PUBLIC_MODE: ${{ vars.PUBLIC_MODE }} + PUBLIC_PM_URL: ${{ vars.PUBLIC_PM_URL }} - name: Release packages uses: ./node_modules/@nanoforge-dev/actions/dist/release-packages diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 30c2e07..c91deaa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,6 +18,9 @@ jobs: - name: Prepare uses: ./.github/actions/prepare + env: + PUBLIC_MODE: ${{ vars.PUBLIC_MODE }} + PUBLIC_PM_URL: ${{ vars.PUBLIC_PM_URL }} - name: Run linter run: pnpm lint diff --git a/.gitignore b/.gitignore index b2b5556..f984847 100644 --- a/.gitignore +++ b/.gitignore @@ -229,6 +229,5 @@ dist .svelte-kit/ test-results/ -package -public/ \ No newline at end of file +public/assets/fonts/ diff --git a/.husky/commit-msg b/.husky/commit-msg index 2a397b8..9ef41ae 100644 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1 +1 @@ -pnpm --no-install commitlint --edit "$1" +pnpm commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit index c7acc22..cb2c84d 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -pnpm --no-install lint-staged +pnpm lint-staged diff --git a/.idea/[NanoForge] Editor.iml b/.idea/[NanoForge] Editor.iml index 24643cc..668cacb 100644 --- a/.idea/[NanoForge] Editor.iml +++ b/.idea/[NanoForge] Editor.iml @@ -2,9 +2,13 @@ - - + + + + + + diff --git a/components.json b/components.json new file mode 100644 index 0000000..a74b7b4 --- /dev/null +++ b/components.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://shadcn-svelte.com/schema.json", + "style": "nova", + "aliases": { + "lib": "$lib", + "components": "$lib/components/ui", + "hooks": "$lib/hooks", + "utils": "@utils/ui" + }, + "tailwind": { + "baseColor": "neutral", + "css": "src/app.css" + }, + "typescript": true +} diff --git a/eslint.config.js b/eslint.config.js index 5fa6710..5f52b7a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -24,6 +24,8 @@ export default [ { rules: { 'svelte/no-unused-svelte-ignore': 'off', + 'svelte/no-navigation-without-resolve': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', }, }, ]; diff --git a/package.json b/package.json index 4f66737..d80d240 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,9 @@ }, "funding": "https://github.com/NanoForge-dev/Editor?sponsor", "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview", + "dev": "bun --bun run vite dev", + "build": "bun --bun run vite build", + "preview": "bun --bun run vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --check . && eslint --format=pretty src", @@ -61,6 +61,8 @@ "@iconify-json/material-icon-theme": "catalog:icons", "@iconify-json/solar": "catalog:icons", "@inlang/paraglide-js": "catalog:i18n", + "@internationalized/date": "catalog:libs-front", + "@lucide/svelte": "catalog:icons", "@nanoforge-dev/actions": "catalog:ci", "@nanoforge-dev/ecs-lib": "catalog:core", "@nanoforge-dev/utils-eslint-config": "catalog:lint", @@ -68,6 +70,7 @@ "@playwright/test": "catalog:test", "@sveltejs/kit": "catalog:core", "@sveltejs/vite-plugin-svelte": "catalog:core", + "@tanstack/svelte-query": "catalog:libs-front", "@trivago/prettier-plugin-sort-imports": "catalog:lint", "@tsconfig/svelte": "catalog:build", "@types/bun": "catalog:core", @@ -77,13 +80,19 @@ "@unocss/preset-wind4": "catalog:css", "@vitest/browser-playwright": "catalog:test", "@vitest/coverage-v8": "catalog:test", + "bits-ui": "catalog:components", + "bun": "catalog:core", + "clsx": "catalog:css", + "dotenv": "catalog:libs-back", "eslint": "catalog:lint", "eslint-plugin-svelte": "catalog:lint", "flowbite": "catalog:components", "flowbite-svelte": "catalog:components", + "formsnap": "catalog:libs-front", "globals": "catalog:lint", "husky": "catalog:ci", "lint-staged": "catalog:ci", + "mode-watcher": "catalog:libs-front", "monaco-editor": "catalog:components", "playwright": "catalog:test", "prettier": "catalog:lint", @@ -92,15 +101,20 @@ "svelte-adapter-bun": "catalog:build", "svelte-check": "catalog:core", "svelte-kit-sessions": "catalog:core", - "svelte-sonner": "catalog:components", + "svelte-sonner": "catalog:libs-front", + "sveltekit-superforms": "catalog:libs-front", + "tailwind-merge": "catalog:css", + "tailwind-variants": "catalog:css", + "tailwindcss": "catalog:css", "typescript": "catalog:build", "typescript-eslint": "catalog:lint", "unocss": "catalog:css", "vite": "catalog:core", "vitest": "catalog:test", - "vitest-browser-svelte": "catalog:test" + "vitest-browser-svelte": "catalog:test", + "zod": "catalog:libs-front" }, - "packageManager": "pnpm@10.33.0", + "packageManager": "pnpm@11.3.0", "engines": { "node": "25" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a85d308..f661cd4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,98 +13,142 @@ catalogs: specifier: ^1.0.1 version: 1.0.1 typescript: - specifier: ^6.0.2 + specifier: ^6.0.3 version: 6.0.3 ci: '@commitlint/cli': - specifier: ^20.5.0 - version: 20.5.0 + specifier: ^21.0.1 + version: 21.0.1 '@commitlint/config-conventional': - specifier: ^20.5.0 - version: 20.5.0 + specifier: ^21.0.1 + version: 21.0.1 '@favware/cliff-jumper': specifier: ^6.1.0 version: 6.1.0 '@nanoforge-dev/actions': - specifier: ^1.2.3 - version: 1.2.3 + specifier: ^2.0.0 + version: 2.0.0 husky: specifier: ^9.1.7 version: 9.1.7 lint-staged: - specifier: ^16.4.0 - version: 16.4.0 + specifier: ^17.0.5 + version: 17.0.5 components: + bits-ui: + specifier: ^2.18.1 + version: 2.18.1 flowbite: - specifier: ^4.0.1 - version: 4.0.1 + specifier: ^4.0.2 + version: 4.0.2 flowbite-svelte: specifier: ^1.33.1 version: 1.33.1 monaco-editor: specifier: ^0.55.1 version: 0.55.1 - svelte-sonner: - specifier: ^1.1.0 - version: 1.1.0 core: '@nanoforge-dev/ecs-lib': - specifier: ^1.1.2 - version: 1.1.2 + specifier: ^1.3.0 + version: 1.3.0 '@sveltejs/kit': - specifier: ^2.57.1 - version: 2.57.1 + specifier: ^2.61.1 + version: 2.61.1 '@sveltejs/vite-plugin-svelte': - specifier: ^7.0.0 - version: 7.0.0 + specifier: ^7.1.2 + version: 7.1.2 '@types/bun': - specifier: ^1.3.12 - version: 1.3.12 + specifier: ^1.3.14 + version: 1.3.14 + bun: + specifier: ^1.3.14 + version: 1.3.14 svelte: - specifier: ^5.55.3 - version: 5.55.4 + specifier: ^5.55.9 + version: 5.55.9 svelte-check: - specifier: ^4.4.6 - version: 4.4.6 + specifier: ^4.4.8 + version: 4.4.8 svelte-kit-sessions: specifier: ^0.4.0 version: 0.4.0 vite: - specifier: ^8.0.8 - version: 8.0.8 + specifier: ^8.0.14 + version: 8.0.14 css: '@alexanderniebuhr/prettier-plugin-unocss': specifier: ^0.0.4 version: 0.0.4 '@unocss/extractor-svelte': - specifier: ^66.6.8 - version: 66.6.8 + specifier: ^66.7.0 + version: 66.7.0 '@unocss/preset-icons': - specifier: ^66.6.8 - version: 66.6.8 + specifier: ^66.7.0 + version: 66.7.0 '@unocss/preset-web-fonts': - specifier: ^66.6.8 - version: 66.6.8 + specifier: ^66.7.0 + version: 66.7.0 '@unocss/preset-wind4': - specifier: ^66.6.8 - version: 66.6.8 + specifier: ^66.7.0 + version: 66.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + tailwind-merge: + specifier: ^3.6.0 + version: 3.6.0 + tailwind-variants: + specifier: ^3.2.2 + version: 3.2.2 + tailwindcss: + specifier: ^4.3.0 + version: 4.3.0 unocss: - specifier: ^66.6.8 - version: 66.6.8 + specifier: ^66.7.0 + version: 66.7.0 i18n: '@inlang/paraglide-js': - specifier: ^2.15.3 - version: 2.16.0 + specifier: ^2.18.1 + version: 2.18.1 icons: '@iconify-json/ic': specifier: ^1.2.4 version: 1.2.4 '@iconify-json/material-icon-theme': - specifier: ^1.2.58 - version: 1.2.59 + specifier: ^1.2.66 + version: 1.2.66 '@iconify-json/solar': specifier: ^1.2.5 version: 1.2.5 + '@lucide/svelte': + specifier: ^1.16.0 + version: 1.16.0 + libs-back: + dotenv: + specifier: ^17.4.2 + version: 17.4.2 + libs-front: + '@internationalized/date': + specifier: ^3.12.1 + version: 3.12.1 + '@tanstack/svelte-query': + specifier: ^6.1.33 + version: 6.1.33 + formsnap: + specifier: ^2.0.1 + version: 2.0.1 + mode-watcher: + specifier: ^1.1.0 + version: 1.1.0 + svelte-sonner: + specifier: ^1.1.1 + version: 1.1.1 + sveltekit-superforms: + specifier: ^2.30.1 + version: 2.30.1 + zod: + specifier: ^4.4.3 + version: 4.4.3 lint: '@nanoforge-dev/utils-eslint-config': specifier: ^1.0.2 @@ -116,39 +160,39 @@ catalogs: specifier: ^6.0.2 version: 6.0.2 eslint: - specifier: ^10.2.0 - version: 10.2.1 + specifier: ^10.4.0 + version: 10.4.0 eslint-plugin-svelte: - specifier: ^3.17.0 - version: 3.17.0 + specifier: ^3.17.1 + version: 3.17.1 globals: - specifier: ^17.5.0 - version: 17.5.0 + specifier: ^17.6.0 + version: 17.6.0 prettier: - specifier: ^3.8.2 + specifier: ^3.8.3 version: 3.8.3 prettier-plugin-svelte: - specifier: ^3.5.1 - version: 3.5.1 + specifier: ^4.0.1 + version: 4.0.1 typescript-eslint: - specifier: ^8.58.2 - version: 8.58.2 + specifier: ^8.60.0 + version: 8.60.0 test: '@playwright/test': - specifier: ^1.59.1 - version: 1.59.1 + specifier: ^1.60.0 + version: 1.60.0 '@vitest/browser-playwright': - specifier: ^4.1.4 - version: 4.1.4 + specifier: ^4.1.7 + version: 4.1.7 '@vitest/coverage-v8': - specifier: ^4.1.4 - version: 4.1.4 + specifier: ^4.1.7 + version: 4.1.7 playwright: - specifier: ^1.59.1 - version: 1.59.1 + specifier: ^1.60.0 + version: 1.60.0 vitest: - specifier: ^4.1.4 - version: 4.1.4 + specifier: ^4.1.7 + version: 4.1.7 vitest-browser-svelte: specifier: ^2.1.1 version: 2.1.1 @@ -162,10 +206,10 @@ importers: version: 0.0.4 '@commitlint/cli': specifier: catalog:ci - version: 20.5.0(@types/node@25.6.0)(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0)(typescript@6.0.3) + version: 21.0.1(@types/node@25.9.1)(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0)(typescript@6.0.3) '@commitlint/config-conventional': specifier: catalog:ci - version: 20.5.0 + version: 21.0.1 '@favware/cliff-jumper': specifier: catalog:ci version: 6.1.0 @@ -174,144 +218,186 @@ importers: version: 1.2.4 '@iconify-json/material-icon-theme': specifier: catalog:icons - version: 1.2.59 + version: 1.2.66 '@iconify-json/solar': specifier: catalog:icons version: 1.2.5 '@inlang/paraglide-js': specifier: catalog:i18n - version: 2.16.0 + version: 2.18.1(typescript@6.0.3) + '@internationalized/date': + specifier: catalog:libs-front + version: 3.12.1 + '@lucide/svelte': + specifier: catalog:icons + version: 1.16.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)) '@nanoforge-dev/actions': specifier: catalog:ci - version: 1.2.3 + version: 2.0.0 '@nanoforge-dev/ecs-lib': specifier: catalog:core - version: 1.1.2 + version: 1.3.0 '@nanoforge-dev/utils-eslint-config': specifier: catalog:lint - version: 1.0.2(@types/eslint@9.6.1)(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3)(typescript@6.0.3) + version: 1.0.2(@types/eslint@9.6.1)(eslint@10.4.0(jiti@2.7.0))(prettier@3.8.3)(typescript@6.0.3) '@nanoforge-dev/utils-prettier-config': specifier: catalog:lint version: 1.0.2 '@playwright/test': specifier: catalog:test - version: 1.59.1 + version: 1.60.0 '@sveltejs/kit': specifier: catalog:core - version: 2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) '@sveltejs/vite-plugin-svelte': specifier: catalog:core - version: 7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + '@tanstack/svelte-query': + specifier: catalog:libs-front + version: 6.1.33(svelte@5.55.9(@typescript-eslint/types@8.60.0)) '@trivago/prettier-plugin-sort-imports': specifier: catalog:lint - version: 6.0.2(prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)))(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + version: 6.0.2(prettier-plugin-svelte@4.0.1(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0)))(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0)) '@tsconfig/svelte': specifier: catalog:build version: 5.0.8 '@types/bun': specifier: catalog:core - version: 1.3.12 + version: 1.3.14 '@unocss/extractor-svelte': specifier: catalog:css - version: 66.6.8 + version: 66.7.0 '@unocss/preset-icons': specifier: catalog:css - version: 66.6.8 + version: 66.7.0 '@unocss/preset-web-fonts': specifier: catalog:css - version: 66.6.8 + version: 66.7.0 '@unocss/preset-wind4': specifier: catalog:css - version: 66.6.8 + version: 66.7.0 '@vitest/browser-playwright': specifier: catalog:test - version: 4.1.4(playwright@1.59.1)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))(vitest@4.1.4) + version: 4.1.7(playwright@1.60.0)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.7) '@vitest/coverage-v8': specifier: catalog:test - version: 4.1.4(@vitest/browser@4.1.4)(vitest@4.1.4) + version: 4.1.7(@vitest/browser@4.1.7)(vitest@4.1.7) + bits-ui: + specifier: catalog:components + version: 2.18.1(@internationalized/date@3.12.1)(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + bun: + specifier: catalog:core + version: 1.3.14 + clsx: + specifier: catalog:css + version: 2.1.1 + dotenv: + specifier: catalog:libs-back + version: 17.4.2 eslint: specifier: catalog:lint - version: 10.2.1(jiti@2.6.1) + version: 10.4.0(jiti@2.7.0) eslint-plugin-svelte: specifier: catalog:lint - version: 3.17.0(eslint@10.2.1(jiti@2.6.1))(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + version: 3.17.1(eslint@10.4.0(jiti@2.7.0))(svelte@5.55.9(@typescript-eslint/types@8.60.0)) flowbite: specifier: catalog:components - version: 4.0.1 + version: 4.0.2 flowbite-svelte: specifier: catalog:components - version: 1.33.1(svelte@5.55.4(@typescript-eslint/types@8.58.2))(tailwindcss@4.2.2) + version: 1.33.1(svelte@5.55.9(@typescript-eslint/types@8.60.0))(tailwindcss@4.3.0) + formsnap: + specifier: catalog:libs-front + version: 2.0.1(svelte@5.55.9(@typescript-eslint/types@8.60.0))(sveltekit-superforms@2.30.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(@types/json-schema@7.0.15)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)) globals: specifier: catalog:lint - version: 17.5.0 + version: 17.6.0 husky: specifier: catalog:ci version: 9.1.7 lint-staged: specifier: catalog:ci - version: 16.4.0 + version: 17.0.5 + mode-watcher: + specifier: catalog:libs-front + version: 1.1.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)) monaco-editor: specifier: catalog:components version: 0.55.1 playwright: specifier: catalog:test - version: 1.59.1 + version: 1.60.0 prettier: specifier: catalog:lint version: 3.8.3 prettier-plugin-svelte: specifier: catalog:lint - version: 3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + version: 4.0.1(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0)) svelte: specifier: catalog:core - version: 5.55.4(@typescript-eslint/types@8.58.2) + version: 5.55.9(@typescript-eslint/types@8.60.0) svelte-adapter-bun: specifier: catalog:build - version: 1.0.1(@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(typescript@6.0.3) + version: 1.0.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(typescript@6.0.3) svelte-check: specifier: catalog:core - version: 4.4.6(picomatch@4.0.4)(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3) + version: 4.4.8(picomatch@4.0.4)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3) svelte-kit-sessions: specifier: catalog:core - version: 0.4.0(@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + version: 0.4.0(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)) svelte-sonner: - specifier: catalog:components - version: 1.1.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + specifier: catalog:libs-front + version: 1.1.1(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + sveltekit-superforms: + specifier: catalog:libs-front + version: 2.30.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(@types/json-schema@7.0.15)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3) + tailwind-merge: + specifier: catalog:css + version: 3.6.0 + tailwind-variants: + specifier: catalog:css + version: 3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.0) + tailwindcss: + specifier: catalog:css + version: 4.3.0 typescript: specifier: catalog:build version: 6.0.3 typescript-eslint: specifier: catalog:lint - version: 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + version: 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) unocss: specifier: catalog:css - version: 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 66.7.0(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) vite: specifier: catalog:core - version: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) + version: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) vitest: specifier: catalog:test - version: 4.1.4(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.7(@types/node@25.9.1)(@vitest/browser-playwright@4.1.7)(@vitest/coverage-v8@4.1.7)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) vitest-browser-svelte: specifier: catalog:test - version: 2.1.1(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vitest@4.1.4) + version: 2.1.1(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vitest@4.1.7) + zod: + specifier: catalog:libs-front + version: 4.4.3 packages: - '@actions/core@3.0.0': - resolution: {integrity: sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==} + '@actions/core@3.0.1': + resolution: {integrity: sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==} '@actions/exec@3.0.0': resolution: {integrity: sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==} - '@actions/github@9.1.0': - resolution: {integrity: sha512-u0hDGQeCS+7VNoLA8hYG65RLdPLMaPGfka0sZ0up7P0AiShqfX6xcuXNteGkQ7X7Tod7AMNwHd4p7DS63i8zzA==} + '@actions/github@9.1.1': + resolution: {integrity: sha512-tL5JbYOBZHc0ngEnCsaDcryUizIUIlQyIMwy1Wkx93H5HzbBJ7TbiPx2PnFjBwZW0Vh05JmfFZhecE6gglYegA==} '@actions/http-client@3.0.2': resolution: {integrity: sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==} - '@actions/http-client@4.0.0': - resolution: {integrity: sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g==} + '@actions/http-client@4.0.1': + resolution: {integrity: sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==} '@actions/io@3.0.2': resolution: {integrity: sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==} @@ -326,41 +412,51 @@ packages: '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@ark/schema@0.56.0': + resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} + + '@ark/util@0.56.0': + resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@1.0.2': @@ -370,74 +466,74 @@ packages: '@blazediff/core@1.9.1': resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} - '@commitlint/cli@20.5.0': - resolution: {integrity: sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==} - engines: {node: '>=v18'} + '@commitlint/cli@21.0.1': + resolution: {integrity: sha512-8vq10krmbJwBkvzXKhbs4o4JQEVscd3pqOlWuDUaDBwbeL694/P33UC29tZQFTAgPU9fVJ2+f2m3zw16yKWxHg==} + engines: {node: '>=22.12.0'} hasBin: true - '@commitlint/config-conventional@20.5.0': - resolution: {integrity: sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==} - engines: {node: '>=v18'} + '@commitlint/config-conventional@21.0.1': + resolution: {integrity: sha512-gRorrkfWOh/+V5X8GYWWbQvrzPczopGMS4CCNrQdHkK4xWElv82BDvIsDhJZWTlI7TazOlYea6VATufCsFs+sw==} + engines: {node: '>=22.12.0'} - '@commitlint/config-validator@20.5.0': - resolution: {integrity: sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==} - engines: {node: '>=v18'} + '@commitlint/config-validator@21.0.1': + resolution: {integrity: sha512-Zd2UFdndeMMaW2O96HK0tdfT4gOImUvidMpAd/pws2zZ4m1nrAZ/9b/v2JYuE8fs86GpXv9F7LNaIuCIWhY+pA==} + engines: {node: '>=22.12.0'} - '@commitlint/ensure@20.5.0': - resolution: {integrity: sha512-IpHqAUesBeW1EDDdjzJeaOxU9tnogLAyXLRBn03SHlj1SGENn2JGZqSWGkFvBJkJzfXAuCNtsoYzax+ZPS+puw==} - engines: {node: '>=v18'} + '@commitlint/ensure@21.0.1': + resolution: {integrity: sha512-jJ1037967wU7YN/xkv+iRlOBlmaOXPhPO5KQSqya6GyXzBlwuLzELBFao16DVg9dZyqmNrhewzwZ3SAibetHBQ==} + engines: {node: '>=22.12.0'} - '@commitlint/execute-rule@20.0.0': - resolution: {integrity: sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==} - engines: {node: '>=v18'} + '@commitlint/execute-rule@21.0.1': + resolution: {integrity: sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==} + engines: {node: '>=22.12.0'} - '@commitlint/format@20.5.0': - resolution: {integrity: sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==} - engines: {node: '>=v18'} + '@commitlint/format@21.0.1': + resolution: {integrity: sha512-ksmG2+cHGtuDPQQbhBbC4unwm444+6TiPw0d1bKf67hntgZqZ8E0g1MuYKUuyT5IH4IMmXZhKq22/Z3jBvtQIw==} + engines: {node: '>=22.12.0'} - '@commitlint/is-ignored@20.5.0': - resolution: {integrity: sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==} - engines: {node: '>=v18'} + '@commitlint/is-ignored@21.0.1': + resolution: {integrity: sha512-iNDP8SFdw8JEkM0CHZ2XFnhTN4Zg5jKUY2d8kBOSFrI2aA+3YJI7fcqVpfgbpJ9xtxFVYpi+DBATU5AvhoTq8g==} + engines: {node: '>=22.12.0'} - '@commitlint/lint@20.5.0': - resolution: {integrity: sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==} - engines: {node: '>=v18'} + '@commitlint/lint@21.0.1': + resolution: {integrity: sha512-gF+iYtUw1gBG3HUH9z3VxwUjGg2R2G5j+nmvPs8aIeYkiB7TtneBu3wO85I0bUl93bYNsvsCNI9Nte2fmDUMww==} + engines: {node: '>=22.12.0'} - '@commitlint/load@20.5.0': - resolution: {integrity: sha512-sLhhYTL/KxeOTZjjabKDhwidGZan84XKK1+XFkwDYL/4883kIajcz/dZFAhBJmZPtL8+nBx6bnkzA95YxPeDPw==} - engines: {node: '>=v18'} + '@commitlint/load@21.0.1': + resolution: {integrity: sha512-Btg1q1mKmiihN4W3x0EsPDrJMOQfMa9NIqlzlJyXAfxvsOGdGXOW5p3R3RcSxDCaY7JabY9flIl+Om1af3PSrw==} + engines: {node: '>=22.12.0'} - '@commitlint/message@20.4.3': - resolution: {integrity: sha512-6akwCYrzcrFcTYz9GyUaWlhisY4lmQ3KvrnabmhoeAV8nRH4dXJAh4+EUQ3uArtxxKQkvxJS78hNX2EU3USgxQ==} - engines: {node: '>=v18'} + '@commitlint/message@21.0.1': + resolution: {integrity: sha512-R3dVQeJQ0B6yqrZEjkUHD4r7UJYLV9Lvk2xs3PTOmtWk2G3mI6Xgc+YdRxL1PwcDfBiUjv2SkIkW4AUc976w1w==} + engines: {node: '>=22.12.0'} - '@commitlint/parse@20.5.0': - resolution: {integrity: sha512-SeKWHBMk7YOTnnEWUhx+d1a9vHsjjuo6Uo1xRfPNfeY4bdYFasCH1dDpAv13Lyn+dDPOels+jP6D2GRZqzc5fA==} - engines: {node: '>=v18'} + '@commitlint/parse@21.0.1': + resolution: {integrity: sha512-oh/nCSOqdoeQNA1tO8aAmxkq5EBo8/NzcFQRvv66AWc9HpED28sL2iSicCKU6hPintWuscL6BJEWi77Wq1LPMQ==} + engines: {node: '>=22.12.0'} - '@commitlint/read@20.5.0': - resolution: {integrity: sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==} - engines: {node: '>=v18'} + '@commitlint/read@21.0.1': + resolution: {integrity: sha512-pMEu4lbpC8W0ZgKJj2U6WaobXIZWdFlULpIEewYhkPXx+WZcnoO53YrVPc7QErQuNolq2Me8dP58Wu7YAVXVOA==} + engines: {node: '>=22.12.0'} - '@commitlint/resolve-extends@20.5.0': - resolution: {integrity: sha512-3SHPWUW2v0tyspCTcfSsYml0gses92l6TlogwzvM2cbxDgmhSRc+fldDjvGkCXJrjSM87BBaWYTPWwwyASZRrg==} - engines: {node: '>=v18'} + '@commitlint/resolve-extends@21.0.1': + resolution: {integrity: sha512-0DhjYWL6uYrY16Efa032fYk3woGJDU4AGWiG1XXltT9AMUNYKyb5cIZU2ivbaMZ3+kKFqUjikD2cjh66Sbh/Sg==} + engines: {node: '>=22.12.0'} - '@commitlint/rules@20.5.0': - resolution: {integrity: sha512-5NdQXQEdnDPT5pK8O39ZA7HohzPRHEsDGU23cyVCNPQy4WegAbAwrQk3nIu7p2sl3dutPk8RZd91yKTrMTnRkQ==} - engines: {node: '>=v18'} + '@commitlint/rules@21.0.1': + resolution: {integrity: sha512-VMooYpz4nJg7xlaUso6CCOWEz8D/ChkvsvZUMARcoJ1ZpfKPyFCGrHNha2tbsETNAb6ErgiRuCr2DvghrvPDYQ==} + engines: {node: '>=22.12.0'} - '@commitlint/to-lines@20.0.0': - resolution: {integrity: sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==} - engines: {node: '>=v18'} + '@commitlint/to-lines@21.0.1': + resolution: {integrity: sha512-bd1BFII7p1EQZre9Kaj+kKaMFP3cFCdt21K7DItVux9XP5WjLgJ0/Uy1pJJh9aPwVJ6SKg62PxqlZaHI8hQAXw==} + engines: {node: '>=22.12.0'} - '@commitlint/top-level@20.4.3': - resolution: {integrity: sha512-qD9xfP6dFg5jQ3NMrOhG0/w5y3bBUsVGyJvXxdWEwBm8hyx4WOk3kKXw28T5czBYvyeCVJgJJ6aoJZUWDpaacQ==} - engines: {node: '>=v18'} + '@commitlint/top-level@21.0.1': + resolution: {integrity: sha512-4esUYqzY7K0FCgcJ/1xWEZekV7Ch4yZT1+xjEb7KzqbJ05XEkxHVsTfC8ADKNNtlCE2pj98KEbPGZWw9WwEnVw==} + engines: {node: '>=22.12.0'} - '@commitlint/types@20.5.0': - resolution: {integrity: sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==} - engines: {node: '>=v18'} + '@commitlint/types@21.0.1': + resolution: {integrity: sha512-4u7w8jcoCUFWhjWnASYzZHAP34OqOtuFBN87nQmFvqda03YU0T6z+yB4w0gSAMpekiRqqGk5rt+qSlW+a2vSEg==} + engines: {node: '>=22.12.0'} '@conventional-changelog/git-client@2.7.0': resolution: {integrity: sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==} @@ -460,11 +556,11 @@ packages: '@dprint/toml@0.7.0': resolution: {integrity: sha512-eFaQTcfxKHB+YyTh83x7GEv+gDPuj9q5NFOTaoj5rZmQTbj6OgjjMxUicmS1R8zYcx8YAq5oA9J3YFa5U6x2gA==} - '@emnapi/core@1.9.2': - resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.9.2': - resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -483,8 +579,8 @@ packages: resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.5': - resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/core@1.2.1': @@ -503,6 +599,9 @@ packages: resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@exodus/schemasafe@1.3.0': + resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} + '@favware/cliff-jumper@6.1.0': resolution: {integrity: sha512-BTuJ3evIMbkXgcQSk9K9B2vAuENi0bzS6qhtKLx6ZO/LTUIuoJfG05IsLqTngwBsJ6ZGnN3dXYGK/ANVMT8Xrw==} engines: {node: '>=v18'} @@ -521,6 +620,12 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -544,8 +649,8 @@ packages: '@iconify-json/ic@1.2.4': resolution: {integrity: sha512-pzPMmrZrBQuwT7nmtrYdkttun8KalRGgZPIL1Ny9KpF2zjRGIUPN+npTfuD3lrgO/OnSwAoJWuekQwBpt/Cqrw==} - '@iconify-json/material-icon-theme@1.2.59': - resolution: {integrity: sha512-tm5at2S/bm/WMkkQNDD9szc0v1F0Zx2nqdsu5F6SDmK60UJTOZeNqIDEflSXHjptVCepq05/sDh3vLgEHDhqnQ==} + '@iconify-json/material-icon-theme@1.2.66': + resolution: {integrity: sha512-TxWgH1twATqzvdMOafXf3V7NtgdLGkg77ySoEUo0uKv4cmzsy/8fHUZWNn6t9s7ZAzAjxf41ZIDdWIwxIsMrbQ==} '@iconify-json/solar@1.2.5': resolution: {integrity: sha512-WMAiNwchU8zhfrySww6KQBRIBbsQ6SvgIu2yA+CHGyMima/0KQwT5MXogrZPJGoQF+1Ye3Qj6K+1CiyNn3YkoA==} @@ -553,20 +658,28 @@ packages: '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@iconify/utils@3.1.0': - resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + '@iconify/utils@3.1.3': + resolution: {integrity: sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==} - '@inlang/paraglide-js@2.16.0': - resolution: {integrity: sha512-O7KKvVoTsGqPRt1VfSvd0UyfSjU2qHiABx968M2decgG7Af6TddW3dTJrTS3I78nOUgRAlYwCYfKefSGD4rGMA==} + '@inlang/paraglide-js@2.18.1': + resolution: {integrity: sha512-YzIrJ34KbsJwzvVKBzcBEgp4AqmhNYD1EF2pOV+g87L024XTFmcmikI4/NMfb63H9zJ6UeEPTOmEK7Nzu/4E2Q==} hasBin: true + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true '@inlang/recommend-sherlock@0.2.1': resolution: {integrity: sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg==} - '@inlang/sdk@2.9.1': - resolution: {integrity: sha512-y0C3xaKo6pSGDr3p5OdreRVT3THJpgKVe1lLvG3BE4v9lskp3UfI9cPCbN8X2dpfLt/4ljtehMb5SykpMfJrMg==} + '@inlang/sdk@2.9.3': + resolution: {integrity: sha512-E/SxcSji8WIt4DqQG9APlOs6tVtJxrrOUS3dE4ho3pWRCLLIY0PIVzgNwSukuFT+m8LuJDFwpRY5VY3ryzyGWQ==} engines: {node: '>=20.0.0'} + '@internationalized/date@3.12.1': + resolution: {integrity: sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==} + '@isaacs/ttlcache@1.4.1': resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} @@ -587,23 +700,28 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@lix-js/sdk@0.4.9': - resolution: {integrity: sha512-30mDkXpx704359oRrJI42bjfCspCiaMItngVBbPkiTGypS7xX4jYbHWQkXI8XuJ7VDB69D0MsVU6xfrBAIrM4A==} + '@lix-js/sdk@0.4.10': + resolution: {integrity: sha512-0dMInAJK/67guTG5rRZaCEhvzC5cCXENOjaePA5AqMXrCE97kaY7SRor9e2vnoGsFIiGqXKlT0MCIoZj36G0gg==} engines: {node: '>=18'} '@lix-js/server-protocol-schema@0.1.1': resolution: {integrity: sha512-jBeALB6prAbtr5q4vTuxnRZZv1M2rKe8iNqRQhFJ4Tv7150unEa0vKyz0hs8Gl3fUGsWaNJBh3J8++fpbrpRBQ==} - '@nanoforge-dev/actions@1.2.3': - resolution: {integrity: sha512-YVQ1e3H5MVHGBku2bA+lMLb+mkDXvJvYN228V6L0R+HXxo82X3Y1oVDKzlsnz+GRvYejJXEsY6jzPrV3pzbGwA==} + '@lucide/svelte@1.16.0': + resolution: {integrity: sha512-AvvPJnaWxeiNkAljI5MsSEc84yHPLMaWQIAJOcbX7k9au/f9ITS7cxTTQiautDiOFKVOXiYdZ+d6mtl88J+Kbg==} + peerDependencies: + svelte: ^5 + + '@nanoforge-dev/actions@2.0.0': + resolution: {integrity: sha512-9t/LC+cIBov7UNLNe1G/fRfKJhpR3tGSiYjReQibf3FZlupooctqW7oeuToCvdCQgM3CrZIJ9nXH7+EvFXXL9A==} engines: {node: '25'} - '@nanoforge-dev/common@1.1.0': - resolution: {integrity: sha512-quxZz4mZZqzp6XMGTzp5JbQH63c5Xt8tscArwz83gw6zqoPzfB0TQH5zFS+9SQF8JVOdmkroA8rNwzlyuZj2Pg==} + '@nanoforge-dev/common@1.3.0': + resolution: {integrity: sha512-MpgZ/fsGpzD2ccsAAqR9iuvdZfVojGASfu0fi2Y3/UQaRcEpStqmWtgMsry4jtaf0wXPWHMMLw9Ses/0TfvWeg==} engines: {node: '25'} - '@nanoforge-dev/ecs-lib@1.1.2': - resolution: {integrity: sha512-3WD75i0rtyedV8IDbJ0v/HwAqpWt9VjIb5H36YEFTblVRsV/FArH5ZmlSTWRFnKL+Ap4Tr3dQ8Bi5bMDfznMMw==} + '@nanoforge-dev/ecs-lib@1.3.0': + resolution: {integrity: sha512-FZozPG9VrJRX/Pydl+iDflBWuIOlPLkiBuQu7cRNt+owJJ3iBU6sdSqwvXa4UxySjIJqij9pNaWyXOHQCl9Fjw==} engines: {node: '25'} '@nanoforge-dev/utils-eslint-config@1.0.2': @@ -661,145 +779,225 @@ packages: resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} engines: {node: '>= 20'} - '@octokit/request@10.0.8': - resolution: {integrity: sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==} + '@octokit/request@10.0.9': + resolution: {integrity: sha512-o8Bi3f608eyM+7BmBiUWxFsdjLb3/ym1cQek5LZOv9KkZcxRrHCPhhRzm6xjO6HVZ85ItD6+sTsjxo821SVa/A==} engines: {node: '>= 20'} '@octokit/types@16.0.0': resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} - '@oxc-parser/binding-android-arm-eabi@0.124.0': - resolution: {integrity: sha512-+R9zCafSL8ovjokdPtorUp3sXrh8zQ2AC2L0ivXNvlLR0WS+5WdPkNVrnENq5UvzagM4Xgl0NPsJKz3Hv9+y8g==} + '@oven/bun-darwin-aarch64@1.3.14': + resolution: {integrity: sha512-Omj20SuiHBOUjUBIyqtkNjSUIjOtEOJwmbix/ZyFH4BaQ6OZTaaRWIR4TjHVz0yadHgli6lLTiAh1uarnvD49A==} + cpu: [arm64] + os: [darwin] + + '@oven/bun-darwin-x64-baseline@1.3.14': + resolution: {integrity: sha512-OSfsTZstc898HHElhU4NccaBGOSSDn5VfahiVTnidZ9B/+wb7WTyfZJaBeJcfjwJ9H2W9uTh2TGtl3UfcXgV9g==} + cpu: [x64] + os: [darwin] + + '@oven/bun-darwin-x64@1.3.14': + resolution: {integrity: sha512-FFj3QdU/OhlDyZOJ8CWfN5eWLpRlT4qjZg7lMQi7jA6GuoY5ajlO1zWLP/MuHYRSbXQUvV52RejNi8DVnAp13w==} + cpu: [x64] + os: [darwin] + + '@oven/bun-freebsd-aarch64@1.3.14': + resolution: {integrity: sha512-LIKrXaFxAHybVO5Pf+9XP2FHUj/5APvXTUKk9dqHm5iFz4oH+W24cmhjkJirNujh9hKeTyrpWSe3no9JZKowIw==} + cpu: [arm64] + os: [freebsd] + + '@oven/bun-freebsd-x64@1.3.14': + resolution: {integrity: sha512-uwD+fGUH1ADpIF3B1U2jWzzb20QwRLZfj5QZ28GUCGrAJ/nTmWrD6YYGsblCY1wuhldRez3lU40AyuvSCyLYmw==} + cpu: [x64] + os: [freebsd] + + '@oven/bun-linux-aarch64-android@1.3.14': + resolution: {integrity: sha512-y4kq5b85lsrmFb9Xvi4w9mA5IEFJkLMrSmYn06q24KjL9rUWDWO3VFZEtteZxUN5+ec3Zm5S8OnJw1umaCbVjA==} + cpu: [arm64] + os: [android] + + '@oven/bun-linux-aarch64-musl@1.3.14': + resolution: {integrity: sha512-jmqOA92Cd1NL/1XBd4bFkJLxQ86K0RW7ohxS2qzzAvuitO4JiIxjjTeCspoU44zCozH72HpfZfUE2On31OjnWA==} + cpu: [arm64] + os: [linux] + + '@oven/bun-linux-aarch64@1.3.14': + resolution: {integrity: sha512-X5SsPZHs+iYO8R/efIcRtc7gT2Q2DgPfliCxEkx4cXBumwkw0c/EsHMNwH3EgGpCDaZ7IYVPhpCG/xBOQHEwZw==} + cpu: [arm64] + os: [linux] + + '@oven/bun-linux-x64-android@1.3.14': + resolution: {integrity: sha512-qe9e1d+3VAEU7nAA2ol9Jvmy/o99PVMSgZhHn7Q/9O3YcDrfEqyQ8zm4zoe5qTEo8HZH0dN03Le0Ys2eQPs7eg==} + cpu: [x64] + os: [android] + + '@oven/bun-linux-x64-baseline@1.3.14': + resolution: {integrity: sha512-q/8EdOC0yUE8FPeoOVq8/Pw5I9/tJaYmUfO/uDUAREx8IUnOJH1RJ5A3BjFqre8pvJoiZA9AovPJq5FnNNjSxA==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64-musl-baseline@1.3.14': + resolution: {integrity: sha512-n6iE71G4lQE4XkrZhQQcL5YUlxDbnq6nqV7zeQi33PMsLT/0kYE+RvHOtBWZ3w0wMdXZfINmp63hIb9ijUBGtw==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64-musl@1.3.14': + resolution: {integrity: sha512-GBCB/k/sIqcr06eTNgg7g46qiUv35Jasx4XiccJ/n7RGqrE4RWUD/XJBbWFprVPjvqd59+QtSnS99XGqvftHfg==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64@1.3.14': + resolution: {integrity: sha512-7OVTAKvwfPmSbIV1HpdOoVVx5VRc427GuPPne93N6vk4eQBPId9nXmZDh9/zGaKPdbVjVtQSZafWQoUjx38Utw==} + cpu: [x64] + os: [linux] + + '@oven/bun-windows-aarch64@1.3.14': + resolution: {integrity: sha512-T7s3x/BsVKQObGU6QDkZeI6wKynzqGbBH1yI77jrrj5siElclxr3DQrDIk8CV4G5/SJq2HHq4kpLyYY2DKCSmA==} + cpu: [arm64] + os: [win32] + + '@oven/bun-windows-x64-baseline@1.3.14': + resolution: {integrity: sha512-uIjLUC1S9DWgICzuoMba7vurBJnBruE4S5CxnvmZkdqWVXRzx1Rgu636HoH+k0qeaQCFh3jeG3JQ1y6fRHv0sw==} + cpu: [x64] + os: [win32] + + '@oven/bun-windows-x64@1.3.14': + resolution: {integrity: sha512-mUFWL3BoYkNpjd8e9PqROiFF/1Xeotq20mABJsiQH62jM1g5zqWh4khw1RZ6bX8Q8fWvlPaxG1PjofkmjUi3vg==} + cpu: [x64] + os: [win32] + + '@oxc-parser/binding-android-arm-eabi@0.131.0': + resolution: {integrity: sha512-t2xicr9pfzkSRYx5aPqZqlLaayIwJTqgQ81Jor31Xep2nGyL2Aq3d0K5wOfeR7VevaSdxaS9dzSQP9xDwn8fDg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-parser/binding-android-arm64@0.124.0': - resolution: {integrity: sha512-ULHC/gVZ+nP4pd3kNNQTYaQ/e066BW/KuY5qUsvwkVWwOUQGDg+WpfyVOmQ4xfxoue6cMlkKkJ+ntdzfDXpNlg==} + '@oxc-parser/binding-android-arm64@0.131.0': + resolution: {integrity: sha512-nlGIod6gw75x1aEDgLS+srj+JRGY0HHm9MI9YgzE/B64l6d6+H3MSP9NOgp0+HTg8tp4vV9rVfgQGgd+TfVZcA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-parser/binding-darwin-arm64@0.124.0': - resolution: {integrity: sha512-fGJ2hw7bnbUYn6UvTjp0m4WJ9zXz3cohgcwcgeo7gUZehpPNpvcVEVeIVHNmHnAuAw/ysf4YJR8DA1E+xCA4Lw==} + '@oxc-parser/binding-darwin-arm64@0.131.0': + resolution: {integrity: sha512-jukuV6xe5RbQKFo7QD34NDCLDZp4PSOm8rmckhNdH/60ymG5zXbDzGBEyc+nTkuLQNama2aSGCt+CPfpjNTqyw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-parser/binding-darwin-x64@0.124.0': - resolution: {integrity: sha512-j0+re9pgps5BH2Tk3fm59Hi3QuLP3C4KhqXi6A+wRHHHJWDFR8mc/KI9mBrfk2JRT+15doGo+zv1eN75/9DuOw==} + '@oxc-parser/binding-darwin-x64@0.131.0': + resolution: {integrity: sha512-g3JOo4khe9rslHm5WYaVDWb0HS/M1MLR3I9S8560MkKIcC96VQY00QjOlsuRyfSj/JDXj8i9T7ryPO2RidiXVg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-parser/binding-freebsd-x64@0.124.0': - resolution: {integrity: sha512-0k5mS0npnrhKy72UfF51lpOZ2ESoPWn6gdFw+RdeRWcokraDW1O2kSx3laQ+yk7cCEavQdJSpWCYS/GvBbUCXQ==} + '@oxc-parser/binding-freebsd-x64@0.131.0': + resolution: {integrity: sha512-1hziITDTxjMePnX+dR9ocVT+EuZkQ8wm4FPAbmbEiKG+Phbo73J1ZnPAA6Y/aGsWF3McOFnQuZIktAFwalkfJQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-parser/binding-linux-arm-gnueabihf@0.124.0': - resolution: {integrity: sha512-P/i4eguRWvAUfGdfhQYg1jpwYkyUV6D3gefIH7HhmRl1Ph6P4IqTIEVcyJr1i/3vr1V5OHU4wonH6/ue/Qzvrw==} + '@oxc-parser/binding-linux-arm-gnueabihf@0.131.0': + resolution: {integrity: sha512-9uRxfXwyKG9+MwmGQBo2ncPNwZH5HTmCETFM2WiuDBNDCW4NC5ttSQkwCAMrTAWgwMzVBH1CP8pM0v7nebCWXQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.124.0': - resolution: {integrity: sha512-/ameqFQH5fFP+66Atr8Ynv/2rYe4utcU7L4MoWS5JtrFLVO78g4qDLavyIlJxa6caSwYOvG/eO3c/DXqY5/6Rw==} + '@oxc-parser/binding-linux-arm-musleabihf@0.131.0': + resolution: {integrity: sha512-mgbLvzRShXOLBdWGInf08Af4q+pfj1xD8hSgLClDZ9of/BXkB6+LIhTH7fihiDUipqB3yoSkKBWaZ3Ejlf5Yag==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.124.0': - resolution: {integrity: sha512-gNeyEcXTtfrRCbj2EfxWU85Fs0wIX3p44Y3twnvuMfkWlLrb9M1Z25AYNSKjJM+fdAjeeQCjw0on47zFuBYwQw==} + '@oxc-parser/binding-linux-arm64-gnu@0.131.0': + resolution: {integrity: sha512-OPT8++4aN6j2GJ8+3IZHS/byXoZP4aSBn+FoG6rgBJ2fKwPKXWF3MqrFMNW7NKHM28FLY579xYLxJSfgobEqPA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-arm64-musl@0.124.0': - resolution: {integrity: sha512-uvG7v4Tz9S8/PVqY0SP0DLHxo4hZGe+Pv2tGVnwcsjKCCUPjplbrFVvDzXq+kOaEoUkiCY0Kt1hlZ6FDJ1LKNQ==} + '@oxc-parser/binding-linux-arm64-musl@0.131.0': + resolution: {integrity: sha512-vtPiwmfVTAXzaxDKsOXG+LwgRAA7WEnaeHzhS5z0GE89gAK18KSXnly7Z6saXXq6L3dVMyK44uoTI03zKxrpmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-ppc64-gnu@0.124.0': - resolution: {integrity: sha512-t7KZaaUhfp2au0MRpoENEFqwLKYDdptEry6V7pTAVdPEcFG4P6ii8yeGU9m6p5vb+b8WEKmdpGMNXBEYy7iJdw==} + '@oxc-parser/binding-linux-ppc64-gnu@0.131.0': + resolution: {integrity: sha512-8AW8L7w5cGHSdZPcyZX2yR0+GUODsT15rbRjfdD54rv6DMbtuEB19ysLOpKJlRGfH6UNYNpCHaU1uJWgTWf1/w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-gnu@0.124.0': - resolution: {integrity: sha512-eurGGaxHZiIQ+fBSageS8TAkRqZgdOiBeqNrWAqAPup9hXBTmQ0WcBjwsLElf+3jvDL9NhnX0dOgOqPfsjSjdg==} + '@oxc-parser/binding-linux-riscv64-gnu@0.131.0': + resolution: {integrity: sha512-vvpjkjEOUsPcsYf8evE4MO3aGx9+3wodXEBOicGNnOwTuAik8eBONNkgSdhkGsAblQmfVHJyanRnpxglddTXIA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-musl@0.124.0': - resolution: {integrity: sha512-d1V7/ll1i/LhqE/gZy6Wbz6evlk0egh2XKkwMI3epiojtbtUwQSLIER0Y3yDBBocPuWOjJdvmjtEmPTTLXje/w==} + '@oxc-parser/binding-linux-riscv64-musl@0.131.0': + resolution: {integrity: sha512-AqmcNC3fClXX+fxQ6VGEN1667xVFiRBkY0CZmDMSiaeFUsv1+UkBPYYi48IUKcA9/ivvoKNRzQl2I4//kT9F/w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-s390x-gnu@0.124.0': - resolution: {integrity: sha512-w1+cBvriUteOpox6ATqCFVkpGL47PFdcfCPGmgUZbd78Fw44U0gQkc+kVGvAOTvGrptMYgwomD1c6OTVvkrpGg==} + '@oxc-parser/binding-linux-s390x-gnu@0.131.0': + resolution: {integrity: sha512-7d3jOMKy7RSQCcDLIci+ySll2FgsOMl/GiRux4q2JNv0zg4EdhFISa9idvrdN/HEUIQQJNg6dmveUeJl2YErGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-gnu@0.124.0': - resolution: {integrity: sha512-RRB1evQiXRtMCsQQiAh9U0H3HzguLpE0ytfStuhRgmOj7tqUCOVxkHsvM9geZjAax6NqVRj7VXx32qjjkZPsBw==} + '@oxc-parser/binding-linux-x64-gnu@0.131.0': + resolution: {integrity: sha512-JHK/h95qVqVQ+ITER837kcTdwBDFpFaNnOTYGCP0zdUSX/mLKC7tXOoyrTb6vG7iRPwGlcgBil3v2IjYw1FqJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-musl@0.124.0': - resolution: {integrity: sha512-asVYN0qmSHlCU8H9Q47SmeJ/Z5EG4IWCC+QGxkfFboI5qh15aLlJnHmnrV61MwQRPXGnVC/sC3qKhrUyqGxUqw==} + '@oxc-parser/binding-linux-x64-musl@0.131.0': + resolution: {integrity: sha512-b2BO82O8azXAyf7EUgOPKu145nWypbNyk07HbU09fkzhm9lEA5oPvaN/M8Nlo7tOErVTa2WOgS4QbOnxAPXdDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxc-parser/binding-openharmony-arm64@0.124.0': - resolution: {integrity: sha512-nhwuxm6B8pn9lzAzMUfa571L5hCXYwQo8C8cx5aGOuHWCzruR8gPJnRRXGBci+uGaIIQEZDyU/U6HDgrSp/JlQ==} + '@oxc-parser/binding-openharmony-arm64@0.131.0': + resolution: {integrity: sha512-GHO9glZaX7LkX/OGfluEPf1yjg+ehiFbUdowbX6uNWOQhmwKWU4m4+nZ9FJkrHNKuxyI1KKertMdGjVKCApKWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-parser/binding-wasm32-wasi@0.124.0': - resolution: {integrity: sha512-LWuq4Dl9tff7n+HjJcqoBjDlVCtruc0shgtdtGM+rTUIE9aFxHA/P+wCYR+aWMjN8m9vNaRME/sKXErmhmeKrA==} - engines: {node: '>=14.0.0'} + '@oxc-parser/binding-wasm32-wasi@0.131.0': + resolution: {integrity: sha512-3SkikPaEFoih1N83qLVEDLRLeY4nYsf6JT9SnWiMCQ5lGQdKup6bEuKCqkRiG9dD1IIaFeYz9RjlciPmYoFIWA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@oxc-parser/binding-win32-arm64-msvc@0.124.0': - resolution: {integrity: sha512-aOh3Lf3AeH0dgzT4yBXcArFZ8VhqNXwZ/xlN0GqBtgVaGoHOOqL2YHlcVIgT+ghsXPVR2PTtYgBiQ1CNK7jp5A==} + '@oxc-parser/binding-win32-arm64-msvc@0.131.0': + resolution: {integrity: sha512-Os5bEhryeA2jkH+ZrnZyAC1EP5gs+X4YB1Fjqml7UPD5kU7ecsK1MPEVMfCrdt/GDNpDbavYXiOXOdyJ5b3OPw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.124.0': - resolution: {integrity: sha512-sib5xC0nz/+SCpaETBuHBz4SXS02KuG5HtyOcHsO/SK5ZvLRGhOZx0elDKawjb6adFkD7dQCqpXUS25wY6ELKQ==} + '@oxc-parser/binding-win32-ia32-msvc@0.131.0': + resolution: {integrity: sha512-m+jNz9EuF0NXoiptc6B9h5yompZQVW/a5MJeOu5zojfH5yWk82tvF2ccrHkfhgtrS9h9DD5l1Qv8dWlfY7Nz8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.124.0': - resolution: {integrity: sha512-UgojtjGUgZgAZQYt7SC6VO65OVdxEkRe2q+2vbHJO//18qw3Hrk6UvHGQKldsQKgbVcIBT/YBrt85YberiYIPQ==} + '@oxc-parser/binding-win32-x64-msvc@0.131.0': + resolution: {integrity: sha512-o14Hk8dAyiEUMFEWEgmAwFZvBt1RzAYLM3xeQ+5315JXgVYhoemivgYcbYVRbsFkS71ShMGlAFE0kPnr460rww==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxc-project/types@0.124.0': - resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@oxc-project/types@0.131.0': + resolution: {integrity: sha512-PgnWDfV0h+b16XNKbXU7Daib/BFSt/J2mEzfYIBu6JB/wNdlU+kVYXCkGA1A9fWkTbOgbjh4e6NhPeQOYvFhEA==} - '@oxc-project/types@0.126.0': - resolution: {integrity: sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==} + '@oxc-project/types@0.132.0': + resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} '@oxfmt/binding-android-arm-eabi@0.35.0': resolution: {integrity: sha512-BaRKlM3DyG81y/xWTsE6gZiv89F/3pHe2BqX2H4JbiB8HNVlWWtplzgATAE5IDSdwChdeuWLDTQzJ92Lglw3ZA==} @@ -927,8 +1125,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.59.1': - resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==} + '@playwright/test@1.60.0': + resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} engines: {node: '>=18'} hasBin: true @@ -938,204 +1136,109 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@poppinss/macroable@1.1.2': + resolution: {integrity: sha512-FAVBRzzWhYP5mA3lCwLH1A0fKBqq5anyjGet90Z81aRK5c/+LTGUE1zJhZrErjaenBSOOI9BVUs3WVmotneFQA==} + '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - '@rolldown/binding-android-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-android-arm64@1.0.0-rc.16': - resolution: {integrity: sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==} + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-arm64@1.0.0-rc.16': - resolution: {integrity: sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==} + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.15': - resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-rc.16': - resolution: {integrity: sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==} + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': - resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.0-rc.16': - resolution: {integrity: sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': - resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16': - resolution: {integrity: sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16': - resolution: {integrity: sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.16': - resolution: {integrity: sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==} + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.16': - resolution: {integrity: sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16': - resolution: {integrity: sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.16': - resolution: {integrity: sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.16': - resolution: {integrity: sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.16': - resolution: {integrity: sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==} + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': - resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} - engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.16': - resolution: {integrity: sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16': - resolution: {integrity: sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==} + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.16': - resolution: {integrity: sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-rc.15': - resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} - - '@rolldown/pluginutils@1.0.0-rc.16': - resolution: {integrity: sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@rollup/plugin-node-resolve@15.3.1': resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} @@ -1166,6 +1269,15 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + '@simple-libs/child-process-utils@1.0.2': resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} engines: {node: '>=18'} @@ -1188,13 +1300,13 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@sveltejs/acorn-typescript@1.0.9': - resolution: {integrity: sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==} + '@sveltejs/acorn-typescript@1.0.10': + resolution: {integrity: sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==} peerDependencies: acorn: ^8.9.0 - '@sveltejs/kit@2.57.1': - resolution: {integrity: sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==} + '@sveltejs/kit@2.61.1': + resolution: {integrity: sha512-Ny8s1SR1TyQS2hD2Rvw0XKzU2Nw1eUF52dTb6T2bdcgz7wSC+Nyb5IwjWYlR4b2dvbbR5NJDiQwHg3rnNseghg==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -1209,76 +1321,79 @@ packages: typescript: optional: true - '@sveltejs/vite-plugin-svelte@7.0.0': - resolution: {integrity: sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==} + '@sveltejs/vite-plugin-svelte@7.1.2': + resolution: {integrity: sha512-DrUBA2UXRfDmUX/ZTiEopd3X40yavsJF1FX2RygcuIScHL7o5YX1fMvoYnDhjeJQC4weCOklirpNWlcb2NiSeA==} engines: {node: ^20.19 || ^22.12 || >=24} peerDependencies: svelte: ^5.46.4 vite: ^8.0.0-beta.7 || ^8.0.0 - '@tailwindcss/node@4.2.2': - resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} + '@swc/helpers@0.5.21': + resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} - '@tailwindcss/oxide-android-arm64@4.2.2': - resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.2': - resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.2': - resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.2': - resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': - resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': - resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -1289,24 +1404,32 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.2': - resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} engines: {node: '>= 20'} - '@tailwindcss/postcss@4.2.2': - resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} + '@tailwindcss/postcss@4.3.0': + resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} + + '@tanstack/query-core@5.100.14': + resolution: {integrity: sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==} + + '@tanstack/svelte-query@6.1.33': + resolution: {integrity: sha512-hdbGeLLOIfkrB+/leytCON+tjpSbkO36OsXxrTkPpwC7p8jK36DaoBRR1FO1Z0jOg/fmfCs26lafzFsWXV5W9w==} + peerDependencies: + svelte: ^5.25.0 '@testing-library/svelte-core@1.0.0': resolution: {integrity: sha512-VkUePoLV6oOYwSUvX6ShA8KLnJqZiYMIbP2JW2t0GLWLkJxKGvuH5qrrZBV/X7cXFnLGuFQEC7RheYiZOW68KQ==} @@ -1336,11 +1459,11 @@ packages: '@tsconfig/svelte@5.0.8': resolution: {integrity: sha512-UkNnw1/oFEfecR8ypyHIQuWYdkPvHiwcQ78sh+ymIiYoF+uc5H1UBetbjyqT+vgGJ3qQN6nhucJviX6HesWtKQ==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@types/bun@1.3.12': - resolution: {integrity: sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A==} + '@types/bun@1.3.14': + resolution: {integrity: sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw==} '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1357,14 +1480,14 @@ packages: '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@25.6.0': - resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/node@25.9.1': + resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -1372,174 +1495,262 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.58.2': - resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} + '@types/validator@13.15.10': + resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} + + '@typeschema/class-validator@0.3.0': + resolution: {integrity: sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==} + peerDependencies: + class-validator: ^0.14.1 + peerDependenciesMeta: + class-validator: + optional: true + + '@typeschema/core@0.14.0': + resolution: {integrity: sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==} + peerDependencies: + '@types/json-schema': ^7.0.15 + peerDependenciesMeta: + '@types/json-schema': + optional: true + + '@typescript-eslint/eslint-plugin@8.59.4': + resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.2 + '@typescript-eslint/parser': ^8.59.4 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.2': - resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} + '@typescript-eslint/eslint-plugin@8.60.0': + resolution: {integrity: sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: + '@typescript-eslint/parser': ^8.60.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.2': - resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} + '@typescript-eslint/parser@8.59.4': + resolution: {integrity: sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.2': - resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} + '@typescript-eslint/parser@8.60.0': + resolution: {integrity: sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/tsconfig-utils@8.58.2': - resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} + '@typescript-eslint/project-service@8.59.4': + resolution: {integrity: sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.2': - resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} + '@typescript-eslint/project-service@8.60.0': + resolution: {integrity: sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.59.4': + resolution: {integrity: sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/scope-manager@8.60.0': + resolution: {integrity: sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.59.4': + resolution: {integrity: sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/tsconfig-utils@8.60.0': + resolution: {integrity: sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.59.4': + resolution: {integrity: sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.2': - resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} + '@typescript-eslint/type-utils@8.60.0': + resolution: {integrity: sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.59.4': + resolution: {integrity: sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/types@8.60.0': + resolution: {integrity: sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.59.4': + resolution: {integrity: sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/typescript-estree@8.60.0': + resolution: {integrity: sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/typescript-estree@8.58.2': - resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} + '@typescript-eslint/utils@8.59.4': + resolution: {integrity: sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.2': - resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} + '@typescript-eslint/utils@8.60.0': + resolution: {integrity: sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.2': - resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} + '@typescript-eslint/visitor-keys@8.59.4': + resolution: {integrity: sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@unocss/cli@66.6.8': - resolution: {integrity: sha512-dJ4AmrhCtQwEDJtpFG7AgJ4Qi4GWnNgWWlLWq4DhKBOCcvldr9k98mscdhs3MOwph25DIxU5MdLRAg/OS1JryQ==} - engines: {node: '>=14'} + '@typescript-eslint/visitor-keys@8.60.0': + resolution: {integrity: sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unocss/cli@66.7.0': + resolution: {integrity: sha512-Pkd/R+WDs8gc1i9fI5XDW8N5r7aoCWjNzt8wGGj5FWTbmsEzewueaL5LQTH4ymv/BhSHFcYpL7geQ5vYont+BA==} hasBin: true - '@unocss/config@66.6.8': - resolution: {integrity: sha512-f+a8OyhD7ZoK8Pa1b3Cbx1RQc3n5x+Qht/cHg3wh/g4DNQIjBI2EqwSLfBigWhdO96zIqFAdyTlO3onmrJwUOw==} - engines: {node: '>=14'} + '@unocss/config@66.7.0': + resolution: {integrity: sha512-C6waL+xzqAPzz5n47qnrs4GbyAtlusNYYmcV6DKYh1MgUP4EFhMnEMyuR2mw3M3tsBpyGuehLdRK5+ECF5yLkA==} '@unocss/core@0.25.1': resolution: {integrity: sha512-YYX40KA2rhsm6aTKTGpE0bi9E7RoAcuqMo/L+f6DmBSwtTXdflckoa903rxgOa6HOLH9fXgOJP9jHt3O/5ysPA==} - '@unocss/core@66.6.8': - resolution: {integrity: sha512-P9IlQfgms+8/nka7fBhiiWU4SPwrTNKbTdK0z1SLnttXMHHjsB2zpG+Vi1JQDpICfY9Y1/2pWtguPE+zeOVu9Q==} + '@unocss/core@66.7.0': + resolution: {integrity: sha512-j6MFMx5C3iIwW4T4hVbh+30fKWgSGkmS3bCcdjlfqM88lRT+dHFBN9nkfNOBJT6e6IHN9415nexuzcQvTjJXxw==} - '@unocss/extractor-arbitrary-variants@66.6.8': - resolution: {integrity: sha512-cOXstpPTOLt/HYcL0OsqFkNau0e8ktZ5Q8fgnXBZjmLGmi+VzdESNlwxZyCXLuamZGnbrZ8lDsKdsGG7P1pMKQ==} + '@unocss/extractor-arbitrary-variants@66.7.0': + resolution: {integrity: sha512-iHMlXmb8aGtYgPQ8o3D4rMz9DKOqSp8g/LWvEoiM7arSjJF9jMpcpYlqZXzkg1mSQX23TRW76Qxj1gyI4lRd9w==} - '@unocss/extractor-svelte@66.6.8': - resolution: {integrity: sha512-wd18VGnhtj+UXsVJ6gMGb3QN2/lgoZsHZ7kQO/nDcCBKJdVMygzz4a0Di30qJDSx5VuOqMVNFv9bO/ERBjxdQw==} + '@unocss/extractor-svelte@66.7.0': + resolution: {integrity: sha512-5T0FQdM2lNv6Q2BTynbsHX9dZ2gRkdnwmc43h+sDobdEOo9oBUiOzVsmez1AAyMvh/UPZF9Bz/UM4qKBuWZr2Q==} - '@unocss/inspector@66.6.8': - resolution: {integrity: sha512-g8uRzXDdmoNRjXX/mZP7m0rWXLtOimyOW7+VFK6FNxRWBmvIGYgTLHkutF6Wyh9lLPDYx3pkkEmfgL35BDT3Sg==} + '@unocss/inspector@66.7.0': + resolution: {integrity: sha512-W1MOO2d/1ZHwFR8+mrUUW6KW3MgJ6FdrSWfWeQ1+fgb0TVj8CweNzeSh46sTEXEcpvlui5mnGYFxanpLMoyOtA==} - '@unocss/preset-attributify@66.6.8': - resolution: {integrity: sha512-YxyRSF5rq0WbY8kCG0gpj3DSXPL89QGxZeqABmceCzPJbXJBBHEJz/pgBPmzSa2Ziulgs0AEkHzWFPfpb2uGTA==} + '@unocss/preset-attributify@66.7.0': + resolution: {integrity: sha512-n8ikthHHkAOeHWUwqRNIMGijV6LuIhiZb3D6kreV3oK98wJYupGNGYMByx7R9gQD9uBNLGs0f1jsaAScV3S2Sw==} - '@unocss/preset-icons@66.6.8': - resolution: {integrity: sha512-+zD5TNGZIXvVOMcvDIYaTXinffpDMERGj6Ch8WTtJluA6qHHBvRuFexoU2bY8nF1r0HZkYzNT9C+RujFSP+6TA==} + '@unocss/preset-icons@66.7.0': + resolution: {integrity: sha512-y6I2qZ2cwNAS2XRBig1lHzdFG9qTnZM/mx3fL3XnURnEYZird4uidLyWOyUGcdy1kMot1QcYVb0D/s9NgrEOgQ==} '@unocss/preset-mini@0.25.1': resolution: {integrity: sha512-NBfa2/t0TIAT//L8OVskDDQJ3OREjLwDzWMBNO86rvM0VPCIBvCmkKuFR3zxQcWK+aegISeScJA9Zcdk3qJjHA==} - '@unocss/preset-mini@66.6.8': - resolution: {integrity: sha512-vAechrReO7LtWzFAeF54P7CintG2m65SlVlBsi1x2Ru7IdgUNJEHII0MfXUvf9r1x8vsIlhATyaqqtBVT6ps/w==} + '@unocss/preset-mini@66.7.0': + resolution: {integrity: sha512-+YtRlr1Fjd24GYWhPB93r6fjefTBCnFUsZCASncSEU29u2Mi8MYINjefLfKlSJFMKg6AKzWbelKMCQfoKlUkbg==} - '@unocss/preset-tagify@66.6.8': - resolution: {integrity: sha512-cG6zBYswtWTpeQe/Lb1Bh+IzU4Ck+VI8rpYvrnvSGl22rJjAsXd+buB1P0PjyDpoe924rq0bLTayZ8r6Ayyyvw==} + '@unocss/preset-tagify@66.7.0': + resolution: {integrity: sha512-MaM07ChHsX8XZM3tlMPuRsZxbNvRVTbmIncOj9cCCrFpeOu8hy2ggRAgGOalWIwnIHc+5KQIkqucbgmXN7KBdA==} - '@unocss/preset-typography@66.6.8': - resolution: {integrity: sha512-wOApJpE0QfeOTWN5RuQts8zS6PXhTZIfjpt6cBj8dmv7+GlIQlwopxL7wcDb2wVwdCByuMvUbWl7nC3kz/iFTA==} + '@unocss/preset-typography@66.7.0': + resolution: {integrity: sha512-Ekdz7jw/TYTiH+QFqMWcWNMnvBnUZ/XPUF938C8DfqD79hZyLdRPo0kQaZh62cit13xNRAb49QP3HIUJIUxoGA==} '@unocss/preset-uno@0.25.1': resolution: {integrity: sha512-e5lvCF5GD52nD/7l/k4TJedw5AgsVGTs/6rKxE9DP0G5oGszKjx+oHLzoYvCP2aQAcallnZ/CxXTbOvqCQCVxQ==} - '@unocss/preset-uno@66.6.8': - resolution: {integrity: sha512-z01Rw/rBuahRulwQRnobUFnGqyU+UenOLz72KGn4p0Yh8gBC44fPlNHsOWA0TNediHRJg33HptX4kx16HCVWDg==} + '@unocss/preset-uno@66.7.0': + resolution: {integrity: sha512-fcLTj5Wax3QydCSdJq9yQHhqKph6Mx9exwNnkaBCXtmBvrSBd2O6O9ZAylcISnACeXJkjSverU8qVu1X2tITdA==} - '@unocss/preset-web-fonts@66.6.8': - resolution: {integrity: sha512-AgEHO8h0AkeOT57AOE9PS7dJOa5Rfr0gIyz/FxA7vJ/FwgQL70uX+bRW8kmoH81zcjo5xBP2IX3Z6A8VAOo3Vw==} + '@unocss/preset-web-fonts@66.7.0': + resolution: {integrity: sha512-jpNLjo/2X/J2J+G/M9W+y6VuiIhjZ9AyOnyNJHsdhmSJYCsnMuaYtP9eFn4d9+oe3Sz2lVNPV0A9RiqQ+xVAyQ==} - '@unocss/preset-wind3@66.6.8': - resolution: {integrity: sha512-WNTeDAYCatmEFjBJ4itUmz0TElBvNFqjh5i2/ianDJO/vkd+IYUb03jEPLUppVlvMhy8bN8AunP0AtW3Xf2psA==} + '@unocss/preset-wind3@66.7.0': + resolution: {integrity: sha512-1xxHBV4TtUHXPpYnWH8J2UHhxaMF84fTvadVzRRaXkyVrXD86Hveh/lfbXHXnCyf0JxwqsleOq8CnCTT8AgoAg==} - '@unocss/preset-wind4@66.6.8': - resolution: {integrity: sha512-CheOm7KXOsTI5t4RXgeYz95CO5p589F6jsyYp+inOCk4N0/d+DWiDHrQ+V0x0HWs3JXWlD+/Va/yXjlc3o2sIw==} + '@unocss/preset-wind4@66.7.0': + resolution: {integrity: sha512-5o3y2BcImLbkxa0fNtwaH8iB47FrOKzT7Xogni5PIDOX/DsoHfDLNiNBRrHHHHBeZ3jqvjv2T9T5kEkD5/WtYQ==} '@unocss/preset-wind@0.25.1': resolution: {integrity: sha512-y5gkCCNiGsonqI8OOmtMVXgEMjPDtr+ihxnS3oDptYR4CcBE1cREhLgZocChHHQNEMN9Qx2GsoMN9l6RsoExiA==} - '@unocss/preset-wind@66.6.8': - resolution: {integrity: sha512-F0mdmwK/HelYOgBRMHl+Yx/VyARCQJtPlcgPBejI3E9ZWOZlKS7hvPqPrgvS63WTGMHgM3/22cGuYYFjpi/ugA==} + '@unocss/preset-wind@66.7.0': + resolution: {integrity: sha512-K2cCgQawl4GzFyI9almN4jZ33OJNI6U7WxZ9s7D5bivZYfHPaStLTPffNxWlmawwUZF0qpH0S+S7H745ZzgajQ==} - '@unocss/rule-utils@66.6.8': - resolution: {integrity: sha512-WR35L07mLP6PElD4hlUHo5KbQ48uz2HT/XCuJyAsHP+15Gv6539hPWA5SresPuva9r8rl+PeGIgMSIKf4A5Ihw==} - engines: {node: '>=14'} + '@unocss/rule-utils@66.7.0': + resolution: {integrity: sha512-DMJIiey/m+xr0hpSbxFhSbKlC3e7QsuwdAEdgMmIM7pEcu/AEMl7oH198QYX9880P2X0hy5iFE6UCWx9CwGAXQ==} - '@unocss/transformer-attributify-jsx@66.6.8': - resolution: {integrity: sha512-g+7lvm+8V1MnJ21ialTxFBonCTtenn/KcZQbm0JfvQjgG+KuuSnt3BGEcXAHQZu3eBDGuJuasTHiXWwzCYIRBQ==} + '@unocss/transformer-attributify-jsx@66.7.0': + resolution: {integrity: sha512-mmsAUluRprSyejbzeQnC3ST056EUj2IxD2hMpPJPtnA4QkkyIgBNCmi2OSeVcEWMat1s3r4LcYSTqN88EcX5Kg==} - '@unocss/transformer-compile-class@66.6.8': - resolution: {integrity: sha512-37dFuzgYo8ki033KmuvyZXugQRVH1c3+/z5kcWLPhcMR8UJscAtjgRx80S1UvWup2q6TPxPpmy/rMbqWvs3jfg==} + '@unocss/transformer-compile-class@66.7.0': + resolution: {integrity: sha512-Z3K/s3TmUqUBGgB2SThWbUAP5E9VIFacbs2+bNJNn+53y1kqdLA1MIje3xlU5hig3OzGk8newwiMflh3s3Jzhg==} - '@unocss/transformer-directives@66.6.8': - resolution: {integrity: sha512-9hC3mQ8eycliW/igI9le0LovTIMBKoL6crucTkr4MmWuNqICMvNxTmGj5Xh64olBPnascevFwam6xsy+J1lX4Q==} + '@unocss/transformer-directives@66.7.0': + resolution: {integrity: sha512-6T9JxrPfLQlJFNLv7paG4yGiIgGrJY30268HWLkBFwgsldNPtQ+GeQJOzfemCH19UXXqqXMP0WnvbsFucdclmg==} - '@unocss/transformer-variant-group@66.6.8': - resolution: {integrity: sha512-+t7gJDW3W3z3/f8zBf0DfV2UZyGyFOwG5CIsIj5ofu3VJ91mKD/5ZAH8fD3cryXCBSqslj4yv+8R+BLV07T5AA==} + '@unocss/transformer-variant-group@66.7.0': + resolution: {integrity: sha512-2TXYLowPMXszGNYRXAWzQ1G9nGP6EYv9XeJvwNvnf0w9J6qOQVVtW/ZViIz61Kk083c06cZ6nai8pCBnc8aPAw==} - '@unocss/vite@66.6.8': - resolution: {integrity: sha512-bXfEnEHdW7zTGLIYU16MsfKSFy3Q47Pevhrt5f9fOGzC4UI1JGkkoQSfoFpXZGliDrhoSFK4Msz9Jt43Ta4j+w==} + '@unocss/vite@66.7.0': + resolution: {integrity: sha512-7J8Mk9M1j55S3bXL87/yHOspnuAaftQWbc3HjCH0/sXNLZJZnlpmUue3EtT5Ez+PE01T3DK1D9Xxn/MvtdvXtA==} peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0-0 + vite: ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0-0 - '@vitest/browser-playwright@4.1.4': - resolution: {integrity: sha512-q3PchVhZINX23Pv+RERgAtDlp6wzVkID/smOPnZ5YGWpeWUe3jMNYppeVh15j4il3G7JIJty1d1Kicpm0HSMig==} + '@valibot/to-json-schema@1.7.0': + resolution: {integrity: sha512-Y3pPVibbIOHzohrlxSINvO7w/bvXkoYS3BQHoImV9ynE+bXKf171bdMucPurV2zp7gdmt0L1HCcNAsbo7cFRQw==} + peerDependencies: + valibot: ^1.4.0 + + '@vinejs/compiler@3.0.0': + resolution: {integrity: sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==} + engines: {node: '>=18.0.0'} + + '@vinejs/vine@3.0.1': + resolution: {integrity: sha512-ZtvYkYpZOYdvbws3uaOAvTFuvFXoQGAtmzeiXu+XSMGxi5GVsODpoI9Xu9TplEMuD/5fmAtBbKb9cQHkWkLXDQ==} + engines: {node: '>=18.16.0'} + + '@vitest/browser-playwright@4.1.7': + resolution: {integrity: sha512-OlTlJej7YN6VwV7zJJoNeaCsctF+JXpzpZ4oBHUbrQFfIq+0KW2f07rprCLh9N/zRIZ0v4Mchn1QDDmWMUhPKw==} peerDependencies: playwright: '*' - vitest: 4.1.4 + vitest: 4.1.7 - '@vitest/browser@4.1.4': - resolution: {integrity: sha512-TrNaY/yVOwxtrxNsDUC/wQ56xSwplpytTeRAqF/197xV/ZddxxulBsxR6TrhVMyniJmp9in8d5u0AcDaNRY30w==} + '@vitest/browser@4.1.7': + resolution: {integrity: sha512-N2JFGfXoEGVAut+kHeru9dD4BUMq/q5xDvBARNl0tUsly3m5KglLOu8VO/6MkDfOlgxXTycojkt6gBKsuyR+IQ==} peerDependencies: - vitest: 4.1.4 + vitest: 4.1.7 - '@vitest/coverage-v8@4.1.4': - resolution: {integrity: sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==} + '@vitest/coverage-v8@4.1.7': + resolution: {integrity: sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==} peerDependencies: - '@vitest/browser': 4.1.4 - vitest: 4.1.4 + '@vitest/browser': 4.1.7 + vitest: 4.1.7 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.4': - resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==} + '@vitest/expect@4.1.7': + resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} - '@vitest/mocker@4.1.4': - resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==} + '@vitest/mocker@4.1.7': + resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1549,20 +1760,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.4': - resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==} + '@vitest/pretty-format@4.1.7': + resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} - '@vitest/runner@4.1.4': - resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==} + '@vitest/runner@4.1.7': + resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} - '@vitest/snapshot@4.1.4': - resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==} + '@vitest/snapshot@4.1.7': + resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} - '@vitest/spy@4.1.4': - resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==} + '@vitest/spy@4.1.7': + resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} - '@vitest/utils@4.1.4': - resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==} + '@vitest/utils@4.1.7': + resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -1574,34 +1785,26 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} ansi-escapes@7.3.0: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - apexcharts@5.10.6: - resolution: {integrity: sha512-FJQGbso3iRuOwUYnj0yUhkWeKeJE6aboVol+ae09lsc+lbLMWZqSRbrAWVa/qishLiaeG2icxdvmVkm+9n6kOQ==} + apexcharts@5.13.0: + resolution: {integrity: sha512-PJuXT6zdiCbv0IkX5cqkKFVIIh+9v3kqP9zsOHEGpIWi7DfTgzvfOKc8icw6G3/ulR3V1alDDUtOVH0zWCWGEQ==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1610,6 +1813,12 @@ packages: resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} engines: {node: '>= 0.4'} + arkregex@0.0.5: + resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} + + arktype@2.2.0: + resolution: {integrity: sha512-t54MZ7ti5BhOEvzEkgKnWvqj+UbDfWig+DHr5I34xatymPusKLS0lQpNJd8M6DzmIto2QGszHfNKoFIT8tMCZQ==} + array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} @@ -1620,8 +1829,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-v8-to-istanbul@1.0.0: - resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + ast-v8-to-istanbul@1.0.2: + resolution: {integrity: sha512-dKmJxJsGItLmc5CYZKuEjuG6GnBs6PG4gohMhyFOWKaNQoYCuRZJDECaBlHmcG0lv2wc2E0uU8lESmBEumC3DQ==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -1637,18 +1846,31 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + bits-ui@2.18.1: + resolution: {integrity: sha512-KkemzKFH4T3gt3H+P86JcnAWExjByv/6vlwjm/BoCwTPHu03yiCdxbghdJLvFReQTe0acCAiRcKfmixxD6XvlA==} + engines: {node: '>=20'} + peerDependencies: + '@internationalized/date': ^3.8.1 + svelte: ^5.33.0 + bottleneck@2.19.5: resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} - bun-types@1.3.12: - resolution: {integrity: sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA==} + bun-types@1.3.14: + resolution: {integrity: sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==} + + bun@1.3.14: + resolution: {integrity: sha512-aB6GVd42x1Y5ie1K16SF+oLGtgSkwX9hgoDdIW88pjvfTccU8F1vfpoOt34QLv0dZ1v3XimtaxPlZUG81Gx9Zg==} + cpu: [arm64, x64] + os: [darwin, linux, android, freebsd, win32] + hasBin: true cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} @@ -1658,6 +1880,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -1674,6 +1900,9 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + class-validator@0.14.4: + resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -1682,21 +1911,14 @@ packages: resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} engines: {node: '>=20'} - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1726,6 +1948,10 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + conventional-changelog-angular@8.3.1: resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} @@ -1789,8 +2015,11 @@ packages: engines: {node: '>=4'} hasBin: true - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + date-fns@4.3.0: + resolution: {integrity: sha512-OYcL+3N/jyWbYdFGqoMAhytDgxP9pbYPUUiRCOgn4Fewaadk9l/Wam4Avciiyp2BgkpfQyBV9B+ehnVJych+eQ==} + + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -1819,6 +2048,10 @@ packages: defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -1826,8 +2059,11 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - devalue@5.7.1: - resolution: {integrity: sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==} + devalue@5.8.1: + resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} dompurify@3.2.7: resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} @@ -1836,17 +2072,21 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + effect@3.21.2: + resolution: {integrity: sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg==} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - enhanced-resolve@5.20.1: - resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + enhanced-resolve@5.22.0: + resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} engines: {node: '>=10.13.0'} env-paths@2.2.1: @@ -1864,8 +2104,11 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-toolkit@1.47.0: + resolution: {integrity: sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==} escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} @@ -1912,8 +2155,8 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-svelte@3.17.0: - resolution: {integrity: sha512-sF6wgd5FLS2P8CCaOy2HdYYYEcZ6TwL251dLHUkNmtLnWECk1Dwc+j6VeulmmnFxr7Xs0WNtjweOA+bJ0PnaFw==} + eslint-plugin-svelte@3.17.1: + resolution: {integrity: sha512-NyiXHtS3Ni7e532RBwS9OXlMKDIrENg3gY+/+ODjZzQx2xhU3NlJ+nIl1a93iUUQeiJL3lS8KLmY+W8hklzweQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 @@ -1945,8 +2188,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.2.1: - resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==} + eslint@10.4.0: + resolution: {integrity: sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -1975,8 +2218,8 @@ packages: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} - esrap@2.2.5: - resolution: {integrity: sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig==} + esrap@2.2.9: + resolution: {integrity: sha512-4KijP+NxCWthMCUC3qHbE6n4vCjqgJS1uAYKhuT/GWfFTf1Qyive2TgOjep+gzbSzRfnNyaN/UU9YmdOt8Eg0A==} peerDependencies: '@typescript-eslint/types': ^8.2.0 peerDependenciesMeta: @@ -2012,6 +2255,10 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -2027,8 +2274,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -2076,8 +2323,15 @@ packages: flowbite@3.1.2: resolution: {integrity: sha512-MkwSgbbybCYgMC+go6Da5idEKUFfMqc/AmSjm/2ZbdmvoKf5frLPq/eIhXc9P+rC8t9boZtUXzHDgt5whZ6A/Q==} - flowbite@4.0.1: - resolution: {integrity: sha512-UwUjvnqrQTiFm3uMJ0WWnzKXKoDyNyfyEzoNnxmZo6KyDzCedjqZw1UW0Oqdn+E0iYVdPu0fizydJN6e4pP9Rw==} + flowbite@4.0.2: + resolution: {integrity: sha512-TxBdfZpd3HktHH4ashiYjirrSZeVPtG1OCRZMKTeXUa9FOlMxSF98zgjMB/AxE49KZ+rlfgWynAlaNpWxrqZmA==} + + formsnap@2.0.1: + resolution: {integrity: sha512-iJSe4YKd/W6WhLwKDVJU9FQeaJRpEFuolhju7ZXlRpUVyDdqFdMP8AUBICgnVvQPyP41IPAlBa/v0Eo35iE6wQ==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.0.0 + sveltekit-superforms: ^2.19.0 fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} @@ -2096,47 +2350,47 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.5.0: - resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} get-stream@9.0.1: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} - git-cliff-darwin-arm64@2.12.0: - resolution: {integrity: sha512-k3jzFDmkjc+6MjpnqvRenzMWRbZN5J+w3iQ8WNt9pSmPewNJIm92O/G6AbAxQaCbSfzQapeZ0e+5wSacVc62GA==} + git-cliff-darwin-arm64@2.13.1: + resolution: {integrity: sha512-3ebPUnUlLmrSZDHknSZQmyZV7DEJVtKse8I25Am0cENET5Py9u9Hg9k8IRXdiDtHtPDs6MYZx7BOi11WtcfqSg==} cpu: [arm64] os: [darwin] - git-cliff-darwin-x64@2.12.0: - resolution: {integrity: sha512-Kkoe+nfmXM/WMcZuC+OaIGA5vj847Ima6NEaaHnyb7Xsri+OAJryPXlABV7q6UeGfiiN2MlL8UsoHgnIEIQLqQ==} + git-cliff-darwin-x64@2.13.1: + resolution: {integrity: sha512-KZfggGAiw1EvZH3BOUclEU4eGCP2+Z+lH/N2Ni3FH9L2M1U7FYJqqaMhqgO8azTj67betvDshH8WBUkIkSsVxA==} cpu: [x64] os: [darwin] - git-cliff-linux-arm64@2.12.0: - resolution: {integrity: sha512-eTp2gZjV4LmfzdlhFsYFYuWf5mojALU03X/37r3VmnpuabaijuTEQo/zm/0BKP8gPiLKLR4ofdUvE1OSisCE1A==} + git-cliff-linux-arm64@2.13.1: + resolution: {integrity: sha512-clNRcNzdvk4GKyTt3ZhhWqcrjVRghcUcGNSV/Y87YJf3Mc/zl9ajUAhnXPOBSX/KWBr2od5SmkCt0qGYagY07g==} cpu: [arm64] os: [linux] - git-cliff-linux-x64@2.12.0: - resolution: {integrity: sha512-abidFG6dH2N5hPUF245/kRYdwViP11Pz7ZwIW/a86CJLZ/WSE7dJt0f2cUIkxTcFSsp11OwuLc5k1hAbwmiIRw==} + git-cliff-linux-x64@2.13.1: + resolution: {integrity: sha512-gZcIQhIQ1lDUMD8UieUSEZAYoyZN7nPd8O3VQoj1Ddhqll4UAS1Zxms1SU3U8pb0UTdc2m3ia/wtOnyhvbjdjQ==} cpu: [x64] os: [linux] - git-cliff-windows-arm64@2.12.0: - resolution: {integrity: sha512-rFuI+D/3Yq3jqafazZw5E68HsXEvcwI/B/5IPDIZD+QqZh8vETf4IXs7wVxYWWtHQJDC+G9ZrR3vE5648mdG3A==} + git-cliff-windows-arm64@2.13.1: + resolution: {integrity: sha512-+XubuQv68DuDwF0u6Af5d889MEf/RD48VBQS7ZmPi4sUSCXAZqRm1/ApCsStLqxMDCf1+7s05B/kNbm9wjV80A==} cpu: [arm64] os: [win32] - git-cliff-windows-x64@2.12.0: - resolution: {integrity: sha512-jskb3nyVGr4dekHSCDM/J6iho45t37wnmMGkPNq42kOoUp04JS96yMBrNRdXfXV9ViZsaZq3NaNu1e3QkhFlyA==} + git-cliff-windows-x64@2.13.1: + resolution: {integrity: sha512-Bi8ehp1VMkomY7M/356PgovKQ8CBRiuOOkq+aWC2evQuMFfXWjG0GBlPED9QkZoUJ4iQ5ygB5DYdK3BjhaOyPw==} cpu: [x64] os: [win32] - git-cliff@2.12.0: - resolution: {integrity: sha512-kjTm5439LsvMs/xRxndWBUetrA4aQfLE8DTbR/ER5H7fGn7ioeFG9YNAK1V7dpTtNi6k2uKYY4f3EvT8J1d+1Q==} - engines: {node: '>=18.19 || >=20.6 || >=21'} + git-cliff@2.13.1: + resolution: {integrity: sha512-2BzXwrom+SMHeNA5Ut+MtzqXejg0wbVwmzj3k7e9w62UQoyCDrM9UIcvtl6hnT3jocEQ1zLRQBaXXx97Gmnk7A==} + engines: {node: ^18.19 || >=20.6} hasBin: true git-raw-commits@5.0.1: @@ -2148,16 +2402,16 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} - engines: {node: '>=18'} + global-directory@5.0.0: + resolution: {integrity: sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==} + engines: {node: '>=20'} globals@16.5.0: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} - globals@17.5.0: - resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} + globals@17.6.0: + resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==} engines: {node: '>=18'} graceful-fs@4.2.11: @@ -2218,9 +2472,12 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} irregular-plurals@3.5.0: resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} @@ -2229,18 +2486,14 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - is-fullwidth-code-point@5.1.0: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} @@ -2293,6 +2546,13 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + js-sha256@0.11.1: resolution: {integrity: sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==} @@ -2317,6 +2577,10 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -2344,14 +2608,17 @@ packages: known-css-properties@0.37.0: resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} - kysely@0.28.16: - resolution: {integrity: sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww==} + kysely@0.28.17: + resolution: {integrity: sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==} engines: {node: '>=20.0.0'} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.13.3: + resolution: {integrity: sha512-xMkdAMqcyG7iN2WZZmGIfWbYxW4orRkny+0/AXIbwL0xll2zkDX0Vzo/BXFa6+7mh2UvJl9MbcTtHk0YXkFtBA==} + lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -2433,14 +2700,14 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lint-staged@16.4.0: - resolution: {integrity: sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==} - engines: {node: '>=20.17'} + lint-staged@17.0.5: + resolution: {integrity: sha512-d12yC+/e8RhBjZtaxZn71FyrgU/P5e+uAPifhCLwdosQZP/zamSdKRWDC30ocVIbzDKiFG1McHc/LUgB92GIPw==} + engines: {node: '>=22.22.1'} hasBin: true - listr2@9.0.5: - resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} - engines: {node: '>=20.0.0'} + listr2@10.2.1: + resolution: {integrity: sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==} + engines: {node: '>=22.13.0'} locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} @@ -2452,24 +2719,6 @@ packages: lodash-es@4.18.1: resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} - lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - - lodash.kebabcase@4.1.1: - resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} - - lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - - lodash.snakecase@4.1.1: - resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - - lodash.startcase@4.4.0: - resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - - lodash.upperfirst@4.3.1: - resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} - log-symbols@7.0.1: resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} engines: {node: '>=18'} @@ -2478,14 +2727,18 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-regexp@0.10.0: resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magicast@0.5.2: - resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + magicast@0.5.3: + resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -2499,6 +2752,9 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + memoize-weak@1.0.2: + resolution: {integrity: sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==} + meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} @@ -2519,12 +2775,14 @@ packages: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - mlly@1.8.2: resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + mode-watcher@1.1.0: + resolution: {integrity: sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g==} + peerDependencies: + svelte: ^5.27.0 + monaco-editor@0.55.1: resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} @@ -2539,8 +2797,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2550,6 +2808,10 @@ packages: node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + normalize-url@8.1.1: + resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==} + engines: {node: '>=14.16'} + npm-run-path@6.0.0: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} @@ -2571,8 +2833,8 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - oxc-parser@0.124.0: - resolution: {integrity: sha512-h07SFj/tp2U3cf3+LFX6MmOguQiM9ahwpGs0ZK5CGhgL8p4kk24etrJKsEzhXAvo7mfvoKTZooZ5MLKAPRmJ1g==} + oxc-parser@0.131.0: + resolution: {integrity: sha512-SJ3/7ZPbgie8dr5Z9BI/M51zZbpXba+hRSG0MDzVwMW5CRQg2fjYE0jHGlLX4eeiibGgC/mzoDFKSDHwVZEHRQ==} engines: {node: ^20.19.0 || >=22.12.0} oxc-walker@0.7.0: @@ -2645,13 +2907,13 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - playwright-core@1.59.1: - resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} + playwright-core@1.60.0: + resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} engines: {node: '>=18'} hasBin: true - playwright@1.59.1: - resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} + playwright@1.60.0: + resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} engines: {node: '>=18'} hasBin: true @@ -2691,8 +2953,8 @@ packages: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -2703,11 +2965,12 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier-plugin-svelte@3.5.1: - resolution: {integrity: sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==} + prettier-plugin-svelte@4.0.1: + resolution: {integrity: sha512-oDVmtKi+M8bJeUoMfPvulUqZYcuXrs5AmhhLYPKtBeg6hcpMdx7UYYisVCqEaLQuKtiPSYFpotfwp4cZK3D4xw==} + engines: {node: '>=20'} peerDependencies: prettier: ^3.0.0 - svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + svelte: ^5.0.0 prettier@2.5.1: resolution: {integrity: sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==} @@ -2723,10 +2986,16 @@ packages: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} + property-expr@2.0.6: + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} @@ -2742,10 +3011,6 @@ packages: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -2770,27 +3035,41 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown@1.0.0-rc.15: - resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.0-rc.16: - resolution: {integrity: sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true + runed@0.23.4: + resolution: {integrity: sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==} + peerDependencies: + svelte: ^5.7.0 + + runed@0.25.0: + resolution: {integrity: sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg==} + peerDependencies: + svelte: ^5.7.0 runed@0.28.0: resolution: {integrity: sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ==} peerDependencies: svelte: ^5.7.0 + runed@0.35.1: + resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==} + peerDependencies: + '@sveltejs/kit': ^2.21.0 + svelte: ^5.7.0 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} engines: {node: '>=10'} hasBin: true @@ -2847,22 +3126,14 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string-width@8.2.0: - resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} engines: {node: '>=20'} - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - strip-ansi@7.2.0: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} @@ -2871,6 +3142,13 @@ packages: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + supports-color@10.2.2: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} @@ -2893,17 +3171,17 @@ packages: '@sveltejs/kit': ^2.4.0 typescript: ^5 - svelte-check@4.4.6: - resolution: {integrity: sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg==} + svelte-check@4.4.8: + resolution: {integrity: sha512-67adfgBox5eNSNIvIIwgFizKGdcRrGpiMoNO2obHcYuLz7iTa8Xgm/NGU3ntMFnNm8K1grFOIG6HhMLX/vcN8w==} engines: {node: '>= 18.0.0'} hasBin: true peerDependencies: svelte: ^4.0.0 || ^5.0.0-next.0 typescript: '>=5.0.0' - svelte-eslint-parser@1.6.0: - resolution: {integrity: sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.30.3} + svelte-eslint-parser@1.6.1: + resolution: {integrity: sha512-hhvSH6kRj46UzrBVO5TaotD+Iuvruj5ccKBcO4wAhVcPTLmIc/c32D8UllBTYO0on4LzYuM0rNzf1lM/gBlkSQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.33.0} peerDependencies: svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: @@ -2916,21 +3194,48 @@ packages: '@sveltejs/kit': ^1.0.0 || ^2.0.0 svelte: ^5.1.13 - svelte-sonner@1.1.0: - resolution: {integrity: sha512-3lYM6ZIqWe+p9vwwWHGWP/ZdvHiUtzURsud2quIxivrX4rvpXh6i+geBGn0m3JS6KwW6W8VgbOl3xQMcDuh6gg==} + svelte-sonner@1.1.1: + resolution: {integrity: sha512-5cd3p7wa4cq0NsqslMwdlPb7x1JglEZ/GKrLePWNr5bCxR1nagAVrY01FRFrXfUGs41miLt3C327+8XJo5BzZw==} peerDependencies: svelte: ^5.0.0 - svelte@5.55.4: - resolution: {integrity: sha512-q8DFohk6vUswSng95IZb9nzWJnbINZsK7OiM1snAa3qCjJBL0ZQpvMyAaVXjUukdM75J/m8UE8xwqat8Ors/zQ==} + svelte-toolbelt@0.10.6: + resolution: {integrity: sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.30.2 + + svelte-toolbelt@0.5.0: + resolution: {integrity: sha512-t3tenZcnfQoIeRuQf/jBU7bvTeT3TGkcEE+1EUr5orp0lR7NEpprflpuie3x9Dn0W9nOKqs3HwKGJeeN5Ok1sQ==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.0.0-next.126 + + svelte-toolbelt@0.7.1: + resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.0.0 + + svelte@5.55.9: + resolution: {integrity: sha512-fTjjT8cHLDwigcu2j3pv7Jq04LklXevPB8uBgyHNiTXv+RMNvVnrjS4UEYrLMkhuq1vpCodHjiW+z/95SDs/fg==} engines: {node: '>=18'} + sveltekit-superforms@2.30.1: + resolution: {integrity: sha512-wBzyqsE0idvEJWuNJ+HCiAtdxa7Z55GZ8jmtlVHJfonrk9bRYC49MoPaloYyFoYuU3QPy6Omna/Qzn1kaIkgew==} + peerDependencies: + '@sveltejs/kit': 1.x || 2.x + svelte: 3.x || 4.x || >=5.0.0-next.51 + synckit@0.11.12: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} - tailwind-merge@3.5.0: - resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} tailwind-variants@3.2.2: resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} @@ -2942,18 +3247,21 @@ packages: tailwind-merge: optional: true - tailwindcss@4.2.2: - resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} - tapable@2.3.2: - resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tiny-case@1.0.3: + resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.1.1: - resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + tinyexec@1.2.2: + resolution: {integrity: sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==} engines: {node: '>=18'} tinyglobby@0.2.16: @@ -2968,16 +3276,26 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} + toposort@2.0.2: + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + ts-deepmerge@7.0.3: + resolution: {integrity: sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==} + engines: {node: '>=14.13.1'} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2989,11 +3307,25 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + type-level-regexp@0.1.17: resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} - typescript-eslint@8.58.2: - resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + + typescript-eslint@8.59.4: + resolution: {integrity: sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript-eslint@8.60.0: + resolution: {integrity: sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3004,8 +3336,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} unconfig-core@7.5.0: resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} @@ -3013,8 +3345,8 @@ packages: unconfig@7.5.0: resolution: {integrity: sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==} - undici-types@7.19.2: - resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} undici@6.25.0: resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==} @@ -3027,13 +3359,12 @@ packages: universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - unocss@66.6.8: - resolution: {integrity: sha512-stq9FbxedTDkoWrxnNQNnPQXOaM6L2Lobq8HzjXdR2tMc55gtfqDArqL7TESfnN7qeZsIocNYCHLNA4DXq50YQ==} - engines: {node: '>=14'} + unocss@66.7.0: + resolution: {integrity: sha512-dVfkL7SQv3fOiZdqeRX1PdpQqXlB+wHcEQjVR0D/2nXsuqmUqTVnX3EUUWFjqVR83Z51zQ0EyVgym8ooDfcVvw==} peerDependencies: - '@unocss/astro': 66.6.8 - '@unocss/postcss': 66.6.8 - '@unocss/webpack': 66.6.8 + '@unocss/astro': 66.7.0 + '@unocss/postcss': 66.7.0 + '@unocss/webpack': 66.7.0 peerDependenciesMeta: '@unocss/astro': optional: true @@ -3059,21 +3390,29 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + uuid@14.0.0: + resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true - uuid@13.0.0: - resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} - hasBin: true + valibot@1.4.1: + resolution: {integrity: sha512-klCmFTz2jeDluy9RwX+F884TCiogtdBJ/YaxSx1EOBYXa3NXNWj8kR1jjN8rzluwojJVWWaHJ4r1U5LfICnM3g==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true - vite@8.0.8: - resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} + engines: {node: '>= 0.10'} + + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 + '@vitejs/devtools': ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -3124,20 +3463,20 @@ packages: svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0 vitest: ^4.0.0 - vitest@4.1.4: - resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==} + vitest@4.1.7: + resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.4 - '@vitest/browser-preview': 4.1.4 - '@vitest/browser-webdriverio': 4.1.4 - '@vitest/coverage-istanbul': 4.1.4 - '@vitest/coverage-v8': 4.1.4 - '@vitest/ui': 4.1.4 + '@vitest/browser-playwright': 4.1.7 + '@vitest/browser-preview': 4.1.7 + '@vitest/browser-webdriverio': 4.1.7 + '@vitest/coverage-istanbul': 4.1.7 + '@vitest/coverage-v8': 4.1.7 + '@vitest/ui': 4.1.7 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3182,16 +3521,16 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@10.0.0: + resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} + engines: {node: '>=20'} wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -3210,18 +3549,18 @@ packages: resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} hasBin: true - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} @@ -3231,27 +3570,38 @@ packages: resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} + yup@1.7.1: + resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==} + zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + zod-v3-to-json-schema@4.0.0: + resolution: {integrity: sha512-KixLrhX/uPmRFnDgsZrzrk4x5SSJA+PmaE5adbfID9+3KPJcdxqRobaHU397EfWBqfQircrjKqvEqZ/mW5QH6w==} + peerDependencies: + zod: ^3.25 || ^4.0.14 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + snapshots: - '@actions/core@3.0.0': + '@actions/core@3.0.1': dependencies: '@actions/exec': 3.0.0 - '@actions/http-client': 4.0.0 + '@actions/http-client': 4.0.1 '@actions/exec@3.0.0': dependencies: '@actions/io': 3.0.2 - '@actions/github@9.1.0': + '@actions/github@9.1.1': dependencies: '@actions/http-client': 3.0.2 '@octokit/core': 7.0.6 '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) - '@octokit/request': 10.0.8 + '@octokit/request': 10.0.9 '@octokit/request-error': 7.1.0 undici: 6.25.0 @@ -3260,7 +3610,7 @@ snapshots: tunnel: 0.0.6 undici: 6.25.0 - '@actions/http-client@4.0.0': + '@actions/http-client@4.0.1': dependencies: tunnel: 0.0.6 undici: 6.25.0 @@ -3278,169 +3628,174 @@ snapshots: '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.6.0 - tinyexec: 1.1.1 + tinyexec: 1.2.2 + + '@ark/schema@0.56.0': + dependencies: + '@ark/util': 0.56.0 + optional: true + + '@ark/util@0.56.0': + optional: true - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/generator@7.29.1': + '@babel/generator@7.29.7': dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/parser@7.29.2': + '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/template@7.28.6': + '@babel/runtime@7.29.7': + optional: true + + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.29.0': + '@babel/types@7.29.7': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 '@bcoe/v8-coverage@1.0.2': {} '@blazediff/core@1.9.1': {} - '@commitlint/cli@20.5.0(@types/node@25.6.0)(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0)(typescript@6.0.3)': + '@commitlint/cli@21.0.1(@types/node@25.9.1)(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0)(typescript@6.0.3)': dependencies: - '@commitlint/format': 20.5.0 - '@commitlint/lint': 20.5.0 - '@commitlint/load': 20.5.0(@types/node@25.6.0)(typescript@6.0.3) - '@commitlint/read': 20.5.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0) - '@commitlint/types': 20.5.0 - tinyexec: 1.1.1 - yargs: 17.7.2 + '@commitlint/format': 21.0.1 + '@commitlint/lint': 21.0.1 + '@commitlint/load': 21.0.1(@types/node@25.9.1)(typescript@6.0.3) + '@commitlint/read': 21.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0) + '@commitlint/types': 21.0.1 + tinyexec: 1.2.2 + yargs: 18.0.0 transitivePeerDependencies: - '@types/node' - conventional-commits-filter - conventional-commits-parser - typescript - '@commitlint/config-conventional@20.5.0': + '@commitlint/config-conventional@21.0.1': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 conventional-changelog-conventionalcommits: 9.3.1 - '@commitlint/config-validator@20.5.0': + '@commitlint/config-validator@21.0.1': dependencies: - '@commitlint/types': 20.5.0 - ajv: 8.18.0 + '@commitlint/types': 21.0.1 + ajv: 8.20.0 - '@commitlint/ensure@20.5.0': + '@commitlint/ensure@21.0.1': dependencies: - '@commitlint/types': 20.5.0 - lodash.camelcase: 4.3.0 - lodash.kebabcase: 4.1.1 - lodash.snakecase: 4.1.1 - lodash.startcase: 4.4.0 - lodash.upperfirst: 4.3.1 + '@commitlint/types': 21.0.1 + es-toolkit: 1.47.0 - '@commitlint/execute-rule@20.0.0': {} + '@commitlint/execute-rule@21.0.1': {} - '@commitlint/format@20.5.0': + '@commitlint/format@21.0.1': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 picocolors: 1.1.1 - '@commitlint/is-ignored@20.5.0': + '@commitlint/is-ignored@21.0.1': dependencies: - '@commitlint/types': 20.5.0 - semver: 7.7.4 + '@commitlint/types': 21.0.1 + semver: 7.8.1 - '@commitlint/lint@20.5.0': + '@commitlint/lint@21.0.1': dependencies: - '@commitlint/is-ignored': 20.5.0 - '@commitlint/parse': 20.5.0 - '@commitlint/rules': 20.5.0 - '@commitlint/types': 20.5.0 + '@commitlint/is-ignored': 21.0.1 + '@commitlint/parse': 21.0.1 + '@commitlint/rules': 21.0.1 + '@commitlint/types': 21.0.1 - '@commitlint/load@20.5.0(@types/node@25.6.0)(typescript@6.0.3)': + '@commitlint/load@21.0.1(@types/node@25.9.1)(typescript@6.0.3)': dependencies: - '@commitlint/config-validator': 20.5.0 - '@commitlint/execute-rule': 20.0.0 - '@commitlint/resolve-extends': 20.5.0 - '@commitlint/types': 20.5.0 + '@commitlint/config-validator': 21.0.1 + '@commitlint/execute-rule': 21.0.1 + '@commitlint/resolve-extends': 21.0.1 + '@commitlint/types': 21.0.1 cosmiconfig: 9.0.1(typescript@6.0.3) - cosmiconfig-typescript-loader: 6.3.0(@types/node@25.6.0)(cosmiconfig@9.0.1(typescript@6.0.3))(typescript@6.0.3) + cosmiconfig-typescript-loader: 6.3.0(@types/node@25.9.1)(cosmiconfig@9.0.1(typescript@6.0.3))(typescript@6.0.3) + es-toolkit: 1.47.0 is-plain-obj: 4.1.0 - lodash.mergewith: 4.6.2 picocolors: 1.1.1 transitivePeerDependencies: - '@types/node' - typescript - '@commitlint/message@20.4.3': {} + '@commitlint/message@21.0.1': {} - '@commitlint/parse@20.5.0': + '@commitlint/parse@21.0.1': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 conventional-changelog-angular: 8.3.1 conventional-commits-parser: 6.4.0 - '@commitlint/read@20.5.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0)': + '@commitlint/read@21.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0)': dependencies: - '@commitlint/top-level': 20.4.3 - '@commitlint/types': 20.5.0 + '@commitlint/top-level': 21.0.1 + '@commitlint/types': 21.0.1 git-raw-commits: 5.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0) - minimist: 1.2.8 - tinyexec: 1.1.1 + tinyexec: 1.2.2 transitivePeerDependencies: - conventional-commits-filter - conventional-commits-parser - '@commitlint/resolve-extends@20.5.0': + '@commitlint/resolve-extends@21.0.1': dependencies: - '@commitlint/config-validator': 20.5.0 - '@commitlint/types': 20.5.0 - global-directory: 4.0.1 - import-meta-resolve: 4.2.0 - lodash.mergewith: 4.6.2 + '@commitlint/config-validator': 21.0.1 + '@commitlint/types': 21.0.1 + es-toolkit: 1.47.0 + global-directory: 5.0.0 resolve-from: 5.0.0 - '@commitlint/rules@20.5.0': + '@commitlint/rules@21.0.1': dependencies: - '@commitlint/ensure': 20.5.0 - '@commitlint/message': 20.4.3 - '@commitlint/to-lines': 20.0.0 - '@commitlint/types': 20.5.0 + '@commitlint/ensure': 21.0.1 + '@commitlint/message': 21.0.1 + '@commitlint/to-lines': 21.0.1 + '@commitlint/types': 21.0.1 - '@commitlint/to-lines@20.0.0': {} + '@commitlint/to-lines@21.0.1': {} - '@commitlint/top-level@20.4.3': + '@commitlint/top-level@21.0.1': dependencies: escalade: 3.2.0 - '@commitlint/types@20.5.0': + '@commitlint/types@21.0.1': dependencies: conventional-commits-parser: 6.4.0 picocolors: 1.1.1 @@ -3449,7 +3804,7 @@ snapshots: dependencies: '@simple-libs/child-process-utils': 1.0.2 '@simple-libs/stream-utils': 1.2.0 - semver: 7.7.4 + semver: 7.8.1 optionalDependencies: conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.4.0 @@ -3460,13 +3815,13 @@ snapshots: '@dprint/toml@0.7.0': {} - '@emnapi/core@1.9.2': + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.2': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true @@ -3476,9 +3831,9 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.4.0(jiti@2.7.0))': dependencies: - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.4.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -3491,7 +3846,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.5': + '@eslint/config-helpers@0.6.0': dependencies: '@eslint/core': 1.2.1 @@ -3508,6 +3863,9 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 + '@exodus/schemasafe@1.3.0': + optional: true + '@favware/cliff-jumper@6.1.0': dependencies: '@favware/colorette-spinner': 1.0.1 @@ -3520,9 +3878,9 @@ snapshots: commander: 14.0.3 conventional-recommended-bump: 11.2.0 execa: 9.6.1 - git-cliff: 2.12.0 + git-cliff: 2.13.1 js-yaml: 4.1.1 - semver: 7.7.4 + semver: 7.8.1 smol-toml: 1.6.1 '@favware/colorette-spinner@1.0.1': @@ -3540,6 +3898,14 @@ snapshots: '@floating-ui/utils@0.2.11': {} + '@hapi/hoek@9.3.0': + optional: true + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + optional: true + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -3560,7 +3926,7 @@ snapshots: dependencies: '@iconify/types': 2.0.0 - '@iconify-json/material-icon-theme@1.2.59': + '@iconify-json/material-icon-theme@1.2.66': dependencies: '@iconify/types': 2.0.0 @@ -3570,21 +3936,23 @@ snapshots: '@iconify/types@2.0.0': {} - '@iconify/utils@3.1.0': + '@iconify/utils@3.1.3': dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/types': 2.0.0 - mlly: 1.8.2 + import-meta-resolve: 4.2.0 - '@inlang/paraglide-js@2.16.0': + '@inlang/paraglide-js@2.18.1(typescript@6.0.3)': dependencies: '@inlang/recommend-sherlock': 0.2.1 - '@inlang/sdk': 2.9.1 + '@inlang/sdk': 2.9.3 commander: 11.1.0 consola: 3.4.0 json5: 2.2.3 unplugin: 2.3.11 urlpattern-polyfill: 10.1.0 + optionalDependencies: + typescript: 6.0.3 transitivePeerDependencies: - babel-plugin-macros @@ -3592,16 +3960,20 @@ snapshots: dependencies: comment-json: 4.6.2 - '@inlang/sdk@2.9.1': + '@inlang/sdk@2.9.3': dependencies: - '@lix-js/sdk': 0.4.9 + '@lix-js/sdk': 0.4.10 '@sinclair/typebox': 0.31.28 - kysely: 0.28.16 - sqlite-wasm-kysely: 0.3.0(kysely@0.28.16) - uuid: 13.0.0 + kysely: 0.28.17 + sqlite-wasm-kysely: 0.3.0(kysely@0.28.17) + uuid: 14.0.0 transitivePeerDependencies: - babel-plugin-macros + '@internationalized/date@3.12.1': + dependencies: + '@swc/helpers': 0.5.21 + '@isaacs/ttlcache@1.4.1': {} '@jridgewell/gen-mapping@0.3.13': @@ -3623,42 +3995,47 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@lix-js/sdk@0.4.9': + '@lix-js/sdk@0.4.10': dependencies: '@lix-js/server-protocol-schema': 0.1.1 dedent: 1.5.1 human-id: 4.1.3 js-sha256: 0.11.1 - kysely: 0.28.16 - sqlite-wasm-kysely: 0.3.0(kysely@0.28.16) - uuid: 10.0.0 + kysely: 0.28.17 + sqlite-wasm-kysely: 0.3.0(kysely@0.28.17) + uuid: 14.0.0 transitivePeerDependencies: - babel-plugin-macros '@lix-js/server-protocol-schema@0.1.1': {} - '@nanoforge-dev/actions@1.2.3': + '@lucide/svelte@1.16.0(svelte@5.55.9(@typescript-eslint/types@8.60.0))': + dependencies: + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + + '@nanoforge-dev/actions@2.0.0': dependencies: - '@actions/core': 3.0.0 - '@actions/github': 9.1.0 + '@actions/core': 3.0.1 + '@actions/github': 9.1.1 commander: 14.0.3 + semver: 7.8.1 - '@nanoforge-dev/common@1.1.0': {} + '@nanoforge-dev/common@1.3.0': {} - '@nanoforge-dev/ecs-lib@1.1.2': + '@nanoforge-dev/ecs-lib@1.3.0': dependencies: - '@nanoforge-dev/common': 1.1.0 + '@nanoforge-dev/common': 1.3.0 - '@nanoforge-dev/utils-eslint-config@1.0.2(@types/eslint@9.6.1)(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3)(typescript@6.0.3)': + '@nanoforge-dev/utils-eslint-config@1.0.2(@types/eslint@9.6.1)(eslint@10.4.0(jiti@2.7.0))(prettier@3.8.3)(typescript@6.0.3)': dependencies: '@eslint/js': 9.39.4 '@favware/cliff-jumper': 6.1.0 - eslint-config-prettier: 10.1.8(eslint@10.2.1(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@10.4.0(jiti@2.7.0)) eslint-formatter-pretty: 7.1.0 - eslint-plugin-format: 1.5.0(eslint@10.2.1(jiti@2.6.1)) - eslint-plugin-prettier: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)))(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3) + eslint-plugin-format: 1.5.0(eslint@10.4.0(jiti@2.7.0)) + eslint-plugin-prettier: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.4.0(jiti@2.7.0)))(eslint@10.4.0(jiti@2.7.0))(prettier@3.8.3) globals: 16.5.0 - typescript-eslint: 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + typescript-eslint: 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) transitivePeerDependencies: - '@types/eslint' - eslint @@ -3668,11 +4045,11 @@ snapshots: '@nanoforge-dev/utils-prettier-config@1.0.2': {} - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 optional: true '@octokit/auth-token@6.0.0': {} @@ -3681,7 +4058,7 @@ snapshots: dependencies: '@octokit/auth-token': 6.0.0 '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.8 + '@octokit/request': 10.0.9 '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 before-after-hook: 4.0.0 @@ -3694,7 +4071,7 @@ snapshots: '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.8 + '@octokit/request': 10.0.9 '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 @@ -3721,11 +4098,12 @@ snapshots: dependencies: '@octokit/types': 16.0.0 - '@octokit/request@10.0.8': + '@octokit/request@10.0.9': dependencies: '@octokit/endpoint': 11.0.3 '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 + content-type: 2.0.0 fast-content-type-parse: 3.0.0 json-with-bigint: 3.5.8 universal-user-agent: 7.0.3 @@ -3734,247 +4112,246 @@ snapshots: dependencies: '@octokit/openapi-types': 27.0.0 - '@oxc-parser/binding-android-arm-eabi@0.124.0': + '@oven/bun-darwin-aarch64@1.3.14': optional: true - '@oxc-parser/binding-android-arm64@0.124.0': + '@oven/bun-darwin-x64-baseline@1.3.14': optional: true - '@oxc-parser/binding-darwin-arm64@0.124.0': + '@oven/bun-darwin-x64@1.3.14': optional: true - '@oxc-parser/binding-darwin-x64@0.124.0': + '@oven/bun-freebsd-aarch64@1.3.14': optional: true - '@oxc-parser/binding-freebsd-x64@0.124.0': + '@oven/bun-freebsd-x64@1.3.14': optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.124.0': + '@oven/bun-linux-aarch64-android@1.3.14': optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.124.0': + '@oven/bun-linux-aarch64-musl@1.3.14': optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.124.0': + '@oven/bun-linux-aarch64@1.3.14': optional: true - '@oxc-parser/binding-linux-arm64-musl@0.124.0': + '@oven/bun-linux-x64-android@1.3.14': optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.124.0': + '@oven/bun-linux-x64-baseline@1.3.14': optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.124.0': + '@oven/bun-linux-x64-musl-baseline@1.3.14': optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.124.0': + '@oven/bun-linux-x64-musl@1.3.14': optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.124.0': + '@oven/bun-linux-x64@1.3.14': optional: true - '@oxc-parser/binding-linux-x64-gnu@0.124.0': + '@oven/bun-windows-aarch64@1.3.14': optional: true - '@oxc-parser/binding-linux-x64-musl@0.124.0': + '@oven/bun-windows-x64-baseline@1.3.14': optional: true - '@oxc-parser/binding-openharmony-arm64@0.124.0': + '@oven/bun-windows-x64@1.3.14': optional: true - '@oxc-parser/binding-wasm32-wasi@0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': - dependencies: - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' + '@oxc-parser/binding-android-arm-eabi@0.131.0': optional: true - '@oxc-parser/binding-win32-arm64-msvc@0.124.0': + '@oxc-parser/binding-android-arm64@0.131.0': optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.124.0': + '@oxc-parser/binding-darwin-arm64@0.131.0': optional: true - '@oxc-parser/binding-win32-x64-msvc@0.124.0': + '@oxc-parser/binding-darwin-x64@0.131.0': optional: true - '@oxc-project/types@0.124.0': {} - - '@oxc-project/types@0.126.0': {} - - '@oxfmt/binding-android-arm-eabi@0.35.0': + '@oxc-parser/binding-freebsd-x64@0.131.0': optional: true - '@oxfmt/binding-android-arm64@0.35.0': + '@oxc-parser/binding-linux-arm-gnueabihf@0.131.0': optional: true - '@oxfmt/binding-darwin-arm64@0.35.0': + '@oxc-parser/binding-linux-arm-musleabihf@0.131.0': optional: true - '@oxfmt/binding-darwin-x64@0.35.0': + '@oxc-parser/binding-linux-arm64-gnu@0.131.0': optional: true - '@oxfmt/binding-freebsd-x64@0.35.0': + '@oxc-parser/binding-linux-arm64-musl@0.131.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.35.0': + '@oxc-parser/binding-linux-ppc64-gnu@0.131.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.35.0': + '@oxc-parser/binding-linux-riscv64-gnu@0.131.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.35.0': + '@oxc-parser/binding-linux-riscv64-musl@0.131.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.35.0': + '@oxc-parser/binding-linux-s390x-gnu@0.131.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.35.0': + '@oxc-parser/binding-linux-x64-gnu@0.131.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.35.0': + '@oxc-parser/binding-linux-x64-musl@0.131.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.35.0': + '@oxc-parser/binding-openharmony-arm64@0.131.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.35.0': + '@oxc-parser/binding-wasm32-wasi@0.131.0': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@oxfmt/binding-linux-x64-gnu@0.35.0': + '@oxc-parser/binding-win32-arm64-msvc@0.131.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.35.0': + '@oxc-parser/binding-win32-ia32-msvc@0.131.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.35.0': + '@oxc-parser/binding-win32-x64-msvc@0.131.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.35.0': - optional: true + '@oxc-project/types@0.131.0': {} - '@oxfmt/binding-win32-ia32-msvc@0.35.0': + '@oxc-project/types@0.132.0': {} + + '@oxfmt/binding-android-arm-eabi@0.35.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.35.0': + '@oxfmt/binding-android-arm64@0.35.0': optional: true - '@pkgr/core@0.2.9': {} + '@oxfmt/binding-darwin-arm64@0.35.0': + optional: true - '@playwright/test@1.59.1': - dependencies: - playwright: 1.59.1 + '@oxfmt/binding-darwin-x64@0.35.0': + optional: true - '@polka/url@1.0.0-next.29': {} + '@oxfmt/binding-freebsd-x64@0.35.0': + optional: true - '@popperjs/core@2.11.8': {} + '@oxfmt/binding-linux-arm-gnueabihf@0.35.0': + optional: true - '@quansync/fs@1.0.0': - dependencies: - quansync: 1.0.0 + '@oxfmt/binding-linux-arm-musleabihf@0.35.0': + optional: true - '@rolldown/binding-android-arm64@1.0.0-rc.15': + '@oxfmt/binding-linux-arm64-gnu@0.35.0': optional: true - '@rolldown/binding-android-arm64@1.0.0-rc.16': + '@oxfmt/binding-linux-arm64-musl@0.35.0': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + '@oxfmt/binding-linux-ppc64-gnu@0.35.0': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.16': + '@oxfmt/binding-linux-riscv64-gnu@0.35.0': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.15': + '@oxfmt/binding-linux-riscv64-musl@0.35.0': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.16': + '@oxfmt/binding-linux-s390x-gnu@0.35.0': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + '@oxfmt/binding-linux-x64-gnu@0.35.0': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.16': + '@oxfmt/binding-linux-x64-musl@0.35.0': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + '@oxfmt/binding-openharmony-arm64@0.35.0': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16': + '@oxfmt/binding-win32-arm64-msvc@0.35.0': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + '@oxfmt/binding-win32-ia32-msvc@0.35.0': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16': + '@oxfmt/binding-win32-x64-msvc@0.35.0': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': - optional: true + '@pkgr/core@0.2.9': {} + + '@playwright/test@1.60.0': + dependencies: + playwright: 1.60.0 + + '@polka/url@1.0.0-next.29': {} + + '@popperjs/core@2.11.8': {} - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.16': + '@poppinss/macroable@1.1.2': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': - optional: true + '@quansync/fs@1.0.0': + dependencies: + quansync: 1.0.0 - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.16': + '@rolldown/binding-android-arm64@1.0.2': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + '@rolldown/binding-darwin-arm64@1.0.2': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16': + '@rolldown/binding-darwin-x64@1.0.2': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + '@rolldown/binding-freebsd-x64@1.0.2': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.16': + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.16': + '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + '@rolldown/binding-linux-ppc64-gnu@1.0.2': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.16': + '@rolldown/binding-linux-s390x-gnu@1.0.2': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': - dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@rolldown/binding-linux-x64-gnu@1.0.2': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.16': - dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@rolldown/binding-linux-x64-musl@1.0.2': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + '@rolldown/binding-openharmony-arm64@1.0.2': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16': + '@rolldown/binding-wasm32-wasi@1.0.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.16': + '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true - '@rolldown/pluginutils@1.0.0-rc.15': {} - - '@rolldown/pluginutils@1.0.0-rc.16': {} + '@rolldown/pluginutils@1.0.1': {} '@rollup/plugin-node-resolve@15.3.1': dependencies: @@ -3986,7 +4363,7 @@ snapshots: '@rollup/pluginutils@5.3.0': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 @@ -3996,6 +4373,17 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + optional: true + + '@sideway/formula@3.0.1': + optional: true + + '@sideway/pinpoint@2.0.0': + optional: true + '@simple-libs/child-process-utils@1.0.2': dependencies: '@simple-libs/stream-utils': 1.2.0 @@ -4010,139 +4398,150 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@sveltejs/acorn-typescript@1.0.9(acorn@8.16.0)': + '@sveltejs/acorn-typescript@1.0.10(acorn@8.16.0)': dependencies: acorn: 8.16.0 - '@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))': + '@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@standard-schema/spec': 1.1.0 - '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + '@sveltejs/acorn-typescript': 1.0.10(acorn@8.16.0) + '@sveltejs/vite-plugin-svelte': 7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 - devalue: 5.7.1 + devalue: 5.8.1 esm-env: 1.2.2 kleur: 4.1.5 magic-string: 0.30.21 mrmime: 2.0.1 set-cookie-parser: 3.1.0 sirv: 3.0.2 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - vite: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) optionalDependencies: typescript: 6.0.3 - '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))': + '@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - vite: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) - vitefu: 1.1.3(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + + '@swc/helpers@0.5.21': + dependencies: + tslib: 2.8.1 - '@tailwindcss/node@4.2.2': + '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.1 - jiti: 2.6.1 + enhanced-resolve: 5.22.0 + jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.2 + tailwindcss: 4.3.0 - '@tailwindcss/oxide-android-arm64@4.2.2': + '@tailwindcss/oxide-android-arm64@4.3.0': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.2': + '@tailwindcss/oxide-darwin-arm64@4.3.0': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.2': + '@tailwindcss/oxide-darwin-x64@4.3.0': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.2': + '@tailwindcss/oxide-freebsd-x64@4.3.0': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.2': + '@tailwindcss/oxide-linux-x64-musl@4.3.0': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.2': + '@tailwindcss/oxide-wasm32-wasi@4.3.0': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': optional: true - '@tailwindcss/oxide@4.2.2': + '@tailwindcss/oxide@4.3.0': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-x64': 4.2.2 - '@tailwindcss/oxide-freebsd-x64': 4.2.2 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-x64-musl': 4.2.2 - '@tailwindcss/oxide-wasm32-wasi': 4.2.2 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - - '@tailwindcss/postcss@4.2.2': + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/postcss@4.3.0': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.2.2 - '@tailwindcss/oxide': 4.2.2 - postcss: 8.5.10 - tailwindcss: 4.2.2 + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + postcss: 8.5.15 + tailwindcss: 4.3.0 + + '@tanstack/query-core@5.100.14': {} + + '@tanstack/svelte-query@6.1.33(svelte@5.55.9(@typescript-eslint/types@8.60.0))': + dependencies: + '@tanstack/query-core': 5.100.14 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) - '@testing-library/svelte-core@1.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))': + '@testing-library/svelte-core@1.0.0(svelte@5.55.9(@typescript-eslint/types@8.60.0))': dependencies: - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) - '@trivago/prettier-plugin-sort-imports@6.0.2(prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)))(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2))': + '@trivago/prettier-plugin-sort-imports@6.0.2(prettier-plugin-svelte@4.0.1(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0)))(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0))': dependencies: - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.2 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 javascript-natural-sort: 0.7.1 lodash-es: 4.18.1 minimatch: 9.0.9 parse-imports-exports: 0.2.4 prettier: 3.8.3 optionalDependencies: - prettier-plugin-svelte: 3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)) - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + prettier-plugin-svelte: 4.0.1(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) transitivePeerDependencies: - supports-color '@tsconfig/svelte@5.0.8': {} - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true - '@types/bun@1.3.12': + '@types/bun@1.3.14': dependencies: - bun-types: 1.3.12 + bun-types: 1.3.14 '@types/chai@5.2.3': dependencies: @@ -4155,32 +4554,65 @@ snapshots: '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@types/esrecurse@4.3.1': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} - '@types/node@25.6.0': + '@types/node@25.9.1': dependencies: - undici-types: 7.19.2 + undici-types: 7.24.6 '@types/resolve@1.20.2': {} '@types/trusted-types@2.0.7': {} - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': + '@types/validator@13.15.10': + optional: true + + '@typeschema/class-validator@0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.4)': + dependencies: + '@typeschema/core': 0.14.0(@types/json-schema@7.0.15) + optionalDependencies: + class-validator: 0.14.4 + transitivePeerDependencies: + - '@types/json-schema' + optional: true + + '@typeschema/core@0.14.0(@types/json-schema@7.0.15)': + optionalDependencies: + '@types/json-schema': 7.0.15 + optional: true + + '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/type-utils': 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.59.4 + eslint: 10.4.0(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/eslint-plugin@8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.58.2 - eslint: 10.2.1(jiti@2.6.1) + '@typescript-eslint/parser': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/type-utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.0 + eslint: 10.4.0(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -4188,89 +4620,164 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/parser@8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.59.4 + debug: 4.4.3 + eslint: 10.4.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.0 + debug: 4.4.3 + eslint: 10.4.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.59.4(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3) + '@typescript-eslint/types': 8.59.4 debug: 4.4.3 - eslint: 10.2.1(jiti@2.6.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.2(typescript@6.0.3)': + '@typescript-eslint/project-service@8.60.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.3) - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 debug: 4.4.3 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.2': + '@typescript-eslint/scope-manager@8.59.4': + dependencies: + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/visitor-keys': 8.59.4 + + '@typescript-eslint/scope-manager@8.60.0': + dependencies: + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/visitor-keys': 8.60.0 + + '@typescript-eslint/tsconfig-utils@8.59.4(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + + '@typescript-eslint/tsconfig-utils@8.60.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + typescript: 6.0.3 - '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + debug: 4.4.3 + eslint: 10.4.0(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript-eslint/type-utils@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.4.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.2': {} + '@typescript-eslint/types@8.59.4': {} + + '@typescript-eslint/types@8.60.0': {} + + '@typescript-eslint/typescript-estree@8.59.4(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.59.4(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3) + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/visitor-keys': 8.59.4 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.1 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.60.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.58.2(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.3) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/project-service': 8.60.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/visitor-keys': 8.60.0 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.7.4 + semver: 7.8.1 tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': + '@typescript-eslint/utils@8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) + eslint: 10.4.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - eslint: 10.2.1(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + eslint: 10.4.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.2': + '@typescript-eslint/visitor-keys@8.59.4': dependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.4 eslint-visitor-keys: 5.0.1 - '@unocss/cli@66.6.8': + '@typescript-eslint/visitor-keys@8.60.0': + dependencies: + '@typescript-eslint/types': 8.60.0 + eslint-visitor-keys: 5.0.1 + + '@unocss/cli@66.7.0': dependencies: '@jridgewell/remapping': 2.3.5 - '@unocss/config': 66.6.8 - '@unocss/core': 66.6.8 - '@unocss/preset-wind3': 66.6.8 - '@unocss/preset-wind4': 66.6.8 - '@unocss/transformer-directives': 66.6.8 + '@unocss/config': 66.7.0 + '@unocss/core': 66.7.0 + '@unocss/preset-wind3': 66.7.0 + '@unocss/preset-wind4': 66.7.0 + '@unocss/transformer-directives': 66.7.0 cac: 7.0.0 chokidar: 5.0.0 colorette: 2.0.20 @@ -4281,59 +4788,59 @@ snapshots: tinyglobby: 0.2.16 unplugin-utils: 0.3.1 - '@unocss/config@66.6.8': + '@unocss/config@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 colorette: 2.0.20 consola: 3.4.2 unconfig: 7.5.0 '@unocss/core@0.25.1': {} - '@unocss/core@66.6.8': {} + '@unocss/core@66.7.0': {} - '@unocss/extractor-arbitrary-variants@66.6.8': + '@unocss/extractor-arbitrary-variants@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 - '@unocss/extractor-svelte@66.6.8': {} + '@unocss/extractor-svelte@66.7.0': {} - '@unocss/inspector@66.6.8': + '@unocss/inspector@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/rule-utils': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/rule-utils': 66.7.0 colorette: 2.0.20 gzip-size: 6.0.0 sirv: 3.0.2 - '@unocss/preset-attributify@66.6.8': + '@unocss/preset-attributify@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 - '@unocss/preset-icons@66.6.8': + '@unocss/preset-icons@66.7.0': dependencies: - '@iconify/utils': 3.1.0 - '@unocss/core': 66.6.8 + '@iconify/utils': 3.1.3 + '@unocss/core': 66.7.0 ofetch: 1.5.1 '@unocss/preset-mini@0.25.1': dependencies: '@unocss/core': 0.25.1 - '@unocss/preset-mini@66.6.8': + '@unocss/preset-mini@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/extractor-arbitrary-variants': 66.6.8 - '@unocss/rule-utils': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/extractor-arbitrary-variants': 66.7.0 + '@unocss/rule-utils': 66.7.0 - '@unocss/preset-tagify@66.6.8': + '@unocss/preset-tagify@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 - '@unocss/preset-typography@66.6.8': + '@unocss/preset-typography@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/rule-utils': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/rule-utils': 66.7.0 '@unocss/preset-uno@0.25.1': dependencies: @@ -4341,163 +4848,180 @@ snapshots: '@unocss/preset-mini': 0.25.1 '@unocss/preset-wind': 0.25.1 - '@unocss/preset-uno@66.6.8': + '@unocss/preset-uno@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/preset-wind3': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/preset-wind3': 66.7.0 - '@unocss/preset-web-fonts@66.6.8': + '@unocss/preset-web-fonts@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 ofetch: 1.5.1 - '@unocss/preset-wind3@66.6.8': + '@unocss/preset-wind3@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/preset-mini': 66.6.8 - '@unocss/rule-utils': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/preset-mini': 66.7.0 + '@unocss/rule-utils': 66.7.0 - '@unocss/preset-wind4@66.6.8': + '@unocss/preset-wind4@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/extractor-arbitrary-variants': 66.6.8 - '@unocss/rule-utils': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/extractor-arbitrary-variants': 66.7.0 + '@unocss/rule-utils': 66.7.0 '@unocss/preset-wind@0.25.1': dependencies: '@unocss/core': 0.25.1 '@unocss/preset-mini': 0.25.1 - '@unocss/preset-wind@66.6.8': + '@unocss/preset-wind@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/preset-wind3': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/preset-wind3': 66.7.0 - '@unocss/rule-utils@66.6.8': + '@unocss/rule-utils@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 magic-string: 0.30.21 - '@unocss/transformer-attributify-jsx@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@unocss/transformer-attributify-jsx@66.7.0': dependencies: - '@unocss/core': 66.6.8 - oxc-parser: 0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) - oxc-walker: 0.7.0(oxc-parser@0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' + '@unocss/core': 66.7.0 + oxc-parser: 0.131.0 + oxc-walker: 0.7.0(oxc-parser@0.131.0) - '@unocss/transformer-compile-class@66.6.8': + '@unocss/transformer-compile-class@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 - '@unocss/transformer-directives@66.6.8': + '@unocss/transformer-directives@66.7.0': dependencies: - '@unocss/core': 66.6.8 - '@unocss/rule-utils': 66.6.8 + '@unocss/core': 66.7.0 + '@unocss/rule-utils': 66.7.0 css-tree: 3.2.1 - '@unocss/transformer-variant-group@66.6.8': + '@unocss/transformer-variant-group@66.7.0': dependencies: - '@unocss/core': 66.6.8 + '@unocss/core': 66.7.0 - '@unocss/vite@66.6.8(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))': + '@unocss/vite@66.7.0(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@jridgewell/remapping': 2.3.5 - '@unocss/config': 66.6.8 - '@unocss/core': 66.6.8 - '@unocss/inspector': 66.6.8 + '@unocss/config': 66.7.0 + '@unocss/core': 66.7.0 + '@unocss/inspector': 66.7.0 chokidar: 5.0.0 magic-string: 0.30.21 pathe: 2.0.3 tinyglobby: 0.2.16 unplugin-utils: 0.3.1 - vite: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) + + '@valibot/to-json-schema@1.7.0(valibot@1.4.1(typescript@6.0.3))': + dependencies: + valibot: 1.4.1(typescript@6.0.3) + optional: true + + '@vinejs/compiler@3.0.0': + optional: true + + '@vinejs/vine@3.0.1': + dependencies: + '@poppinss/macroable': 1.1.2 + '@types/validator': 13.15.10 + '@vinejs/compiler': 3.0.0 + camelcase: 8.0.0 + dayjs: 1.11.20 + dlv: 1.1.3 + normalize-url: 8.1.1 + validator: 13.15.35 + optional: true - '@vitest/browser-playwright@4.1.4(playwright@1.59.1)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))(vitest@4.1.4)': + '@vitest/browser-playwright@4.1.7(playwright@1.60.0)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.7)': dependencies: - '@vitest/browser': 4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))(vitest@4.1.4) - '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) - playwright: 1.59.1 + '@vitest/browser': 4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.7) + '@vitest/mocker': 4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + playwright: 1.60.0 tinyrainbow: 3.1.0 - vitest: 4.1.4(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + vitest: 4.1.7(@types/node@25.9.1)(@vitest/browser-playwright@4.1.7)(@vitest/coverage-v8@4.1.7)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))(vitest@4.1.4)': + '@vitest/browser@4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.7)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) - '@vitest/utils': 4.1.4 + '@vitest/mocker': 4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/utils': 4.1.7 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.4(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) - ws: 8.20.0 + vitest: 4.1.7(@types/node@25.9.1)(@vitest/browser-playwright@4.1.7)(@vitest/coverage-v8@4.1.7)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + ws: 8.21.0 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/coverage-v8@4.1.4(@vitest/browser@4.1.4)(vitest@4.1.4)': + '@vitest/coverage-v8@4.1.7(@vitest/browser@4.1.7)(vitest@4.1.7)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.4 - ast-v8-to-istanbul: 1.0.0 + '@vitest/utils': 4.1.7 + ast-v8-to-istanbul: 1.0.2 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 - magicast: 0.5.2 + magicast: 0.5.3 obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.4(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + vitest: 4.1.7(@types/node@25.9.1)(@vitest/browser-playwright@4.1.7)(@vitest/coverage-v8@4.1.7)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) optionalDependencies: - '@vitest/browser': 4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))(vitest@4.1.4) + '@vitest/browser': 4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.7) - '@vitest/expect@4.1.4': + '@vitest/expect@4.1.7': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.4 - '@vitest/utils': 4.1.4 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))': + '@vitest/mocker@4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.4 + '@vitest/spy': 4.1.7 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.4': + '@vitest/pretty-format@4.1.7': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.4': + '@vitest/runner@4.1.7': dependencies: - '@vitest/utils': 4.1.4 + '@vitest/utils': 4.1.7 pathe: 2.0.3 - '@vitest/snapshot@4.1.4': + '@vitest/snapshot@4.1.7': dependencies: - '@vitest/pretty-format': 4.1.4 - '@vitest/utils': 4.1.4 + '@vitest/pretty-format': 4.1.7 + '@vitest/utils': 4.1.7 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.4': {} + '@vitest/spy@4.1.7': {} - '@vitest/utils@4.1.4': + '@vitest/utils@4.1.7': dependencies: - '@vitest/pretty-format': 4.1.4 + '@vitest/pretty-format': 4.1.7 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -4507,17 +5031,17 @@ snapshots: acorn@8.16.0: {} - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.18.0: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -4525,29 +5049,35 @@ snapshots: dependencies: environment: 1.1.0 - ansi-regex@5.0.1: {} - ansi-regex@6.2.2: {} - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - ansi-styles@6.2.3: {} - apexcharts@5.10.6: {} + apexcharts@5.13.0: {} argparse@2.0.1: {} aria-query@5.3.1: {} + arkregex@0.0.5: + dependencies: + '@ark/util': 0.56.0 + optional: true + + arktype@2.2.0: + dependencies: + '@ark/schema': 0.56.0 + '@ark/util': 0.56.0 + arkregex: 0.0.5 + optional: true + array-ify@1.0.0: {} array-timsort@1.0.3: {} assertion-error@2.0.1: {} - ast-v8-to-istanbul@1.0.0: + ast-v8-to-istanbul@1.0.2: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -4561,24 +5091,59 @@ snapshots: before-after-hook@4.0.0: {} + bits-ui@2.18.1(@internationalized/date@3.12.1)(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/dom': 1.7.6 + '@internationalized/date': 3.12.1 + esm-env: 1.2.2 + runed: 0.35.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + svelte-toolbelt: 0.10.6(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + tabbable: 6.4.0 + transitivePeerDependencies: + - '@sveltejs/kit' + bottleneck@2.19.5: {} - brace-expansion@2.1.0: + brace-expansion@2.1.1: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.5: + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 - bun-types@1.3.12: + bun-types@1.3.14: dependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.1 + + bun@1.3.14: + optionalDependencies: + '@oven/bun-darwin-aarch64': 1.3.14 + '@oven/bun-darwin-x64': 1.3.14 + '@oven/bun-darwin-x64-baseline': 1.3.14 + '@oven/bun-freebsd-aarch64': 1.3.14 + '@oven/bun-freebsd-x64': 1.3.14 + '@oven/bun-linux-aarch64': 1.3.14 + '@oven/bun-linux-aarch64-android': 1.3.14 + '@oven/bun-linux-aarch64-musl': 1.3.14 + '@oven/bun-linux-x64': 1.3.14 + '@oven/bun-linux-x64-android': 1.3.14 + '@oven/bun-linux-x64-baseline': 1.3.14 + '@oven/bun-linux-x64-musl': 1.3.14 + '@oven/bun-linux-x64-musl-baseline': 1.3.14 + '@oven/bun-windows-aarch64': 1.3.14 + '@oven/bun-windows-x64': 1.3.14 + '@oven/bun-windows-x64-baseline': 1.3.14 cac@7.0.0: {} callsites@3.1.0: {} + camelcase@8.0.0: + optional: true + chai@6.2.2: {} chalk@5.6.2: {} @@ -4591,6 +5156,13 @@ snapshots: dependencies: readdirp: 5.0.0 + class-validator@0.14.4: + dependencies: + '@types/validator': 13.15.10 + libphonenumber-js: 1.13.3 + validator: 13.15.35 + optional: true + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -4598,22 +5170,16 @@ snapshots: cli-truncate@5.2.0: dependencies: slice-ansi: 8.0.0 - string-width: 8.2.0 + string-width: 8.2.1 - cliui@8.0.1: + cliui@9.0.1: dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 clsx@2.1.1: {} - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - colorette@2.0.20: {} commander@11.1.0: {} @@ -4636,6 +5202,8 @@ snapshots: consola@3.4.2: {} + content-type@2.0.0: {} + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -4665,9 +5233,9 @@ snapshots: cookie@0.6.0: {} - cosmiconfig-typescript-loader@6.3.0(@types/node@25.6.0)(cosmiconfig@9.0.1(typescript@6.0.3))(typescript@6.0.3): + cosmiconfig-typescript-loader@6.3.0(@types/node@25.9.1)(cosmiconfig@9.0.1(typescript@6.0.3))(typescript@6.0.3): dependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.1 cosmiconfig: 9.0.1(typescript@6.0.3) jiti: 2.6.1 typescript: 6.0.3 @@ -4694,7 +5262,10 @@ snapshots: cssesc@3.0.0: {} - date-fns@4.1.0: {} + date-fns@4.3.0: {} + + dayjs@1.11.20: + optional: true debug@4.4.3: dependencies: @@ -4708,11 +5279,16 @@ snapshots: defu@6.1.7: {} + dequal@2.0.3: {} + destr@2.0.5: {} detect-libc@2.1.2: {} - devalue@5.7.1: {} + devalue@5.8.1: {} + + dlv@1.1.3: + optional: true dompurify@3.2.7: optionalDependencies: @@ -4722,16 +5298,22 @@ snapshots: dependencies: is-obj: 2.0.0 + dotenv@17.4.2: {} + duplexer@0.1.2: {} - emoji-regex@10.6.0: {} + effect@3.21.2: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + optional: true - emoji-regex@8.0.0: {} + emoji-regex@10.6.0: {} - enhanced-resolve@5.20.1: + enhanced-resolve@5.22.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.2 + tapable: 2.3.3 env-paths@2.2.1: {} @@ -4743,15 +5325,17 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.0.0: {} + es-module-lexer@2.1.0: {} + + es-toolkit@1.47.0: {} escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.4.0(jiti@2.7.0)): dependencies: - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.4.0(jiti@2.7.0) eslint-formatter-pretty@7.1.0: dependencies: @@ -4761,54 +5345,54 @@ snapshots: eslint-rule-docs: 1.1.235 log-symbols: 7.0.1 plur: 5.1.0 - string-width: 8.2.0 + string-width: 8.2.1 supports-hyperlinks: 4.4.0 - eslint-formatting-reporter@0.0.0(eslint@10.2.1(jiti@2.6.1)): + eslint-formatting-reporter@0.0.0(eslint@10.4.0(jiti@2.7.0)): dependencies: - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.4.0(jiti@2.7.0) prettier-linter-helpers: 1.0.1 eslint-parser-plain@0.1.1: {} - eslint-plugin-format@1.5.0(eslint@10.2.1(jiti@2.6.1)): + eslint-plugin-format@1.5.0(eslint@10.4.0(jiti@2.7.0)): dependencies: '@dprint/formatter': 0.5.1 '@dprint/markdown': 0.21.1 '@dprint/toml': 0.7.0 - eslint: 10.2.1(jiti@2.6.1) - eslint-formatting-reporter: 0.0.0(eslint@10.2.1(jiti@2.6.1)) + eslint: 10.4.0(jiti@2.7.0) + eslint-formatting-reporter: 0.0.0(eslint@10.4.0(jiti@2.7.0)) eslint-parser-plain: 0.1.1 ohash: 2.0.11 oxfmt: 0.35.0 prettier: 3.8.3 synckit: 0.11.12 - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)))(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.4.0(jiti@2.7.0)))(eslint@10.4.0(jiti@2.7.0))(prettier@3.8.3): dependencies: - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.4.0(jiti@2.7.0) prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@10.2.1(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@10.4.0(jiti@2.7.0)) - eslint-plugin-svelte@3.17.0(eslint@10.2.1(jiti@2.6.1))(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + eslint-plugin-svelte@3.17.1(eslint@10.4.0(jiti@2.7.0))(svelte@5.55.9(@typescript-eslint/types@8.60.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.4.0(jiti@2.7.0) esutils: 2.0.3 globals: 16.5.0 known-css-properties: 0.37.0 - postcss: 8.5.10 - postcss-load-config: 3.1.4(postcss@8.5.10) - postcss-safe-parser: 7.0.1(postcss@8.5.10) - semver: 7.7.4 - svelte-eslint-parser: 1.6.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + postcss: 8.5.15 + postcss-load-config: 3.1.4(postcss@8.5.15) + postcss-safe-parser: 7.0.1(postcss@8.5.15) + semver: 7.8.1 + svelte-eslint-parser: 1.6.1(svelte@5.55.9(@typescript-eslint/types@8.60.0)) optionalDependencies: - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) transitivePeerDependencies: - ts-node @@ -4822,7 +5406,7 @@ snapshots: eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -4832,19 +5416,19 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.2.1(jiti@2.6.1): + eslint@10.4.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 - '@eslint/config-helpers': 0.5.5 + '@eslint/config-helpers': 0.6.0 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.1 '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 + '@types/estree': 1.0.9 + ajv: 6.15.0 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 @@ -4865,7 +5449,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -4889,11 +5473,11 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@2.2.5(@typescript-eslint/types@8.58.2): + esrap@2.2.9(@typescript-eslint/types@8.60.0): dependencies: '@jridgewell/sourcemap-codec': 1.5.5 optionalDependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.60.0 esrecurse@4.3.0: dependencies: @@ -4905,7 +5489,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} @@ -4928,6 +5512,11 @@ snapshots: expect-type@1.3.0: {} + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + optional: true + fast-content-type-parse@3.0.0: {} fast-deep-equal@3.1.3: {} @@ -4938,7 +5527,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} + fast-uri@3.1.2: {} fdir@6.5.0(picomatch@4.0.4): optionalDependencies: @@ -4974,23 +5563,23 @@ snapshots: flowbite-datepicker@2.0.0: dependencies: '@rollup/plugin-node-resolve': 15.3.1 - '@tailwindcss/postcss': 4.2.2 + '@tailwindcss/postcss': 4.3.0 transitivePeerDependencies: - rollup - flowbite-svelte@1.33.1(svelte@5.55.4(@typescript-eslint/types@8.58.2))(tailwindcss@4.2.2): + flowbite-svelte@1.33.1(svelte@5.55.9(@typescript-eslint/types@8.60.0))(tailwindcss@4.3.0): dependencies: '@floating-ui/dom': 1.7.6 '@floating-ui/utils': 0.2.11 - apexcharts: 5.10.6 + apexcharts: 5.13.0 clsx: 2.1.1 - date-fns: 4.1.0 + date-fns: 4.3.0 esm-env: 1.2.2 flowbite: 3.1.2 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - tailwind-merge: 3.5.0 - tailwind-variants: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.2) - tailwindcss: 4.2.2 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + tailwind-merge: 3.6.0 + tailwind-variants: 3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.0) + tailwindcss: 4.3.0 transitivePeerDependencies: - rollup @@ -5007,20 +5596,26 @@ snapshots: '@popperjs/core': 2.11.8 flowbite-datepicker: 1.3.2 mini-svg-data-uri: 1.4.4 - postcss: 8.5.10 + postcss: 8.5.15 transitivePeerDependencies: - rollup - flowbite@4.0.1: + flowbite@4.0.2: dependencies: '@popperjs/core': 2.11.8 flowbite-datepicker: 2.0.0 mini-svg-data-uri: 1.4.4 - postcss: 8.5.10 - tailwindcss: 4.2.2 + postcss: 8.5.15 + tailwindcss: 4.3.0 transitivePeerDependencies: - rollup + formsnap@2.0.1(svelte@5.55.9(@typescript-eslint/types@8.60.0))(sveltekit-superforms@2.30.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(@types/json-schema@7.0.15)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)): + dependencies: + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + svelte-toolbelt: 0.5.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + sveltekit-superforms: 2.30.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(@types/json-schema@7.0.15)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3) + fsevents@2.3.2: optional: true @@ -5031,41 +5626,41 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.5.0: {} + get-east-asian-width@1.6.0: {} get-stream@9.0.1: dependencies: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 - git-cliff-darwin-arm64@2.12.0: + git-cliff-darwin-arm64@2.13.1: optional: true - git-cliff-darwin-x64@2.12.0: + git-cliff-darwin-x64@2.13.1: optional: true - git-cliff-linux-arm64@2.12.0: + git-cliff-linux-arm64@2.13.1: optional: true - git-cliff-linux-x64@2.12.0: + git-cliff-linux-x64@2.13.1: optional: true - git-cliff-windows-arm64@2.12.0: + git-cliff-windows-arm64@2.13.1: optional: true - git-cliff-windows-x64@2.12.0: + git-cliff-windows-x64@2.13.1: optional: true - git-cliff@2.12.0: + git-cliff@2.13.1: dependencies: execa: 9.6.1 optionalDependencies: - git-cliff-darwin-arm64: 2.12.0 - git-cliff-darwin-x64: 2.12.0 - git-cliff-linux-arm64: 2.12.0 - git-cliff-linux-x64: 2.12.0 - git-cliff-windows-arm64: 2.12.0 - git-cliff-windows-x64: 2.12.0 + git-cliff-darwin-arm64: 2.13.1 + git-cliff-darwin-x64: 2.13.1 + git-cliff-linux-arm64: 2.13.1 + git-cliff-linux-x64: 2.13.1 + git-cliff-windows-arm64: 2.13.1 + git-cliff-windows-x64: 2.13.1 git-raw-commits@5.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.4.0): dependencies: @@ -5079,13 +5674,13 @@ snapshots: dependencies: is-glob: 4.0.3 - global-directory@4.0.1: + global-directory@5.0.0: dependencies: - ini: 4.1.1 + ini: 6.0.0 globals@16.5.0: {} - globals@17.5.0: {} + globals@17.6.0: {} graceful-fs@4.2.11: {} @@ -5127,23 +5722,23 @@ snapshots: imurmurhash@0.1.4: {} - ini@4.1.1: {} + ini@6.0.0: {} + + inline-style-parser@0.2.7: {} irregular-plurals@3.5.0: {} is-arrayish@0.2.1: {} - is-core-module@2.16.1: + is-core-module@2.16.2: dependencies: hasown: 2.0.3 is-extglob@2.1.1: {} - is-fullwidth-code-point@3.0.0: {} - is-fullwidth-code-point@5.1.0: dependencies: - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 is-glob@4.0.3: dependencies: @@ -5157,7 +5752,7 @@ snapshots: is-reference@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 is-stream@4.0.1: {} @@ -5182,6 +5777,17 @@ snapshots: jiti@2.6.1: {} + jiti@2.7.0: {} + + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + optional: true + js-sha256@0.11.1: {} js-tokens@10.0.0: {} @@ -5198,6 +5804,12 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + optional: true + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -5216,13 +5828,16 @@ snapshots: known-css-properties@0.37.0: {} - kysely@0.28.16: {} + kysely@0.28.17: {} levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.13.3: + optional: true + lightningcss-android-arm64@1.32.0: optional: true @@ -5276,23 +5891,22 @@ snapshots: lines-and-columns@1.2.4: {} - lint-staged@16.4.0: + lint-staged@17.0.5: dependencies: - commander: 14.0.3 - listr2: 9.0.5 + listr2: 10.2.1 picomatch: 4.0.4 string-argv: 0.3.2 - tinyexec: 1.1.1 - yaml: 2.8.3 + tinyexec: 1.2.2 + optionalDependencies: + yaml: 2.9.0 - listr2@9.0.5: + listr2@10.2.1: dependencies: cli-truncate: 5.2.0 - colorette: 2.0.20 eventemitter3: 5.0.4 log-update: 6.1.0 rfdc: 1.4.1 - wrap-ansi: 9.0.2 + wrap-ansi: 10.0.0 locate-character@3.0.0: {} @@ -5302,18 +5916,6 @@ snapshots: lodash-es@4.18.1: {} - lodash.camelcase@4.3.0: {} - - lodash.kebabcase@4.1.1: {} - - lodash.mergewith@4.6.2: {} - - lodash.snakecase@4.1.1: {} - - lodash.startcase@4.4.0: {} - - lodash.upperfirst@4.3.1: {} - log-symbols@7.0.1: dependencies: is-unicode-supported: 2.1.0 @@ -5327,6 +5929,8 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 + lz-string@1.5.0: {} + magic-regexp@0.10.0: dependencies: estree-walker: 3.0.3 @@ -5334,27 +5938,29 @@ snapshots: mlly: 1.8.2 regexp-tree: 0.1.27 type-level-regexp: 0.1.17 - ufo: 1.6.3 + ufo: 1.6.4 unplugin: 2.3.11 magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - magicast@0.5.2: + magicast@0.5.3: dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 source-map-js: 1.2.1 make-dir@4.0.0: dependencies: - semver: 7.7.4 + semver: 7.8.1 marked@14.0.0: {} mdn-data@2.27.1: {} + memoize-weak@1.0.2: {} + meow@13.2.0: {} mimic-function@5.0.1: {} @@ -5363,20 +5969,24 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.6 minimatch@9.0.9: dependencies: - brace-expansion: 2.1.0 - - minimist@1.2.8: {} + brace-expansion: 2.1.1 mlly@1.8.2: dependencies: acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.3 + ufo: 1.6.4 + + mode-watcher@1.1.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + runed: 0.25.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + svelte-toolbelt: 0.7.1(svelte@5.55.9(@typescript-eslint/types@8.60.0)) monaco-editor@0.55.1: dependencies: @@ -5389,12 +5999,15 @@ snapshots: ms@2.1.3: {} - nanoid@3.3.11: {} + nanoid@3.3.12: {} natural-compare@1.4.0: {} node-fetch-native@1.6.7: {} + normalize-url@8.1.1: + optional: true + npm-run-path@6.0.0: dependencies: path-key: 4.0.0 @@ -5406,7 +6019,7 @@ snapshots: dependencies: destr: 2.0.5 node-fetch-native: 1.6.7 - ufo: 1.6.3 + ufo: 1.6.4 ohash@2.0.11: {} @@ -5423,38 +6036,35 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - oxc-parser@0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + oxc-parser@0.131.0: dependencies: - '@oxc-project/types': 0.124.0 + '@oxc-project/types': 0.131.0 optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.124.0 - '@oxc-parser/binding-android-arm64': 0.124.0 - '@oxc-parser/binding-darwin-arm64': 0.124.0 - '@oxc-parser/binding-darwin-x64': 0.124.0 - '@oxc-parser/binding-freebsd-x64': 0.124.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.124.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.124.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.124.0 - '@oxc-parser/binding-linux-arm64-musl': 0.124.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.124.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.124.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.124.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.124.0 - '@oxc-parser/binding-linux-x64-gnu': 0.124.0 - '@oxc-parser/binding-linux-x64-musl': 0.124.0 - '@oxc-parser/binding-openharmony-arm64': 0.124.0 - '@oxc-parser/binding-wasm32-wasi': 0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) - '@oxc-parser/binding-win32-arm64-msvc': 0.124.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.124.0 - '@oxc-parser/binding-win32-x64-msvc': 0.124.0 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - oxc-walker@0.7.0(oxc-parser@0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)): + '@oxc-parser/binding-android-arm-eabi': 0.131.0 + '@oxc-parser/binding-android-arm64': 0.131.0 + '@oxc-parser/binding-darwin-arm64': 0.131.0 + '@oxc-parser/binding-darwin-x64': 0.131.0 + '@oxc-parser/binding-freebsd-x64': 0.131.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.131.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.131.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.131.0 + '@oxc-parser/binding-linux-arm64-musl': 0.131.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.131.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.131.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.131.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.131.0 + '@oxc-parser/binding-linux-x64-gnu': 0.131.0 + '@oxc-parser/binding-linux-x64-musl': 0.131.0 + '@oxc-parser/binding-openharmony-arm64': 0.131.0 + '@oxc-parser/binding-wasm32-wasi': 0.131.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.131.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.131.0 + '@oxc-parser/binding-win32-x64-msvc': 0.131.0 + + oxc-walker@0.7.0(oxc-parser@0.131.0): dependencies: magic-regexp: 0.10.0 - oxc-parser: 0.124.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + oxc-parser: 0.131.0 oxfmt@0.35.0: dependencies: @@ -5500,7 +6110,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -5531,11 +6141,11 @@ snapshots: mlly: 1.8.2 pathe: 2.0.3 - playwright-core@1.59.1: {} + playwright-core@1.60.0: {} - playwright@1.59.1: + playwright@1.60.0: dependencies: - playwright-core: 1.59.1 + playwright-core: 1.60.0 optionalDependencies: fsevents: 2.3.2 @@ -5545,29 +6155,29 @@ snapshots: pngjs@7.0.0: {} - postcss-load-config@3.1.4(postcss@8.5.10): + postcss-load-config@3.1.4(postcss@8.5.15): dependencies: lilconfig: 2.1.0 yaml: 1.10.3 optionalDependencies: - postcss: 8.5.10 + postcss: 8.5.15 - postcss-safe-parser@7.0.1(postcss@8.5.10): + postcss-safe-parser@7.0.1(postcss@8.5.15): dependencies: - postcss: 8.5.10 + postcss: 8.5.15 - postcss-scss@4.0.9(postcss@8.5.10): + postcss-scss@4.0.9(postcss@8.5.15): dependencies: - postcss: 8.5.10 + postcss: 8.5.15 postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.5.10: + postcss@8.5.15: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -5577,10 +6187,10 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + prettier-plugin-svelte@4.0.1(prettier@3.8.3)(svelte@5.55.9(@typescript-eslint/types@8.60.0)): dependencies: prettier: 3.8.3 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) prettier@2.5.1: {} @@ -5590,8 +6200,14 @@ snapshots: dependencies: parse-ms: 4.0.0 + property-expr@2.0.6: + optional: true + punycode@2.3.1: {} + pure-rand@6.1.0: + optional: true + quansync@1.0.0: {} readdirp@4.1.2: {} @@ -5600,8 +6216,6 @@ snapshots: regexp-tree@0.1.27: {} - require-directory@2.1.1: {} - require-from-string@2.0.2: {} resolve-from@4.0.0: {} @@ -5611,7 +6225,7 @@ snapshots: resolve@1.22.12: dependencies: es-errors: 1.3.0 - is-core-module: 2.16.1 + is-core-module: 2.16.2 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -5622,58 +6236,56 @@ snapshots: rfdc@1.4.1: {} - rolldown@1.0.0-rc.15: + rolldown@1.0.2: dependencies: - '@oxc-project/types': 0.124.0 - '@rolldown/pluginutils': 1.0.0-rc.15 + '@oxc-project/types': 0.132.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-x64': 1.0.0-rc.15 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 - - rolldown@1.0.0-rc.16: - dependencies: - '@oxc-project/types': 0.126.0 - '@rolldown/pluginutils': 1.0.0-rc.16 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.16 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.16 - '@rolldown/binding-darwin-x64': 1.0.0-rc.16 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.16 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.16 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.16 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.16 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.16 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.16 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.16 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.16 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.16 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.16 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.16 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.16 - - runed@0.28.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + '@rolldown/binding-android-arm64': 1.0.2 + '@rolldown/binding-darwin-arm64': 1.0.2 + '@rolldown/binding-darwin-x64': 1.0.2 + '@rolldown/binding-freebsd-x64': 1.0.2 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 + '@rolldown/binding-linux-arm64-gnu': 1.0.2 + '@rolldown/binding-linux-arm64-musl': 1.0.2 + '@rolldown/binding-linux-ppc64-gnu': 1.0.2 + '@rolldown/binding-linux-s390x-gnu': 1.0.2 + '@rolldown/binding-linux-x64-gnu': 1.0.2 + '@rolldown/binding-linux-x64-musl': 1.0.2 + '@rolldown/binding-openharmony-arm64': 1.0.2 + '@rolldown/binding-wasm32-wasi': 1.0.2 + '@rolldown/binding-win32-arm64-msvc': 1.0.2 + '@rolldown/binding-win32-x64-msvc': 1.0.2 + + runed@0.23.4(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + esm-env: 1.2.2 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + + runed@0.25.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + esm-env: 1.2.2 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + + runed@0.28.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + esm-env: 1.2.2 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + + runed@0.35.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)): dependencies: + dequal: 2.0.3 esm-env: 1.2.2 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + lz-string: 1.5.0 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + optionalDependencies: + '@sveltejs/kit': 2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) sade@1.8.1: dependencies: mri: 1.2.0 - semver@7.7.4: {} + semver@7.8.1: {} set-cookie-parser@3.1.0: {} @@ -5707,10 +6319,10 @@ snapshots: source-map-js@1.2.1: {} - sqlite-wasm-kysely@0.3.0(kysely@0.28.16): + sqlite-wasm-kysely@0.3.0(kysely@0.28.17): dependencies: '@sqlite.org/sqlite-wasm': 3.48.0-build4 - kysely: 0.28.16 + kysely: 0.28.17 stackback@0.0.2: {} @@ -5718,33 +6330,30 @@ snapshots: string-argv@0.3.2: {} - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 - string-width@8.2.0: + string-width@8.2.1: dependencies: - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 strip-final-newline@4.0.0: {} + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + superstruct@2.0.2: + optional: true + supports-color@10.2.2: {} supports-color@7.2.0: @@ -5758,61 +6367,83 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-adapter-bun@1.0.1(@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(typescript@6.0.3): + svelte-adapter-bun@1.0.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(typescript@6.0.3): dependencies: - '@sveltejs/kit': 2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) - rolldown: 1.0.0-rc.16 + '@sveltejs/kit': 2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + rolldown: 1.0.2 typescript: 6.0.3 - svelte-check@4.4.6(picomatch@4.0.4)(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3): + svelte-check@4.4.8(picomatch@4.0.4)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 chokidar: 4.0.3 fdir: 6.5.0(picomatch@4.0.4) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) typescript: 6.0.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.6.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + svelte-eslint-parser@1.6.1(svelte@5.55.9(@typescript-eslint/types@8.60.0)): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - postcss: 8.5.10 - postcss-scss: 4.0.9(postcss@8.5.10) + postcss: 8.5.15 + postcss-scss: 4.0.9(postcss@8.5.15) postcss-selector-parser: 7.1.1 - semver: 7.7.4 + semver: 7.8.1 optionalDependencies: - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) - svelte-kit-sessions@0.4.0(@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + svelte-kit-sessions@0.4.0(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)): dependencies: '@isaacs/ttlcache': 1.4.1 - '@sveltejs/kit': 2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + '@sveltejs/kit': 2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + + svelte-sonner@1.1.1(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + runed: 0.28.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + + svelte-toolbelt@0.10.6(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + clsx: 2.1.1 + runed: 0.35.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + style-to-object: 1.0.14 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + transitivePeerDependencies: + - '@sveltejs/kit' + + svelte-toolbelt@0.5.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)): + dependencies: + clsx: 2.1.1 + style-to-object: 1.0.14 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) - svelte-sonner@1.1.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + svelte-toolbelt@0.7.1(svelte@5.55.9(@typescript-eslint/types@8.60.0)): dependencies: - runed: 0.28.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)) - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + clsx: 2.1.1 + runed: 0.23.4(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + style-to-object: 1.0.14 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) - svelte@5.55.4(@typescript-eslint/types@8.58.2): + svelte@5.55.9(@typescript-eslint/types@8.60.0): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 - '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@types/estree': 1.0.8 + '@sveltejs/acorn-typescript': 1.0.10(acorn@8.16.0) + '@types/estree': 1.0.9 '@types/trusted-types': 2.0.7 acorn: 8.16.0 aria-query: 5.3.1 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.7.1 + devalue: 5.8.1 esm-env: 1.2.2 - esrap: 2.2.5(@typescript-eslint/types@8.58.2) + esrap: 2.2.9(@typescript-eslint/types@8.60.0) is-reference: 3.0.3 locate-character: 3.0.0 magic-string: 0.30.21 @@ -5820,25 +6451,58 @@ snapshots: transitivePeerDependencies: - '@typescript-eslint/types' + sveltekit-superforms@2.30.1(@sveltejs/kit@2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(@types/json-schema@7.0.15)(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3): + dependencies: + '@sveltejs/kit': 2.61.1(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.55.9(@typescript-eslint/types@8.60.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + devalue: 5.8.1 + memoize-weak: 1.0.2 + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + ts-deepmerge: 7.0.3 + optionalDependencies: + '@exodus/schemasafe': 1.3.0 + '@standard-schema/spec': 1.1.0 + '@typeschema/class-validator': 0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.4) + '@valibot/to-json-schema': 1.7.0(valibot@1.4.1(typescript@6.0.3)) + '@vinejs/vine': 3.0.1 + arktype: 2.2.0 + class-validator: 0.14.4 + effect: 3.21.2 + joi: 17.13.3 + json-schema-to-ts: 3.1.1 + superstruct: 2.0.2 + typebox: 1.1.38 + valibot: 1.4.1(typescript@6.0.3) + yup: 1.7.1 + zod: 4.4.3 + zod-v3-to-json-schema: 4.0.0(zod@4.4.3) + transitivePeerDependencies: + - '@types/json-schema' + - typescript + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 - tailwind-merge@3.5.0: {} + tabbable@6.4.0: {} + + tailwind-merge@3.6.0: {} - tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.2): + tailwind-variants@3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.0): dependencies: - tailwindcss: 4.2.2 + tailwindcss: 4.3.0 optionalDependencies: - tailwind-merge: 3.5.0 + tailwind-merge: 3.6.0 - tailwindcss@4.2.2: {} + tailwindcss@4.3.0: {} - tapable@2.3.2: {} + tapable@2.3.3: {} + + tiny-case@1.0.3: + optional: true tinybench@2.9.0: {} - tinyexec@1.1.1: {} + tinyexec@1.2.2: {} tinyglobby@0.2.16: dependencies: @@ -5849,14 +6513,21 @@ snapshots: tinyrainbow@3.1.0: {} + toposort@2.0.2: + optional: true + totalist@3.0.1: {} + ts-algebra@2.0.0: + optional: true + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: typescript: 6.0.3 - tslib@2.8.1: - optional: true + ts-deepmerge@7.0.3: {} + + tslib@2.8.1: {} tunnel@0.0.6: {} @@ -5864,22 +6535,39 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@2.19.0: + optional: true + type-level-regexp@0.1.17: {} - typescript-eslint@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3): + typebox@1.1.38: + optional: true + + typescript-eslint@8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.59.4(@typescript-eslint/parser@8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.4(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + typescript-eslint@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/parser': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - eslint: 10.2.1(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color typescript@6.0.3: {} - ufo@1.6.3: {} + ufo@1.6.4: {} unconfig-core@7.5.0: dependencies: @@ -5890,11 +6578,11 @@ snapshots: dependencies: '@quansync/fs': 1.0.0 defu: 6.1.7 - jiti: 2.6.1 + jiti: 2.7.0 quansync: 1.0.0 unconfig-core: 7.5.0 - undici-types@7.19.2: {} + undici-types@7.24.6: {} undici@6.25.0: {} @@ -5902,28 +6590,26 @@ snapshots: universal-user-agent@7.0.3: {} - unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)): - dependencies: - '@unocss/cli': 66.6.8 - '@unocss/core': 66.6.8 - '@unocss/preset-attributify': 66.6.8 - '@unocss/preset-icons': 66.6.8 - '@unocss/preset-mini': 66.6.8 - '@unocss/preset-tagify': 66.6.8 - '@unocss/preset-typography': 66.6.8 - '@unocss/preset-uno': 66.6.8 - '@unocss/preset-web-fonts': 66.6.8 - '@unocss/preset-wind': 66.6.8 - '@unocss/preset-wind3': 66.6.8 - '@unocss/preset-wind4': 66.6.8 - '@unocss/transformer-attributify-jsx': 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) - '@unocss/transformer-compile-class': 66.6.8 - '@unocss/transformer-directives': 66.6.8 - '@unocss/transformer-variant-group': 66.6.8 - '@unocss/vite': 66.6.8(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + unocss@66.7.0(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)): + dependencies: + '@unocss/cli': 66.7.0 + '@unocss/core': 66.7.0 + '@unocss/preset-attributify': 66.7.0 + '@unocss/preset-icons': 66.7.0 + '@unocss/preset-mini': 66.7.0 + '@unocss/preset-tagify': 66.7.0 + '@unocss/preset-typography': 66.7.0 + '@unocss/preset-uno': 66.7.0 + '@unocss/preset-web-fonts': 66.7.0 + '@unocss/preset-wind': 66.7.0 + '@unocss/preset-wind3': 66.7.0 + '@unocss/preset-wind4': 66.7.0 + '@unocss/transformer-attributify-jsx': 66.7.0 + '@unocss/transformer-compile-class': 66.7.0 + '@unocss/transformer-directives': 66.7.0 + '@unocss/transformer-variant-group': 66.7.0 + '@unocss/vite': 66.7.0(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - vite unplugin-utils@0.3.1: @@ -5946,43 +6632,49 @@ snapshots: util-deprecate@1.0.2: {} - uuid@10.0.0: {} + uuid@14.0.0: {} + + valibot@1.4.1(typescript@6.0.3): + optionalDependencies: + typescript: 6.0.3 + optional: true - uuid@13.0.0: {} + validator@13.15.35: + optional: true - vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3): + vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 - rolldown: 1.0.0-rc.15 + postcss: 8.5.15 + rolldown: 1.0.2 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.1 fsevents: 2.3.3 - jiti: 2.6.1 - yaml: 2.8.3 + jiti: 2.7.0 + yaml: 2.9.0 - vitefu@1.1.3(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)): + vitefu@1.1.3(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)): optionalDependencies: - vite: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) - vitest-browser-svelte@2.1.1(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vitest@4.1.4): + vitest-browser-svelte@2.1.1(svelte@5.55.9(@typescript-eslint/types@8.60.0))(vitest@4.1.7): dependencies: - '@testing-library/svelte-core': 1.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2)) - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - vitest: 4.1.4(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) + '@testing-library/svelte-core': 1.0.0(svelte@5.55.9(@typescript-eslint/types@8.60.0)) + svelte: 5.55.9(@typescript-eslint/types@8.60.0) + vitest: 4.1.7(@types/node@25.9.1)(@vitest/browser-playwright@4.1.7)(@vitest/coverage-v8@4.1.7)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) - vitest@4.1.4(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)): + vitest@4.1.7(@types/node@25.9.1)(@vitest/browser-playwright@4.1.7)(@vitest/coverage-v8@4.1.7)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.4 - '@vitest/runner': 4.1.4 - '@vitest/snapshot': 4.1.4 - '@vitest/spy': 4.1.4 - '@vitest/utils': 4.1.4 - es-module-lexer: 2.0.0 + '@vitest/expect': 4.1.7 + '@vitest/mocker': 4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.7 + '@vitest/runner': 4.1.7 + '@vitest/snapshot': 4.1.7 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 @@ -5990,15 +6682,15 @@ snapshots: picomatch: 4.0.4 std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.1.1 + tinyexec: 1.2.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.6.0 - '@vitest/browser-playwright': 4.1.4(playwright@1.59.1)(vite@8.0.8(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.3))(vitest@4.1.4) - '@vitest/coverage-v8': 4.1.4(@vitest/browser@4.1.4)(vitest@4.1.4) + '@types/node': 25.9.1 + '@vitest/browser-playwright': 4.1.7(playwright@1.60.0)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.7) + '@vitest/coverage-v8': 4.1.7(@vitest/browser@4.1.7)(vitest@4.1.7) transitivePeerDependencies: - msw @@ -6015,11 +6707,11 @@ snapshots: word-wrap@1.2.5: {} - wrap-ansi@7.0.0: + wrap-ansi@10.0.0: dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 + ansi-styles: 6.2.3 + string-width: 8.2.1 + strip-ansi: 7.2.0 wrap-ansi@9.0.2: dependencies: @@ -6027,28 +6719,43 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 - ws@8.20.0: {} + ws@8.21.0: {} y18n@5.0.8: {} yaml@1.10.3: {} - yaml@2.8.3: {} + yaml@2.9.0: + optional: true - yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} - yargs@17.7.2: + yargs@18.0.0: dependencies: - cliui: 8.0.1 + cliui: 9.0.1 escalade: 3.2.0 get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 + string-width: 7.2.0 y18n: 5.0.8 - yargs-parser: 21.1.1 + yargs-parser: 22.0.0 yocto-queue@0.1.0: {} yoctocolors@2.1.2: {} + yup@1.7.1: + dependencies: + property-expr: 2.0.6 + tiny-case: 1.0.3 + toposort: 2.0.2 + type-fest: 2.19.0 + optional: true + zimmerframe@1.1.4: {} + + zod-v3-to-json-schema@4.0.0(zod@4.4.3): + dependencies: + zod: 4.4.3 + optional: true + + zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 57782b5..9fb5654 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,60 +1,98 @@ +allowBuilds: + bun: true + catalogs: build: '@tsconfig/svelte': ^5.0.8 'svelte-adapter-bun': ^1.0.1 - typescript: ^6.0.2 + typescript: ^6.0.3 ci: - '@commitlint/cli': ^20.5.0 - '@commitlint/config-conventional': ^20.5.0 + '@commitlint/cli': ^21.0.1 + '@commitlint/config-conventional': ^21.0.1 '@favware/cliff-jumper': ^6.1.0 - '@nanoforge-dev/actions': ^1.2.3 + '@nanoforge-dev/actions': ^2.0.0 husky: ^9.1.7 - lint-staged: ^16.4.0 + lint-staged: ^17.0.5 components: - flowbite: ^4.0.1 + bits-ui: ^2.18.1 + flowbite: ^4.0.2 flowbite-svelte: ^1.33.1 monaco-editor: ^0.55.1 - svelte-sonner: ^1.1.0 + svelte-sonner: ^1.1.1 core: - '@nanoforge-dev/ecs-lib': ^1.1.2 + '@nanoforge-dev/ecs-lib': ^1.3.0 '@sveltejs/adapter-auto': ^7.0.1 - '@sveltejs/kit': ^2.57.1 - '@sveltejs/vite-plugin-svelte': ^7.0.0 - '@types/bun': ^1.3.12 - svelte: ^5.55.3 - svelte-check: ^4.4.6 - svelte-kit-sessions: "^0.4.0" - vite: ^8.0.8 + '@sveltejs/kit': ^2.61.1 + '@sveltejs/vite-plugin-svelte': ^7.1.2 + '@types/bun': ^1.3.14 + bun: ^1.3.14 + svelte: ^5.55.9 + svelte-check: ^4.4.8 + svelte-kit-sessions: ^0.4.0 + vite: ^8.0.14 css: '@alexanderniebuhr/prettier-plugin-unocss': ^0.0.4 - '@unocss/extractor-svelte': ^66.6.8 - '@unocss/preset-icons': ^66.6.8 - '@unocss/preset-web-fonts': ^66.6.8 - '@unocss/preset-wind4': ^66.6.8 - unocss: ^66.6.8 + '@unocss/extractor-svelte': ^66.7.0 + '@unocss/preset-icons': ^66.7.0 + '@unocss/preset-web-fonts': ^66.7.0 + '@unocss/preset-wind4': ^66.7.0 + clsx: ^2.1.1 + tailwind-merge: ^3.6.0 + tailwind-variants: ^3.2.2 + tailwindcss: ^4.3.0 + unocss: ^66.7.0 i18n: - '@inlang/paraglide-js': ^2.15.3 + '@inlang/paraglide-js': ^2.18.1 icons: '@iconify-json/ic': ^1.2.4 - '@iconify-json/material-icon-theme': ^1.2.58 + '@iconify-json/material-icon-theme': ^1.2.66 '@iconify-json/solar': ^1.2.5 + '@lucide/svelte': ^1.16.0 + libs-back: + dotenv: ^17.4.2 + libs-front: + '@internationalized/date': ^3.12.1 + '@tanstack/svelte-query': ^6.1.33 + formsnap: ^2.0.1 + mode-watcher: ^1.1.0 + svelte-sonner: ^1.1.1 + sveltekit-superforms: ^2.30.1 + zod: ^4.4.3 lint: '@nanoforge-dev/utils-eslint-config': ^1.0.2 '@nanoforge-dev/utils-prettier-config': ^1.0.2 '@trivago/prettier-plugin-sort-imports': ^6.0.2 - eslint: ^10.2.0 - eslint-plugin-svelte: ^3.17.0 - globals: ^17.5.0 - prettier: ^3.8.2 - prettier-plugin-svelte: ^3.5.1 - typescript-eslint: ^8.58.2 + eslint: ^10.4.0 + eslint-plugin-svelte: ^3.17.1 + globals: ^17.6.0 + prettier: ^3.8.3 + prettier-plugin-svelte: ^4.0.1 + typescript-eslint: ^8.60.0 test: - '@playwright/test': ^1.59.1 - '@vitest/browser-playwright': ^4.1.4 - '@vitest/coverage-v8': ^4.1.4 - playwright: ^1.59.1 - vitest: ^4.1.4 + '@playwright/test': ^1.60.0 + '@vitest/browser-playwright': ^4.1.7 + '@vitest/coverage-v8': ^4.1.7 + playwright: ^1.60.0 + vitest: ^4.1.7 vitest-browser-svelte: ^2.1.1 +minimumReleaseAgeExclude: + - '@iconify-json/material-icon-theme@1.2.66' + - '@nanoforge-dev/actions@2.0.0' + - '@nanoforge-dev/common@1.3.0' + - '@nanoforge-dev/ecs-lib@1.3.0' + - '@typescript-eslint/eslint-plugin@8.60.0' + - '@typescript-eslint/parser@8.60.0' + - '@typescript-eslint/project-service@8.60.0' + - '@typescript-eslint/scope-manager@8.60.0' + - '@typescript-eslint/tsconfig-utils@8.60.0' + - '@typescript-eslint/type-utils@8.60.0' + - '@typescript-eslint/types@8.60.0' + - '@typescript-eslint/typescript-estree@8.60.0' + - '@typescript-eslint/utils@8.60.0' + - '@typescript-eslint/visitor-keys@8.60.0' + - typescript-eslint@8.60.0 + onlyBuiltDependencies: + - bun - esbuild diff --git a/public/assets/fonts/dmmono-612bc94f.woff2 b/public/assets/fonts/dmmono-612bc94f.woff2 deleted file mode 100644 index 80a82cb..0000000 Binary files a/public/assets/fonts/dmmono-612bc94f.woff2 and /dev/null differ diff --git a/public/assets/fonts/dmmono-cbe07c46.woff2 b/public/assets/fonts/dmmono-cbe07c46.woff2 deleted file mode 100644 index d1985ac..0000000 Binary files a/public/assets/fonts/dmmono-cbe07c46.woff2 and /dev/null differ diff --git a/public/assets/fonts/dmsans-2fb93aaf.woff2 b/public/assets/fonts/dmsans-2fb93aaf.woff2 deleted file mode 100644 index f966e16..0000000 Binary files a/public/assets/fonts/dmsans-2fb93aaf.woff2 and /dev/null differ diff --git a/public/assets/fonts/dmsans-dbe1f17c.woff2 b/public/assets/fonts/dmsans-dbe1f17c.woff2 deleted file mode 100644 index 1697494..0000000 Binary files a/public/assets/fonts/dmsans-dbe1f17c.woff2 and /dev/null differ diff --git a/public/assets/fonts/dmserifdisplay-aca0e217.woff2 b/public/assets/fonts/dmserifdisplay-aca0e217.woff2 deleted file mode 100644 index ff6b054..0000000 Binary files a/public/assets/fonts/dmserifdisplay-aca0e217.woff2 and /dev/null differ diff --git a/public/assets/fonts/dmserifdisplay-cbc631ca.woff2 b/public/assets/fonts/dmserifdisplay-cbc631ca.woff2 deleted file mode 100644 index fdd125d..0000000 Binary files a/public/assets/fonts/dmserifdisplay-cbc631ca.woff2 and /dev/null differ diff --git a/static/favicon.svg b/public/favicon.svg similarity index 100% rename from static/favicon.svg rename to public/favicon.svg diff --git a/static/robots.txt b/public/robots.txt similarity index 100% rename from static/robots.txt rename to public/robots.txt diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app.css b/src/app.css index 3131c5a..8c7e6e2 100644 --- a/src/app.css +++ b/src/app.css @@ -10,8 +10,77 @@ } } +/* White theme */ +/*:root {*/ +/* --background: 0.9851 0 0;*/ +/* --foreground: 0.2046 0 0;*/ + +/* --border: 0.9288 0.0126 255.51;*/ +/* --input: 0.9683 0.0069 247.9;*/ +/* --ring: 0.4493 0.1953 294.69;*/ + +/* --card: 1 0 0;*/ +/* --card-foreground: 0.2046 0 0;*/ + +/* --popover: 1 0 0;*/ +/* --popover-foreground: 0.2046 0 0;*/ + +/* --primary: 0.4493 0.1953 294.69;*/ +/* --primary-foreground: 0.9842 0.0034 247.86;*/ + +/* --secondary: 0.9683 0.0069 247.9;*/ +/* --secondary-foreground: 0.2077 0.0398 265.75;*/ + +/* --muted: 0.9683 0.0069 247.9;*/ +/* --muted-foreground: 0.5544 0.0407 257.42;*/ + +/* --accent: 0.4493 0.1953 294.69;*/ +/* --accent-foreground: 0.9842 0.0034 247.86;*/ + +/* --destructive: 0.6368 0.2078 25.33;*/ +/* --destructive-foreground: 0.9842 0.0034 247.86;*/ +/*}*/ + +/* Dark theme */ +/*.dark {*/ :root { + --background: 0.115 0 89.876; + --foreground: 0.9461 0 0; + + --border: 0.264 0 89.876; + --input: 0.244 0 89.876; + --ring: 0.4493 0.1953 294.69; + + --card: 0.1683 0 0; + --card-foreground: 0.9461 0 0; + + --popover: 0.115 0 89.876; + --popover-foreground: 0.9461 0 0; + + --primary: 0.4493 0.1953 294.69; + --primary-foreground: 0.9461 0 0; + + --secondary: 0.244 0 89.876; + --secondary-foreground: 0.9461 0 0; + + --muted: 0.205 0 89.876; + --muted-foreground: 0.7107 0.0351 256.79; + + --accent: 0.4493 0.1953 294.69; + --accent-foreground: 0.9461 0 0; + + --success: 0.4546 0.1348 141.88; + --success-foreground: 0.9461 0 0; + + --destructive: 0.3958 0.1331 25.72; + --destructive-foreground: 0.9461 0 0; +} + +body { + background: oklch(var(--background)); + color: oklch(var(--foreground)); font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; font-weight: 400; @@ -19,8 +88,6 @@ text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - - @apply color-neutral-200 bg-neutral-900; } html { @@ -41,3 +108,21 @@ html::-webkit-scrollbar-thumb { background: #52525b; border-radius: 9999px; } + +@keyframes enter { + from { + opacity: var(--un-enter-opacity, 1); + transform: translate3d(var(--un-enter-translate-x, 0), var(--un-enter-translate-y, 0), 0) + scale3d(var(--un-enter-scale, 1), var(--un-enter-scale, 1), var(--un-enter-scale, 1)) + rotate(var(--un-enter-rotate, 0)); + } +} + +@keyframes exit { + to { + opacity: var(--un-exit-opacity, 1); + transform: translate3d(var(--un-exit-translate-x, 0), var(--un-exit-translate-y, 0), 0) + scale3d(var(--un-exit-scale, 1), var(--un-exit-scale, 1), var(--un-exit-scale, 1)) + rotate(var(--un-exit-rotate, 0)); + } +} diff --git a/src/app.d.ts b/src/app.d.ts index ba56e29..85e7cdf 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,7 +1,5 @@ // See https://svelte.dev/docs/kit/types#app.d.ts // for information about these interfaces -import child_process from 'node:child_process'; - declare global { namespace App { // interface Error {} @@ -14,8 +12,7 @@ declare global { declare module 'svelte-kit-sessions' { interface SessionData { - path: string; - projectPid?: number; + id: string; } } diff --git a/src/demo.spec.ts b/src/demo.spec.ts new file mode 100644 index 0000000..e2efa47 --- /dev/null +++ b/src/demo.spec.ts @@ -0,0 +1,5 @@ +import { expect, it } from 'vitest'; + +it('expect 1 + 2 = 3', async () => { + expect(1 + 2).equal(3); +}); diff --git a/src/hooks.server.ts b/src/hooks.server.ts index dcbf401..2b5b4b4 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,31 +1,8 @@ -import { type Handle, redirect } from '@sveltejs/kit'; +import { type Handle } from '@sveltejs/kit'; import { sequence } from '@sveltejs/kit/hooks'; -import * as crypto from 'node:crypto'; -import { sveltekitSessionHandle } from 'svelte-kit-sessions'; - -import { env } from '$env/dynamic/private'; import { paraglideMiddleware } from '$lib/paraglide/server'; - -if (!env.SESSION_SECRET) { - env.SESSION_SECRET = crypto.randomBytes(20).toString('hex'); - console.log(`SESSION_SECRET not found, generating a temporary one: ${env.SESSION_SECRET}`); -} - -const sessionHandle = sveltekitSessionHandle({ - secret: env.SESSION_SECRET, -}); - -const checkAuthorizationHandle: Handle = async ({ event, resolve }) => { - if ( - !event.locals.session.data.path && - event.url.pathname !== '/load-project' && - event.url.pathname + event.url.search !== '/cli?/new' - ) { - throw redirect(302, '/load-project'); - } - return resolve(event); -}; +import { checkAuthorizationHandle, sessionHandle } from '$lib/server/session'; const handleParaglide: Handle = ({ event, resolve }) => paraglideMiddleware(event.request, ({ request, locale }) => { diff --git a/src/lib/client/action/base.repository.ts b/src/lib/client/action/base.repository.ts new file mode 100644 index 0000000..2cea8a8 --- /dev/null +++ b/src/lib/client/action/base.repository.ts @@ -0,0 +1,58 @@ +import { deserialize } from '$app/forms'; + +import { Exception } from '@utils/exception'; +import type { HttpClient, RequestOptions } from '@utils/http'; + +export class BaseRepository { + private readonly _client: HttpClient; + + constructor(client: HttpClient) { + this._client = client; + } + + protected run( + path: string, + body?: I, + options?: RequestOptions, + ): Promise { + return this.runRequestBody(path, body, options); + } + + private async runRequestBody(path: string, body?: I, options?: RequestOptions): Promise { + const rawResult = await this._client.post(path, this._parseBodyToFormData(body), options); + const result = deserialize(await rawResult.text()); + + if (result.type === 'redirect') + throw new Error(`Redirect (${result.status}) - ${result.location}`); + if (result.type === 'error') { + if (result.error?.error && result.error?.message && result.status) + throw new Exception(result.error.error, result.error.message, result.status); + throw new Error(`Error (${result.status}) - ${result.error}`); + } + + if (result.type === 'failure') { + if (result.data?.error && result.data?.message && result.status) + throw new Exception( + result.data.error as string, + result.data.message as string, + result.status, + ); + throw new Error(`Failure (${result.status}) - ${result.data}`); + } + + return result.data as R; + } + + private _parseBodyToFormData(body?: any): FormData { + const formData = new FormData(); + if (body) { + for (const [key, baseValue] of Object.entries(body)) { + let value: Blob | string; + if (baseValue instanceof File) value = baseValue; + else value = JSON.stringify(baseValue); + formData.append(key, value); + } + } + return formData; + } +} diff --git a/src/lib/client/action/client.ts b/src/lib/client/action/client.ts new file mode 100644 index 0000000..22c7d58 --- /dev/null +++ b/src/lib/client/action/client.ts @@ -0,0 +1,33 @@ +import { SESSION_PROJECT_HEADER } from '@utils/const'; +import { HttpClient } from '@utils/http'; + +import { ProjectFsRepository } from './repositories/fs.repository'; +import { ProjectLoaderRepository } from './repositories/loader.repository'; +import { ProjectPackageRepository } from './repositories/package.repository'; +import { ProjectRepository } from './repositories/project.repository'; +import { ProjectSaveRepository } from './repositories/save.repository'; + +export interface ActionClient { + fs: ProjectFsRepository; + loader: ProjectLoaderRepository; + package: ProjectPackageRepository; + project: ProjectRepository; + save: ProjectSaveRepository; +} + +export const getActionClient = (projectId?: string): ActionClient => { + const client = new HttpClient( + '', + projectId ? { headers: { [SESSION_PROJECT_HEADER]: projectId } } : {}, + ); + + return { + fs: new ProjectFsRepository(client), + loader: new ProjectLoaderRepository(client), + package: new ProjectPackageRepository(client), + project: new ProjectRepository(client), + save: new ProjectSaveRepository(client), + }; +}; + +export const noProjectActions = getActionClient(); diff --git a/src/lib/client/action/index.ts b/src/lib/client/action/index.ts new file mode 100644 index 0000000..c2c5d62 --- /dev/null +++ b/src/lib/client/action/index.ts @@ -0,0 +1,2 @@ +export { noProjectActions, type ActionClient, getActionClient } from './client'; +export * from './types'; diff --git a/src/lib/client/action/repositories/fs.repository.ts b/src/lib/client/action/repositories/fs.repository.ts new file mode 100644 index 0000000..e19e0de --- /dev/null +++ b/src/lib/client/action/repositories/fs.repository.ts @@ -0,0 +1,8 @@ +import { BaseRepository } from '../base.repository'; +import type { ReaddirFsActionInput, ReaddirFsActionResult } from '../types'; + +export class ProjectFsRepository extends BaseRepository { + readdir(input: ReaddirFsActionInput): Promise { + return this.run(`/actions/project/fs?/readdir`, input); + } +} diff --git a/src/lib/client/action/repositories/loader.repository.ts b/src/lib/client/action/repositories/loader.repository.ts new file mode 100644 index 0000000..d7dd052 --- /dev/null +++ b/src/lib/client/action/repositories/loader.repository.ts @@ -0,0 +1,16 @@ +import { BaseRepository } from '../base.repository'; +import type { ActionLoaderEnv, ActionLoaderManifest } from '../types'; + +export class ProjectLoaderRepository extends BaseRepository { + env(): Promise { + return this.run(`/actions/project/loader?/env`); + } + + manifest(): Promise { + return this.run(`/actions/project/loader?/manifest`); + } + + build(): Promise { + return this.run(`/actions/project/loader?/build`); + } +} diff --git a/src/lib/client/action/repositories/package.repository.ts b/src/lib/client/action/repositories/package.repository.ts new file mode 100644 index 0000000..a3e98d7 --- /dev/null +++ b/src/lib/client/action/repositories/package.repository.ts @@ -0,0 +1,41 @@ +import type { EditorComponentManifest, EditorSystemManifest } from '@nanoforge-dev/ecs-lib'; + +import { BaseRepository } from '../base.repository'; +import type { + AddComponentsActionInput, + AddSystemsActionInput, + CreateComponentActionInput, + CreateSystemActionInput, + GetComponentsManifestsActionInput, + GetSystemsManifestsActionInput, + NewComponentPackageResult, + NewSystemPackageResult, +} from '../types'; + +export class ProjectPackageRepository extends BaseRepository { + addComponents(input: AddComponentsActionInput): Promise { + return this.run(`/actions/project/package?/add-components`, input); + } + + addSystems(input: AddSystemsActionInput): Promise { + return this.run(`/actions/project/package?/add-systems`, input); + } + + createComponent(input: CreateComponentActionInput): Promise { + return this.run(`/actions/project/package?/create-component`, input); + } + + createSystem(input: CreateSystemActionInput): Promise { + return this.run(`/actions/project/package?/create-system`, input); + } + + getComponentsManifests( + input: GetComponentsManifestsActionInput, + ): Promise { + return this.run(`/actions/project/package?/get-components-manifests`, input); + } + + getSystemsManifests(input: GetSystemsManifestsActionInput): Promise { + return this.run(`/actions/project/package?/get-systems-manifests`, input); + } +} diff --git a/src/lib/client/action/repositories/project.repository.ts b/src/lib/client/action/repositories/project.repository.ts new file mode 100644 index 0000000..068795b --- /dev/null +++ b/src/lib/client/action/repositories/project.repository.ts @@ -0,0 +1,31 @@ +import { BaseRepository } from '../base.repository'; +import type { + ActionProject, + CreateProjectActionInput, + GatewayProjectResult, + InfoProjectInput, + InfoProjectResult, + LoadProjectActionInput, +} from '../types'; + +export class ProjectRepository extends BaseRepository { + load(input: LoadProjectActionInput): Promise { + return this.run(`/actions/project?/load`, input); + } + + new(input: CreateProjectActionInput): Promise { + return this.run(`/actions/project?/new`, input); + } + + getInfo(): Promise { + return this.run(`/actions/project?/get-info`); + } + + setInfo(input: InfoProjectInput): Promise { + return this.run(`/actions/project?/set-info`, input); + } + + getGatewayProjects(): Promise { + return this.run(`/actions/project?/get-gateway-projects`); + } +} diff --git a/src/lib/client/action/repositories/save.repository.ts b/src/lib/client/action/repositories/save.repository.ts new file mode 100644 index 0000000..e2939f4 --- /dev/null +++ b/src/lib/client/action/repositories/save.repository.ts @@ -0,0 +1,11 @@ +import { BaseRepository } from '../base.repository'; +import type { GetSaveResult, SetSaveInput } from '../types'; + +export class ProjectSaveRepository extends BaseRepository { + get(): Promise { + return this.run(`/actions/project/save?/get`); + } + set(input: SetSaveInput): Promise { + return this.run(`/actions/project/save?/set`, input); + } +} diff --git a/src/lib/client/action/types/fs.type.ts b/src/lib/client/action/types/fs.type.ts new file mode 100644 index 0000000..ee72695 --- /dev/null +++ b/src/lib/client/action/types/fs.type.ts @@ -0,0 +1,6 @@ +import type { ReaddirFsBody } from '$lib/server/actions/project/fs/readdir.action'; +import type { DirectoryContent } from '$lib/server/file-system/project-directory'; + +export type ReaddirFsActionInput = ReaddirFsBody; + +export type ReaddirFsActionResult = DirectoryContent; diff --git a/src/lib/client/action/types/index.ts b/src/lib/client/action/types/index.ts new file mode 100644 index 0000000..78759b4 --- /dev/null +++ b/src/lib/client/action/types/index.ts @@ -0,0 +1,5 @@ +export * from './fs.type'; +export * from './loader.type'; +export * from './project.type'; +export * from './package.type'; +export * from './save.type'; diff --git a/src/lib/client/action/types/loader.type.ts b/src/lib/client/action/types/loader.type.ts new file mode 100644 index 0000000..3b24c56 --- /dev/null +++ b/src/lib/client/action/types/loader.type.ts @@ -0,0 +1,5 @@ +import type { Loader } from '$lib/server/project/loader'; + +export type ActionLoaderManifest = ReturnType; + +export type ActionLoaderEnv = ReturnType; diff --git a/src/lib/client/action/types/package.type.ts b/src/lib/client/action/types/package.type.ts new file mode 100644 index 0000000..c347943 --- /dev/null +++ b/src/lib/client/action/types/package.type.ts @@ -0,0 +1,26 @@ +import type { AddComponentBody } from '$lib/server/actions/project/package/add-components.action'; +import type { AddSystemBody } from '$lib/server/actions/project/package/add-systems.action'; +import type { CreateComponentBody } from '$lib/server/actions/project/package/create-component.action'; +import type { CreateSystemBody } from '$lib/server/actions/project/package/create-system.action'; +import type { GetComponentManifestBody } from '$lib/server/actions/project/package/get-components-manifests.action'; +import type { GetSystemManifestBody } from '$lib/server/actions/project/package/get-systems-manifests.action'; +import type { + NewComponentPackage, + NewSystemPackage, +} from '$lib/server/project/package/package.type'; + +export type NewComponentPackageResult = NewComponentPackage; + +export type NewSystemPackageResult = NewSystemPackage; + +export type AddComponentsActionInput = AddComponentBody; + +export type AddSystemsActionInput = AddSystemBody; + +export type GetComponentsManifestsActionInput = GetComponentManifestBody; + +export type GetSystemsManifestsActionInput = GetSystemManifestBody; + +export type CreateComponentActionInput = CreateComponentBody; + +export type CreateSystemActionInput = CreateSystemBody; diff --git a/src/lib/client/action/types/project.type.ts b/src/lib/client/action/types/project.type.ts new file mode 100644 index 0000000..67c7660 --- /dev/null +++ b/src/lib/client/action/types/project.type.ts @@ -0,0 +1,16 @@ +import type { GatewayProject } from '$lib/server/actions/project/gateway.action'; +import type { InfoProject, InfoProjectBody } from '$lib/server/actions/project/info.action'; +import type { LoadProjectBody } from '$lib/server/actions/project/load.action'; +import type { CreateProjectBody } from '$lib/server/actions/project/new.action'; +import type { Project } from '$lib/server/project'; + +export type ActionProject = Project; + +export type LoadProjectActionInput = LoadProjectBody; + +export type CreateProjectActionInput = CreateProjectBody; + +export type InfoProjectResult = InfoProject; +export type InfoProjectInput = InfoProjectBody; + +export type GatewayProjectResult = GatewayProject; diff --git a/src/lib/client/action/types/save.type.ts b/src/lib/client/action/types/save.type.ts new file mode 100644 index 0000000..3f71760 --- /dev/null +++ b/src/lib/client/action/types/save.type.ts @@ -0,0 +1,7 @@ +import type { SetSaveBody } from '$lib/server/actions/project/save/set-save.action'; + +import type { Save } from '@utils/types'; + +export type GetSaveResult = Save; + +export type SetSaveInput = SetSaveBody; diff --git a/src/lib/client/config/config.ts b/src/lib/client/config/config.ts new file mode 100644 index 0000000..03da139 --- /dev/null +++ b/src/lib/client/config/config.ts @@ -0,0 +1,9 @@ +import { PUBLIC_MODE } from '$env/static/public'; + +import type { Config } from './config.type'; + +export const getConfig = (): Config => { + return { + mode: PUBLIC_MODE === 'online' ? 'online' : 'offline', + }; +}; diff --git a/src/lib/client/config/config.type.ts b/src/lib/client/config/config.type.ts new file mode 100644 index 0000000..0b54c05 --- /dev/null +++ b/src/lib/client/config/config.type.ts @@ -0,0 +1,3 @@ +export interface Config { + mode: 'offline' | 'online'; +} diff --git a/src/lib/client/config/index.ts b/src/lib/client/config/index.ts new file mode 100644 index 0000000..ce28a64 --- /dev/null +++ b/src/lib/client/config/index.ts @@ -0,0 +1,2 @@ +export type { Config } from './config.type'; +export { getConfig } from './config'; diff --git a/src/lib/client/event/event-emitter.ts b/src/lib/client/event/event-emitter.ts new file mode 100644 index 0000000..09e5956 --- /dev/null +++ b/src/lib/client/event/event-emitter.ts @@ -0,0 +1,72 @@ +import type { IEventEmitter, ListenerType, QueuedEvent } from './types'; + +export class EventEmitter< + Events extends string, + EventsMap extends Record, +> implements IEventEmitter { + public listeners: { + [K in keyof EventsMap]?: ListenerType[]; + } = {}; + + public eventQueue: QueuedEvent[] = []; + + runEvents(): void { + this.eventQueue.forEach((e) => { + this._executeEvent(e); + }); + + this.eventQueue = []; + } + + emitEvent(event: K, ...args: EventsMap[K]): void { + this.eventQueue.push({ + event, + args, + }); + } + addListener( + event: K, + listener: ListenerType, + ): void { + if (!this.listeners[event]) this.listeners[event] = []; + this.listeners[event].push(listener); + } + on(event: K, listener: ListenerType): void { + this.addListener(event, listener); + } + + removeListener( + event: K, + listener: ListenerType, + ): void { + if (!this.listeners[event]) return; + const index = this.listeners[event].indexOf(listener); + if (index >= 0) { + this.listeners[event].splice(index, 1); + } + } + off(event: K, listener: ListenerType): void { + this.removeListener(event, listener); + } + + removeListenersForEvent(event: keyof EventsMap): void { + if (!this.listeners[event]) return; + this.listeners[event] = []; + } + removeAllListeners(): void { + this.listeners = {}; + } + + private _executeEvent({ + event, + args, + }: QueuedEvent): void { + this.listeners[event]?.forEach((listener) => { + try { + listener(...args); + } catch (error) { + console.error(`Error handling event [${String(event)}]:`, error); + } + }); + } +} diff --git a/src/lib/client/event/event-handler.ts b/src/lib/client/event/event-handler.ts new file mode 100644 index 0000000..27af05d --- /dev/null +++ b/src/lib/client/event/event-handler.ts @@ -0,0 +1,20 @@ +import { EventEmitter } from './event-emitter'; +import { type CoreEvents, type CoreEventsMap } from './events/core-events'; +import { type EditorEvents, type EditorEventsMap } from './events/editor-events'; +import type { ListenerType } from './types'; + +export class EventHandler { + public readonly _coreEvents = new EventEmitter(); + public readonly _editorEvents = new EventEmitter(); + + emit(event: K, ...args: CoreEventsMap[K]) { + this._coreEvents.emitEvent(event, ...args); + } + + on( + event: K, + callback: ListenerType, + ) { + this._editorEvents.on(event, callback); + } +} diff --git a/src/lib/client/event/events/core-events.ts b/src/lib/client/event/events/core-events.ts new file mode 100644 index 0000000..fda6f18 --- /dev/null +++ b/src/lib/client/event/events/core-events.ts @@ -0,0 +1,15 @@ +export enum CoreEvents { + HOT_RELOAD = 'hot-reload', + HARD_RELOAD = 'hard-reload', + PAUSE_GAME = 'pause-game', + STOP_GAME = 'stop-game', + UNPAUSE_GAME = 'unpause-game', +} + +export interface CoreEventsMap { + [CoreEvents.HOT_RELOAD]: []; + [CoreEvents.HARD_RELOAD]: []; + [CoreEvents.PAUSE_GAME]: [duration: number]; + [CoreEvents.STOP_GAME]: []; + [CoreEvents.UNPAUSE_GAME]: []; +} diff --git a/src/lib/client/event/events/editor-events.ts b/src/lib/client/event/events/editor-events.ts new file mode 100644 index 0000000..85b6752 --- /dev/null +++ b/src/lib/client/event/events/editor-events.ts @@ -0,0 +1,9 @@ +// ! Please do not remove this event unless a new one replaces it, it causes types issues + +export enum EditorEvents { + EMPTY = 'empty', +} + +export interface EditorEventsMap { + [EditorEvents.EMPTY]: []; +} diff --git a/src/lib/client/event/index.ts b/src/lib/client/event/index.ts new file mode 100644 index 0000000..7a43e86 --- /dev/null +++ b/src/lib/client/event/index.ts @@ -0,0 +1,4 @@ +export { EventHandler } from './event-handler'; +export type * from './types'; +export * from './events/core-events'; +export * from './events/editor-events'; diff --git a/src/lib/client/event/types/event-emitter.type.ts b/src/lib/client/event/types/event-emitter.type.ts new file mode 100644 index 0000000..1e23f07 --- /dev/null +++ b/src/lib/client/event/types/event-emitter.type.ts @@ -0,0 +1,40 @@ +export type ListenerType< + Events extends string, + EventsMap extends Record, + K extends keyof EventsMap, +> = (...args: EventsMap[K]) => void; + +export type QueuedEvent = { + event: K; + args: EventsMap[K]; +}; + +export interface IEventEmitter> { + listeners: { + [K in keyof EventsMap]?: ListenerType[]; + }; + + eventQueue: QueuedEvent[]; + + runEvents(): void; + + emitEvent(event: K, ...args: EventsMap[K]): void; + + addListener( + event: K, + listener: ListenerType, + ): void; + + on(event: K, listener: ListenerType): void; + + removeListener( + event: K, + listener: ListenerType, + ): void; + + off(event: K, listener: ListenerType): void; + + removeListenersForEvent(event: keyof EventsMap): void; + + removeAllListeners(): void; +} diff --git a/src/lib/client/event/types/index.ts b/src/lib/client/event/types/index.ts new file mode 100644 index 0000000..532d572 --- /dev/null +++ b/src/lib/client/event/types/index.ts @@ -0,0 +1 @@ +export * from './event-emitter.type'; diff --git a/src/lib/client/info/index.ts b/src/lib/client/info/index.ts new file mode 100644 index 0000000..6297afe --- /dev/null +++ b/src/lib/client/info/index.ts @@ -0,0 +1 @@ +export { InfoHandler } from './info'; diff --git a/src/lib/client/info/info.store.ts b/src/lib/client/info/info.store.ts new file mode 100644 index 0000000..3fb9af4 --- /dev/null +++ b/src/lib/client/info/info.store.ts @@ -0,0 +1,5 @@ +import { writable } from 'svelte/store'; + +import type { ProjectInfo } from './info.type'; + +export const infoStore = writable(); diff --git a/src/lib/client/info/info.ts b/src/lib/client/info/info.ts new file mode 100644 index 0000000..e2093a3 --- /dev/null +++ b/src/lib/client/info/info.ts @@ -0,0 +1,36 @@ +import { get } from 'svelte/store'; + +import { type Project } from '$lib/client/project'; + +import { infoStore } from './info.store'; +import type { ProjectInfo, ProjectInfoInput } from './info.type'; + +export class InfoHandler { + static reset(): void { + infoStore.set(null); + } + + constructor(private readonly core: Project) {} + + get(cacheOnly: true): ProjectInfo | null; + get(): Promise; + get(cacheOnly?: boolean): ProjectInfo | null | Promise { + if (cacheOnly) return get(infoStore); + return this.fetch(); + } + + async fetch(noCache: boolean = false): Promise { + if (!noCache) { + const cache = get(infoStore); + if (cache) return cache; + } + const res = await this.core.actions.project.getInfo(); + infoStore.set(res); + return res; + } + + async set(input: ProjectInfoInput): Promise { + await this.core.actions.project.setInfo(input); + await this.fetch(true); + } +} diff --git a/src/lib/client/info/info.type.ts b/src/lib/client/info/info.type.ts new file mode 100644 index 0000000..775aa38 --- /dev/null +++ b/src/lib/client/info/info.type.ts @@ -0,0 +1,5 @@ +import type { InfoProject, InfoProjectBody } from '$lib/server/actions/project/info.action'; + +export type ProjectInfo = InfoProject; + +export type ProjectInfoInput = InfoProjectBody; diff --git a/src/lib/client/loader/index.ts b/src/lib/client/loader/index.ts new file mode 100644 index 0000000..a172c26 --- /dev/null +++ b/src/lib/client/loader/index.ts @@ -0,0 +1,3 @@ +export { Loader } from './loader'; +export * from './types/game.type'; +export * from './types/manifest.type'; diff --git a/src/lib/client/loader/loader.ts b/src/lib/client/loader/loader.ts new file mode 100644 index 0000000..a88d42b --- /dev/null +++ b/src/lib/client/loader/loader.ts @@ -0,0 +1,84 @@ +import type { Project } from '$lib/client/project'; +import { SyncFileSystem } from '$lib/client/sync-file-system'; + +import type { RawEventEmitter } from './types/event-emitter.type'; +import type { IGameOptions } from './types/game.type'; +import type { IExtendedManifestFile, IManifest } from './types/manifest.type'; + +type MainFunction = (options: IGameOptions) => Promise; + +export class Loader { + private readonly fs: SyncFileSystem; + + constructor(private readonly core: Project) { + this.fs = new SyncFileSystem(this.core, 'build'); + } + + async build(): Promise { + await this.core.actions.loader.build(); + } + + async start(container: HTMLDivElement): Promise { + const manifest = await this.fetchManifest(); + const env = await this.fetchEnv(); + const { mainFile, files } = await this.resolveGameFiles(manifest); + const save = this.core.save.save; + + const main = await this.loadMainFile(mainFile); + + main({ + files, + env, + editor: { + save, + coreEvents: this.core.event._coreEvents as unknown as RawEventEmitter, + editorEvents: this.core.event._editorEvents as unknown as RawEventEmitter, + }, + container, + }).then(() => console.log('Game started!')); + } + + private async loadMainFile(file: string): Promise { + const res = await import(/* @vite-ignore */ file); + if (res['main']) return res['main']; + throw new Error('No main function found in the main.js file'); + } + + private fetchEnv(): Promise> { + return this.core.actions.loader.env(); + } + + private fetchManifest(): Promise { + return this.core.actions.loader.manifest(); + } + + private async resolveGameFiles( + manifest: IManifest, + ): Promise<{ mainFile: string; files: Map }> { + const files = await this.fetchFiles(manifest); + + let mainFile: string | undefined; + const resMap = new Map(); + + for (const file of files) { + if (file.gamePath === '/main.js') { + mainFile = file.localPath; + continue; + } + resMap.set(file.gamePath, file.localPath); + } + + if (!mainFile) throw new Error('No main.js file found in the manifest'); + return { mainFile, files: resMap }; + } + + private async fetchFiles(manifest: IManifest): Promise { + return await Promise.all( + manifest.files.map(async ({ path }) => { + const file = await this.fs.getFile(path); + await file.fetch(); + return { gamePath: path, localPath: await file.getUrl() }; + }), + ); + } +} diff --git a/src/lib/client/loader/types/event-emitter.type.ts b/src/lib/client/loader/types/event-emitter.type.ts new file mode 100644 index 0000000..c74d027 --- /dev/null +++ b/src/lib/client/loader/types/event-emitter.type.ts @@ -0,0 +1,3 @@ +import type { IEventEmitter } from '$lib/client/event'; + +export type RawEventEmitter = IEventEmitter>; diff --git a/src/lib/client/loader/types/game.type.ts b/src/lib/client/loader/types/game.type.ts new file mode 100644 index 0000000..c02a445 --- /dev/null +++ b/src/lib/client/loader/types/game.type.ts @@ -0,0 +1,14 @@ +import type { Save } from '@utils/types'; + +import type { RawEventEmitter } from './event-emitter.type'; + +export interface IGameOptions { + container: HTMLDivElement; + files: Map; + env: Record; + editor: { + save: Save; + coreEvents: RawEventEmitter; + editorEvents: RawEventEmitter; + }; +} diff --git a/src/lib/loader/client/types/manifest.type.ts b/src/lib/client/loader/types/manifest.type.ts similarity index 82% rename from src/lib/loader/client/types/manifest.type.ts rename to src/lib/client/loader/types/manifest.type.ts index 580f9a2..a9b59a4 100644 --- a/src/lib/loader/client/types/manifest.type.ts +++ b/src/lib/client/loader/types/manifest.type.ts @@ -1,6 +1,6 @@ export interface IManifest { version: string; - files: string[]; + files: { path: string }[]; } export interface IExtendedManifestFile { diff --git a/src/lib/client/project/index.ts b/src/lib/client/project/index.ts new file mode 100644 index 0000000..64cf9e3 --- /dev/null +++ b/src/lib/client/project/index.ts @@ -0,0 +1,3 @@ +export { Project } from './project'; +export { ProjectCache, type ProjectDataCache } from './project-loader/project-cache'; +export { ProjectLoader, useProject, getProject } from './project-loader/project-loader'; diff --git a/src/lib/client/project/package-handler.ts b/src/lib/client/project/package-handler.ts new file mode 100644 index 0000000..d3e0a01 --- /dev/null +++ b/src/lib/client/project/package-handler.ts @@ -0,0 +1,73 @@ +import type { EditorComponentManifest, EditorSystemManifest } from '@nanoforge-dev/ecs-lib'; + +import type { Project } from '$lib/client/project'; + +export class PackageHandler { + private _project: Project; + + private _componentsManifests: Map = new Map(); + private _systemsManifests: Map = new Map(); + + constructor(project: Project) { + this._project = project; + } + + async init() { + if (this._project.save.save.components.length > 0) { + this._componentsManifests = new Map( + ( + await this._project.actions.package.getComponentsManifests({ + componentPaths: this._project.save.save.components.map((c) => c.path) as [ + string, + ...string[], + ], + }) + ).map((e, index) => [this._project.save.save.components[index].name, e]), + ); + } + if (this._project.save.save.systems.length > 0) { + this._systemsManifests = new Map( + ( + await this._project.actions.package.getSystemsManifests({ + systemPaths: this._project.save.save.systems.map((s) => s.path) as [ + string, + ...string[], + ], + }) + ).map((e, index) => [this._project.save.save.systems[index].name, e]), + ); + } + } + + getComponentManifest(componentName: string): EditorComponentManifest | undefined { + return this._componentsManifests.get(componentName); + } + + getSystemManifest(systemName: string): EditorSystemManifest | undefined { + return this._systemsManifests.get(systemName); + } + + async installComponent(name: string): Promise { + const newComponent = ( + await this._project.actions.package.addComponents({ componentNames: [name] }) + )[0]; + + this._project.save.save.components.push(newComponent.save); + this._componentsManifests.set(newComponent.save.name, newComponent.manifest); + } + + async installSystem(name: string): Promise { + const newSystem = (await this._project.actions.package.addSystems({ systemNames: [name] }))[0]; + + this._project.save.save.systems.push(newSystem.save); + this._systemsManifests.set(newSystem.save.name, newSystem.manifest); + } + + addComponentManifest(componentName: string, component: EditorComponentManifest) { + this._componentsManifests.set(componentName, component); + } + + addSystemManifest(systemName: string, system: EditorSystemManifest) { + this._systemsManifests.set(systemName, system); + } +} diff --git a/src/lib/client/project/project-loader/project-cache.ts b/src/lib/client/project/project-loader/project-cache.ts new file mode 100644 index 0000000..e513379 --- /dev/null +++ b/src/lib/client/project/project-loader/project-cache.ts @@ -0,0 +1,94 @@ +import { noProjectActions } from '$lib/client/action'; +import { getConfig } from '$lib/client/config'; + +import { generateKey } from '@utils/string'; + +export interface ProjectDataCache { + id: string; + resolvable: string; + lastOpened: number; + name?: string; + imageUrl?: string; + invalid?: boolean; +} + +export class ProjectCache { + private static storageKey = 'projects'; + private static isOnline = getConfig().mode === 'online'; + + static async getProjects(): Promise { + if (this.isOnline) return ProjectCache.getOnlineProjects(); + const storedProjects = localStorage.getItem(this.storageKey); + if (storedProjects) { + return (JSON.parse(storedProjects) as ProjectDataCache[]).sort( + (a, b) => b.lastOpened - a.lastOpened, + ); + } + return []; + } + + static async getOnlineProjects(): Promise { + const projects = await noProjectActions.project.getGatewayProjects(); + return projects.map((project) => ({ + id: generateKey(10), + resolvable: project.gatewayId, + lastOpened: Date.now(), + name: project.name, + })); + } + + static async getProject(id: string): Promise { + const projects = await this.getProjects(); + const project = projects.find((project) => project.id === id); + if (project) return project; + throw new Error('Project not found'); + } + + static async addProject(project: ProjectDataCache): Promise { + if (this.isOnline) return; + const projects = await this.getProjects(); + projects.push(project); + localStorage.setItem(this.storageKey, JSON.stringify(projects)); + } + + static async removeProject(id: string): Promise { + if (this.isOnline) return; + let projects = await this.getProjects(); + projects = projects.filter((project) => project.id !== id); + localStorage.setItem(this.storageKey, JSON.stringify(projects)); + } + + static async updateProject(id: string, updatedProject: Partial): Promise { + if (this.isOnline) return; + const projects = await this.getProjects(); + const projectIndex = projects.findIndex((project) => project.id === id); + + if (projectIndex !== -1) { + projects[projectIndex] = { ...projects[projectIndex], ...updatedProject }; + localStorage.setItem(this.storageKey, JSON.stringify(projects)); + } + } + + static async invalidateProject(id: string): Promise { + return ProjectCache.updateProject(id, { invalid: true }); + } + + static async clearProjects(): Promise { + if (this.isOnline) return; + localStorage.removeItem(this.storageKey); + } + + static async addOrUpdateProject(project: ProjectDataCache): Promise { + if (this.isOnline) return; + const projects = await this.getProjects(); + const projectIndex = projects.findIndex( + (p) => p.id === project.id || p.resolvable === project.resolvable, + ); + if (projectIndex !== -1) { + projects[projectIndex] = { ...projects[projectIndex], ...project }; + } else { + projects.push(project); + } + localStorage.setItem(this.storageKey, JSON.stringify(projects)); + } +} diff --git a/src/lib/client/project/project-loader/project-loader.ts b/src/lib/client/project/project-loader/project-loader.ts new file mode 100644 index 0000000..2474e24 --- /dev/null +++ b/src/lib/client/project/project-loader/project-loader.ts @@ -0,0 +1,106 @@ +import { get, writable } from 'svelte/store'; + +import { + type ActionProject, + type CreateProjectActionInput, + noProjectActions, +} from '$lib/client/action'; +import { getConfig } from '$lib/client/config/config'; +import { Project, ProjectCache, type ProjectDataCache } from '$lib/client/project'; +import { SfsTreeCache } from '$lib/client/sync-file-system'; + +import { FileSystemManager } from '@utils-client/file-system'; + +const projectStore = writable(null); + +export class ProjectLoader { + static async create(input: CreateProjectActionInput) { + const res = await noProjectActions.project.new(input); + + return ProjectLoader.init(res); + } + + static async loadFromCacheWithTryId(cache: ProjectDataCache) { + try { + return await ProjectLoader.loadFromId(cache.id); + } catch { + /* empty */ + } + + return ProjectLoader.loadFromCache(cache); + } + + static async loadFromIdWithCacheFetching(id: string) { + try { + return await ProjectLoader.loadFromId(id); + } catch { + /* empty */ + } + + const cache = await ProjectCache.getProject(id); + + return ProjectLoader.loadFromCache(cache); + } + + static async loadFromCache(cache: ProjectDataCache) { + await ProjectCache.removeProject(cache.id); + const config = getConfig(); + const input = + config.mode === 'offline' ? { path: cache.resolvable } : { gatewayId: cache.resolvable }; + + const res = await noProjectActions.project.load(input); + + const treeCache = new SfsTreeCache(cache.id); + await treeCache.init(); + await treeCache.changeId(res.id); + + const fs = new FileSystemManager('projects'); + const dir = await fs.getDirectory(cache.id); + await dir.rename(res.id); + + return ProjectLoader.init(res); + } + + static async loadFromPath(path: string) { + const res = await noProjectActions.project.load({ path }); + + return ProjectLoader.init(res); + } + + static async loadFromId(id: string) { + const res = await noProjectActions.project.load({ id }); + + return ProjectLoader.init(res); + } + + static unload() { + projectStore.set(null); + Project.reset(); + } + + static async init(input: ActionProject): Promise { + Project.reset(); + + const project = new Project(input.id); + // @todo add a route to check if the project is valid + projectStore.set(project); + + const infos = await project.info.get(); + + await ProjectCache.addOrUpdateProject({ + id: input.id, + resolvable: input.cacheResolvable, + name: infos.name, + lastOpened: Date.now(), + }); + return project; + } +} + +export const useProject = () => { + const project = get(projectStore); + if (!project) throw new Error('Project not loaded'); + return project; +}; + +export const getProject = () => get(projectStore); diff --git a/src/lib/client/project/project.ts b/src/lib/client/project/project.ts new file mode 100644 index 0000000..e2ef54c --- /dev/null +++ b/src/lib/client/project/project.ts @@ -0,0 +1,75 @@ +import { type ActionClient, getActionClient } from '$lib/client/action'; +import { EventHandler } from '$lib/client/event'; +import { InfoHandler } from '$lib/client/info'; +import { Loader } from '$lib/client/loader'; +import { PackageHandler } from '$lib/client/project/package-handler'; +import { SaveHandler } from '$lib/client/project/save-handler'; +import { SyncFileSystem } from '$lib/client/sync-file-system'; + +export class Project { + private _info: InfoHandler | undefined; + private _actions: ActionClient | undefined; + private _fs: SyncFileSystem | undefined; + private _loader: Loader | undefined; + private _save: SaveHandler | undefined; + private _packageHandler: PackageHandler | undefined; + private _eventHandler: EventHandler | undefined; + + private _inited = false; + + static reset(): void { + InfoHandler.reset(); + } + + constructor(public id: string) { + this._save = new SaveHandler(this); + this._packageHandler = new PackageHandler(this); + } + + async init(): Promise { + await this.fs.init(); + await this.save.init(); + await this.packages.init(); + this._inited = true; + return this; + } + + isReady(): boolean { + return this._inited; + } + + get info(): InfoHandler { + if (!this._info) this._info = new InfoHandler(this); + return this._info; + } + + get actions(): ActionClient { + if (!this._actions) this._actions = getActionClient(this.id); + return this._actions; + } + + get fs(): SyncFileSystem { + if (!this._fs) this._fs = new SyncFileSystem(this, 'project'); + return this._fs; + } + + get loader(): Loader { + if (!this._loader) this._loader = new Loader(this); + return this._loader; + } + + get save(): SaveHandler { + if (!this._save) this._save = new SaveHandler(this); + return this._save; + } + + get packages(): PackageHandler { + if (!this._packageHandler) this._packageHandler = new PackageHandler(this); + return this._packageHandler; + } + + get event(): EventHandler { + if (!this._eventHandler) this._eventHandler = new EventHandler(); + return this._eventHandler; + } +} diff --git a/src/lib/client/project/save-handler.ts b/src/lib/client/project/save-handler.ts new file mode 100644 index 0000000..ada63c0 --- /dev/null +++ b/src/lib/client/project/save-handler.ts @@ -0,0 +1,58 @@ +import type { EditorComponentManifest } from '@nanoforge-dev/ecs-lib'; +import { type Writable, get, writable } from 'svelte/store'; + +import type { Project } from '$lib/client/project'; + +import type { Save, SaveComponent, SaveEntity, SaveSystem } from '@utils/types'; + +export class SaveHandler { + private _project: Project; + private _save: Writable = writable({ + libraries: [], + entities: [], + components: [], + systems: [], + }); + + constructor(project: Project) { + this._project = project; + } + + async init() { + await this.fetchFromServer(); + } + + async fetchFromServer() { + this._save.set(await this._project.actions.save.get()); + } + + get save(): Save { + return get(this._save); + } + + addComponent(component: SaveComponent) { + get(this._save).components.push(component); + } + + addEntity(entity: SaveEntity) { + get(this._save).entities.push(entity); + } + + addSystem(system: SaveSystem) { + get(this._save).systems.push(system); + } + + addComponentToEntity( + entityId: string, + componentName: string, + componentManifest: EditorComponentManifest, + ) { + const entity = get(this._save).entities.find((e) => e.id === entityId); + if (!entity) { + throw new Error('Entity not found: ' + entityId); + } + const newComp: Record = {}; + componentManifest.params.forEach((c) => (newComp[c.name] = c.default)); + entity.components[componentName] = newComp; + } +} diff --git a/src/lib/client/sync-file-system/index.ts b/src/lib/client/sync-file-system/index.ts new file mode 100644 index 0000000..4cca18a --- /dev/null +++ b/src/lib/client/sync-file-system/index.ts @@ -0,0 +1,4 @@ +export { SyncFileSystem } from './sfs'; +export { SfsDirectory, type SfsDirectoryMap } from './sfs-directory'; +export { SfsFile } from './sfs-file'; +export { SfsTreeCache } from './sfs-tree-cache'; diff --git a/src/lib/client/sync-file-system/sfs-directory.ts b/src/lib/client/sync-file-system/sfs-directory.ts new file mode 100644 index 0000000..c8a54f5 --- /dev/null +++ b/src/lib/client/sync-file-system/sfs-directory.ts @@ -0,0 +1,46 @@ +import { type SyncFileSystem } from '$lib/client/sync-file-system/sfs'; +import type { DirectoryContent } from '$lib/server/file-system/project-directory'; + +import { type FileSystemDirectory } from '@utils-client/file-system'; + +import { SfsFile } from './sfs-file'; + +export type SfsDirectoryMap = DirectoryContent; + +export class SfsDirectory { + constructor( + private readonly _handler: SyncFileSystem, + private _cache: FileSystemDirectory, + private readonly _path: string, + ) {} + + get path(): string { + return this._path; + } + + async getFile(path: string): Promise { + const fullPath = `${this._path}/${path}`; + if (await this._cache.fileExist(path)) + return new SfsFile(this._handler, await this._cache?.getFile(path, false), fullPath); + return new SfsFile(this._handler, null, fullPath); + } + + async getDirectory(path: string): Promise { + const fullPath = `${this._path}/${path}`; + return new SfsDirectory(this._handler, await this._cache.getDirectory(path, true), fullPath); + } + + async readdir(noCache: boolean = false): Promise { + let res: SfsDirectoryMap | null = null; + + if (!noCache && this._handler.treeCache) res = await this._handler.treeCache.read(this._path); + + if (res) return res; + + res = await this._handler.project.actions.fs.readdir({ path: this._path }); + + if (this._handler.treeCache) await this._handler.treeCache.write(this._path, res); + + return res; + } +} diff --git a/src/lib/client/sync-file-system/sfs-file.ts b/src/lib/client/sync-file-system/sfs-file.ts new file mode 100644 index 0000000..83ab34f --- /dev/null +++ b/src/lib/client/sync-file-system/sfs-file.ts @@ -0,0 +1,89 @@ +import type { SyncFileSystem } from '$lib/client/sync-file-system/sfs'; + +import { SESSION_PROJECT_HEADER } from '@utils/const'; + +import { type FileSystemFile } from '@utils-client/file-system'; + +export class SfsFile { + private readonly _route: string; + + constructor( + private readonly _handler: SyncFileSystem, + private _cache: FileSystemFile | null, + private readonly _path: string, + ) { + this._route = `${this._handler.route}?path=${encodeURIComponent(`${this._path}?url`)}`; + } + + get path(): string { + return this._path; + } + + async getUrl(): Promise { + await this._preRead(); + return this._cache!.getUrl(); + } + + async read(): Promise { + await this._preRead(); + return this._cache!.read(); + } + + async readJson(): Promise { + await this._preRead(); + return this._cache!.readJson(); + } + + async fetch(): Promise { + await this._preWrite(); + const res = await fetch(this._route, { + method: 'GET', + headers: { [SESSION_PROJECT_HEADER]: this._handler.project.id }, + }); + if (!res.ok || !res.body) { + throw new Error('Failed to fetch file'); + } + const stream = await this._cache!.handle.createWritable(); + await res.body.pipeTo(stream); + } + + async write(test: string): Promise { + await this._preWrite(); + await this._cache!.write(test); + await this.sync(); + } + + async writeJson(content: any): Promise { + await this._preWrite(); + await this._cache!.writeJson(content); + await this.sync(); + } + + async sync(): Promise { + if (!this._cache) return; + const file = await this._cache.getFile(); + const res = await fetch(this._route, { + body: file.stream(), + method: 'POST', + headers: { [SESSION_PROJECT_HEADER]: this._handler.project.id }, + }); + if (!res.ok) throw new Error('Failed to sync file'); + } + + async getFile(): Promise { + await this._preRead(); + return this._cache!; + } + + private async _preRead() { + if (!this._cache) { + await this.fetch(); + } + } + + private async _preWrite() { + if (!this._cache) { + this._cache = await this._handler.cache.getFile(this.path, true); + } + } +} diff --git a/src/lib/client/sync-file-system/sfs-tree-cache.ts b/src/lib/client/sync-file-system/sfs-tree-cache.ts new file mode 100644 index 0000000..a27d6dc --- /dev/null +++ b/src/lib/client/sync-file-system/sfs-tree-cache.ts @@ -0,0 +1,78 @@ +import { IndexedDB } from '@utils-client/indexed-db'; + +import { type SfsDirectoryMap } from './sfs-directory'; + +export const SFS_DB_STORE_NAME = 'fs-project-tree'; + +export class SfsTreeCache extends IndexedDB { + constructor(private readonly projectId: string) { + super(); + } + + init(): Promise { + return this.open(1, async (db) => { + db.createObjectStore(SFS_DB_STORE_NAME); + }); + } + + async changeId(newId: string): Promise { + const store = this.getStore(SFS_DB_STORE_NAME); + const data = await store.get(this.projectId); + if (!data) return; + await store.set(newId, data); + await store.delete(this.projectId); + } + + async read(path: string): Promise { + const store = this.getStore(SFS_DB_STORE_NAME); + const data = await store.get(this.projectId); + return this._extractMapFromPath(path, data ?? null); + } + + async write(path: string, data: SfsDirectoryMap): Promise { + const currentData = await this.read(path); + const store = this.getStore(SFS_DB_STORE_NAME); + const map = this._generateMapFromPath( + path, + currentData ?? { files: [], directories: {} }, + data, + ); + await store.set(this.projectId, map); + } + + private _extractMapFromPath(path: string, map: SfsDirectoryMap | null): SfsDirectoryMap | null { + const parts = path.split('/'); + let currentMap: SfsDirectoryMap | null = map; + for (const part of parts) { + if (currentMap === null) return null; + if (part in currentMap.directories) currentMap = currentMap.directories[part] ?? null; + } + return currentMap; + } + + private _generateMapFromPath( + path: string, + map: SfsDirectoryMap, + data: SfsDirectoryMap, + ): SfsDirectoryMap | null { + if (!path) return data; + const parts = path.split('/'); + return this._generateMapFromPathRec(parts, map, data); + } + + private _generateMapFromPathRec( + parts: string[], + map: SfsDirectoryMap, + data: SfsDirectoryMap, + ): SfsDirectoryMap | null { + if (parts.length === 0) return data; + const [part, ...rest] = parts; + + map.directories[part] = this._generateMapFromPathRec( + rest, + map.directories[part] ?? { files: [], directories: {} }, + data, + ); + return map; + } +} diff --git a/src/lib/client/sync-file-system/sfs.ts b/src/lib/client/sync-file-system/sfs.ts new file mode 100644 index 0000000..4a325e6 --- /dev/null +++ b/src/lib/client/sync-file-system/sfs.ts @@ -0,0 +1,44 @@ +import type { Project } from '$lib/client/project'; + +import { FileSystemManager } from '@utils-client/file-system'; + +import { SfsDirectory } from './sfs-directory'; +import { SfsFile } from './sfs-file'; +import { SfsTreeCache } from './sfs-tree-cache'; + +export type SyncFileSystemPart = 'build' | 'project'; + +const FS_ROUTE: Record = { + build: '/fs/build', + project: '/fs/project', +}; + +export class SyncFileSystem { + public readonly project: Project; + public readonly route: string; + public readonly cache: FileSystemManager; + public readonly treeCache: SfsTreeCache | undefined; + + constructor(project: Project, part: SyncFileSystemPart) { + this.project = project; + this.route = FS_ROUTE[part]; + this.cache = new FileSystemManager(`projects/${project.id}/${part}`); + if (part === 'project') this.treeCache = new SfsTreeCache(project.id); + } + + async init(): Promise { + await this.treeCache?.init(); + } + + async getFile(path: string): Promise { + return new SfsFile( + this, + (await this.cache.fileExist(path)) ? await this.cache.getFile(path, false) : null, + path, + ); + } + + async getDirectory(path?: string): Promise { + return new SfsDirectory(this, await this.cache.getDirectory(path, true), path ?? ''); + } +} diff --git a/src/lib/client/utils/error.ts b/src/lib/client/utils/error.ts new file mode 100644 index 0000000..5402375 --- /dev/null +++ b/src/lib/client/utils/error.ts @@ -0,0 +1,29 @@ +import { Exception } from '@utils/exception'; +import type { MaybePromise } from '@utils/types'; + +import { toastError } from '@utils-client/toasts'; + +export const handleError = (error: unknown, context?: string) => { + const message = `Failed to ${context ?? 'execute'}`; + if (error instanceof Exception) { + console.error(`${message} (${error.error} - ${error.status}): ${error.message}`); + toastError(message, error.message); + return; + } + console.error(`${message}: ${error}`); + toastError(message, `${error}`); +}; + +export const runSafe = async ( + context: string, + cb: () => Promise, + fallback?: () => MaybePromise, +): Promise => { + try { + return await cb(); + } catch (error) { + handleError(error, context); + } + fallback?.(); + return null; +}; diff --git a/src/lib/utils-client/file-system/file-system-directory.ts b/src/lib/client/utils/file-system/file-system-directory.ts similarity index 84% rename from src/lib/utils-client/file-system/file-system-directory.ts rename to src/lib/client/utils/file-system/file-system-directory.ts index 7a6ee6e..5481e77 100644 --- a/src/lib/utils-client/file-system/file-system-directory.ts +++ b/src/lib/client/utils/file-system/file-system-directory.ts @@ -13,7 +13,7 @@ export class FileSystemDirectory { this.handle = handle; } - getName(): string { + get name(): string { return this.handle.name; } @@ -21,6 +21,15 @@ export class FileSystemDirectory { return new FileSystemFile(await this.handle.getFileHandle(name, { create })); } + async fileExist(name: string): Promise { + try { + await this.handle.getFileHandle(name, { create: false }); + return true; + } catch { + return false; + } + } + async getDirectory(name: string, create = true): Promise { return new FileSystemDirectory(await this.handle.getDirectoryHandle(name, { create })); } @@ -63,4 +72,9 @@ export class FileSystemDirectory { await this.removeChild(name); } } + + async rename(name: string): Promise { + if ('move' in this.handle && typeof this.handle.move === 'function') + return await this.handle.move(name); + } } diff --git a/src/lib/client/utils/file-system/file-system-file.ts b/src/lib/client/utils/file-system/file-system-file.ts new file mode 100644 index 0000000..5806181 --- /dev/null +++ b/src/lib/client/utils/file-system/file-system-file.ts @@ -0,0 +1,151 @@ +const FILE_TYPES = { + aac: 'audio/aac', + abw: 'application/x-abiword', + apng: 'image/apng', + arc: 'application/x-freearc', + avi: 'video/x-msvideo', + avif: 'image/avif', + azw: 'application/vnd.amazon.ebook', + bin: 'application/octet-stream', + bmp: 'image/bmp', + bz: 'application/x-bzip', + bz2: 'application/x-bzip2', + cda: 'application/x-cdf', + cjs: 'text/javascript', + csh: 'application/x-csh', + css: 'text/css', + csv: 'text/csv', + doc: 'application/msword', + docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + eot: 'application/vnd.ms-fontobject', + epub: 'application/epub+zip', + gz: 'application/gzip', + gif: 'image/gif', + htm: 'text/html', + html: 'text/html', + ico: 'image/vnd.microsoft.icon', + ics: 'text/calendar', + jar: 'application/java-archive', + jpeg: 'image/jpeg', + jpg: 'image/jpeg', + js: 'application/javascript', + json: 'application/json', + jsonld: 'application/ld+json', + md: 'text/markdown', + mid: 'audio/midi', + midi: 'audio/midi', + mjs: 'text/javascript', + mp3: 'audio/mpeg', + mp4: 'video/mp4', + mpeg: 'video/mpeg', + mpkg: 'application/vnd.apple.installer+xml', + odp: 'application/vnd.oasis.opendocument.presentation', + ods: 'application/vnd.oasis.opendocument.spreadsheet', + odt: 'application/vnd.oasis.opendocument.text', + oga: 'audio/ogg', + ogv: 'video/ogg', + ogx: 'application/ogg', + opus: 'audio/ogg', + otf: 'font/otf', + png: 'image/png', + pdf: 'application/pdf', + php: 'application/x-httpd-php', + ppt: 'application/vnd.ms-powerpoint', + pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + rar: 'application/vnd.rar', + rtf: 'application/rtf', + sh: 'application/x-sh', + svg: 'image/svg+xml', + swf: 'application/x-shockwave-flash', + tar: 'application/x-tar', + tif: 'image/tiff', + tiff: 'image/tiff', + ts: 'text/plain', + ttf: 'font/ttf', + txt: 'text/plain', + vsd: 'application/vnd.visio', + wasm: 'application/wasm', + wav: 'audio/x-wav', + weba: 'audio/webm', + webm: 'video/webm', + webmanifest: 'application/manifest+json', + webp: 'image/webp', + wgsl: 'text/wgsl', + woff: 'font/woff', + woff2: 'font/woff2', + xhtml: 'application/xhtml+xml', + xls: 'application/vnd.ms-excel', + xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + xml: 'application/xml', + xul: 'application/vnd.mozilla.xul+xml', + zip: 'application/zip', + '3gp': 'video/3gpp', + '3g2': 'video/3gpp2', + '7z': 'application/x-7z-compressed', +}; + +const URL_CACHE = new Map(); + +export class FileSystemFile { + readonly handle: FileSystemFileHandle; + + constructor(handle: FileSystemFileHandle) { + this.handle = handle; + } + + get name(): string { + return this.handle.name; + } + + getFile(): Promise { + return this.handle.getFile(); + } + + async isSameFile(file: FileSystemFile): Promise { + return await this.handle.isSameEntry(file.handle); + } + + async read(): Promise { + const file = await this.handle.getFile(); + return file.text(); + } + + async readJson(): Promise { + const raw = await this.read(); + return JSON.parse(raw) as T; + } + + async write(text: string): Promise { + const writable = await this.handle.createWritable(); + await writable.write(text); + await writable.close(); + } + + async writeBinary(base64: string): Promise { + const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)); + const writable = await this.handle.createWritable(); + await writable.write(binary); + await writable.close(); + } + + async writeJson(content: any): Promise { + const raw = JSON.stringify(content); + return this.write(raw); + } + + async getUrl(): Promise { + if (URL_CACHE.has(this.handle.name)) URL.revokeObjectURL(URL_CACHE.get(this.handle.name)!); + const file = await this.handle.getFile(); + const blob = new Blob([await file.arrayBuffer()], { type: this._resolveFileType(file.name) }); + const url = URL.createObjectURL(blob); + URL_CACHE.set(this.handle.name, url); + return url; + } + + private _resolveFileType(name: string): string { + const extension = name.split('.').pop(); + const type = FILE_TYPES[extension as keyof typeof FILE_TYPES]; + if (type) return type; + return 'text/plain'; + } +} diff --git a/src/lib/utils-client/file-system/file-system-handler.ts b/src/lib/client/utils/file-system/file-system-handler.ts similarity index 100% rename from src/lib/utils-client/file-system/file-system-handler.ts rename to src/lib/client/utils/file-system/file-system-handler.ts diff --git a/src/lib/utils-client/file-system/file-system-manager.ts b/src/lib/client/utils/file-system/file-system-manager.ts similarity index 100% rename from src/lib/utils-client/file-system/file-system-manager.ts rename to src/lib/client/utils/file-system/file-system-manager.ts diff --git a/src/lib/utils-client/file-system/index.ts b/src/lib/client/utils/file-system/index.ts similarity index 100% rename from src/lib/utils-client/file-system/index.ts rename to src/lib/client/utils/file-system/index.ts diff --git a/src/lib/client/utils/indexed-db/idb-object.ts b/src/lib/client/utils/indexed-db/idb-object.ts new file mode 100644 index 0000000..436274e --- /dev/null +++ b/src/lib/client/utils/indexed-db/idb-object.ts @@ -0,0 +1,35 @@ +export class IndexedDBObject { + private readonly _store: IDBObjectStore; + + constructor(store: IDBObjectStore) { + this._store = store; + } + + get store(): IDBObjectStore { + return this._store; + } + + get(key: string): Promise { + return new Promise((resolve, reject) => { + const request = this._store.get(key); + request.onsuccess = () => resolve((request.result as T) ?? null); + request.onerror = () => reject(request.error); + }); + } + + set(key: string, data: T): Promise { + return new Promise((resolve, reject) => { + const request = this._store.put(data, key); + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); + } + + delete(key: string): Promise { + return new Promise((resolve, reject) => { + const request = this._store.delete(key); + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); + } +} diff --git a/src/lib/client/utils/indexed-db/idb.ts b/src/lib/client/utils/indexed-db/idb.ts new file mode 100644 index 0000000..634111b --- /dev/null +++ b/src/lib/client/utils/indexed-db/idb.ts @@ -0,0 +1,69 @@ +import { IndexedDBObject } from './idb-object'; + +const DB_NAME = 'nanoforge'; + +export class IndexedDB { + private _db: IDBDatabase | undefined; + + protected constructor() {} + + protected get db(): IDBDatabase { + if (!this._db) { + throw new Error('Database is not open'); + } + return this._db; + } + + protected async open( + version?: number, + upgrade?: (db: IDBDatabase) => Promise, + ): Promise { + const window = (await import('@utils-client/window')).default; + if (!window.indexedDB) { + throw new Error("Your browser doesn't support a stable version of IndexedDB."); + } + const request = window.indexedDB.open(DB_NAME, version ?? 1); + + [this._db] = await Promise.all([ + new Promise((resolve, reject) => { + request.onerror = () => reject(request.error); + request.onsuccess = () => resolve(request.result); + }), + new Promise | undefined>((resolve) => { + request.onupgradeneeded = () => { + upgrade?.(request.result); + }; + // * I don't know how to do it :/ + setTimeout(resolve, 500); + }), + ]); + } + + protected close() { + this._db?.close(); + } + + protected createStore(name: string, keyPath?: string): void { + this._assertDB(); + + this._db!.createObjectStore(name, { keyPath }); + } + + protected getStore(name: string) { + this._assertDB(); + + return new IndexedDBObject(this._db!.transaction(name, 'readwrite').objectStore(name)); + } + + protected deleteStore(name: string) { + this._assertDB(); + + this._db!.deleteObjectStore(name); + } + + private _assertDB() { + if (!this._db) { + throw new Error('Database is not open'); + } + } +} diff --git a/src/lib/client/utils/indexed-db/index.ts b/src/lib/client/utils/indexed-db/index.ts new file mode 100644 index 0000000..b6dc134 --- /dev/null +++ b/src/lib/client/utils/indexed-db/index.ts @@ -0,0 +1 @@ +export { IndexedDB } from './idb'; diff --git a/src/lib/components/Utils/LocalStorage/persistedWritable.ts b/src/lib/client/utils/store.ts similarity index 100% rename from src/lib/components/Utils/LocalStorage/persistedWritable.ts rename to src/lib/client/utils/store.ts diff --git a/src/lib/client/utils/toasts.ts b/src/lib/client/utils/toasts.ts new file mode 100644 index 0000000..42f35fe --- /dev/null +++ b/src/lib/client/utils/toasts.ts @@ -0,0 +1,8 @@ +import { toast } from 'svelte-sonner'; + +export const toastError = (message: string, description?: string) => + toast.error(message, { + description, + position: 'top-right', + style: 'background: oklch(var(--destructive)); color: oklch(var(--destructive-foreground));', + }); diff --git a/src/lib/client/utils/window.ts b/src/lib/client/utils/window.ts new file mode 100644 index 0000000..76f1ace --- /dev/null +++ b/src/lib/client/utils/window.ts @@ -0,0 +1 @@ +export default window; diff --git a/src/lib/components/Entity/types.ts b/src/lib/components/Entity/types.ts deleted file mode 100644 index 79d7c19..0000000 --- a/src/lib/components/Entity/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface RegistryComponentManifest { - name: string; - type: 'component' | 'system'; - description: string; - tags: string[]; - _file: string; -} diff --git a/src/lib/components/Menu/MenuBar.svelte b/src/lib/components/Menu/MenuBar.svelte index 77e98b4..fa023b3 100644 --- a/src/lib/components/Menu/MenuBar.svelte +++ b/src/lib/components/Menu/MenuBar.svelte @@ -35,9 +35,7 @@ /> Export - goto(resolve('/load-project'))} - >Exit + goto(resolve('/'))}>Exit Undo diff --git a/src/lib/components/ProjectLoader/CreateProject.svelte b/src/lib/components/ProjectLoader/CreateProject.svelte deleted file mode 100644 index 97adcef..0000000 --- a/src/lib/components/ProjectLoader/CreateProject.svelte +++ /dev/null @@ -1,191 +0,0 @@ - - - -{#if projectLoading !== null} - newProject()} - /> -{/if} diff --git a/src/lib/components/ProjectLoader/LoadProject.svelte b/src/lib/components/ProjectLoader/LoadProject.svelte deleted file mode 100644 index e58c4a9..0000000 --- a/src/lib/components/ProjectLoader/LoadProject.svelte +++ /dev/null @@ -1,81 +0,0 @@ - - - diff --git a/src/lib/components/Tabs/MainTab/MainTab.svelte b/src/lib/components/Tabs/MainTab/MainTab.svelte index d38b6c7..76631f9 100644 --- a/src/lib/components/Tabs/MainTab/MainTab.svelte +++ b/src/lib/components/Tabs/MainTab/MainTab.svelte @@ -40,5 +40,5 @@
- +
diff --git a/src/lib/components/Tabs/store.ts b/src/lib/components/Tabs/store.ts index 0e40a73..afd0388 100644 --- a/src/lib/components/Tabs/store.ts +++ b/src/lib/components/Tabs/store.ts @@ -1,6 +1,6 @@ import { get } from 'svelte/store'; -import { persistedWritable } from '$lib/components/Utils/LocalStorage/persistedWritable'; +import { persistedWritable } from '@utils-client/store'; import type { TabInstance, TabsState } from './types'; @@ -10,6 +10,7 @@ const initialState: TabsState = { id: 'tab-main', type: 'main', title: 'Game', + metadata: {}, }, ], selectedTabId: 'tab-main', @@ -94,11 +95,11 @@ function createTabsStore() { tab: Omit & { id?: string }, ): Promise { const tabs = get({ subscribe }).tabs; - if (tab.file) { + if (tab.metadata?.path) { for (const t of tabs) { - if (!t.file) continue; + if (!t.metadata?.path) continue; - if (await t.file.isSameFile(tab.file)) { + if (t.metadata.path === tab.metadata.path) { return t; } } diff --git a/src/lib/components/Tabs/types.ts b/src/lib/components/Tabs/types.ts index 81c9ff8..6d86970 100644 --- a/src/lib/components/Tabs/types.ts +++ b/src/lib/components/Tabs/types.ts @@ -1,8 +1,6 @@ import type { Component } from 'svelte'; -import type { FileSystemFile } from '@utils-client/file-system'; - -export type TabTypeId = 'main' | 'ts' | '3d' | 'song'; +export type TabTypeId = 'main' | 'ts' | '3d' | 'song' | 'img' | 'unknown'; export interface Tab { id: TabTypeId; @@ -14,7 +12,9 @@ export interface TabInstance { id: string; type: TabTypeId; title: string; - file?: FileSystemFile; + metadata?: { + path?: string; + }; } export interface TabsState { diff --git a/src/lib/components/Utils/LocalStorage/ProjectCache.ts b/src/lib/components/Utils/LocalStorage/ProjectCache.ts deleted file mode 100644 index cf33d0b..0000000 --- a/src/lib/components/Utils/LocalStorage/ProjectCache.ts +++ /dev/null @@ -1,45 +0,0 @@ -export interface ProjectDataCache { - name: string; - path: string; - imageUrl: string; -} - -class ProjectCache { - private static storageKey = 'projects'; - - static getProjects(): Array { - const storedProjects = localStorage.getItem(this.storageKey); - if (storedProjects) { - return JSON.parse(storedProjects); - } - return []; - } - - static addProject(project: ProjectDataCache) { - const projects = this.getProjects(); - projects.push(project); - localStorage.setItem(this.storageKey, JSON.stringify(projects)); - } - - static removeProject(projectName: string) { - let projects = this.getProjects(); - projects = projects.filter((project) => project.name !== projectName); - localStorage.setItem(this.storageKey, JSON.stringify(projects)); - } - - static updateProject(updatedProject: ProjectDataCache) { - const projects = this.getProjects(); - const projectIndex = projects.findIndex((project) => project.name === updatedProject.name); - - if (projectIndex !== -1) { - projects[projectIndex] = updatedProject; - localStorage.setItem(this.storageKey, JSON.stringify(projects)); - } - } - - static clearProjects() { - localStorage.removeItem(this.storageKey); - } -} - -export default ProjectCache; diff --git a/src/lib/components/Utils/api/api.ts b/src/lib/components/Utils/api/api.ts deleted file mode 100644 index 222ba3c..0000000 --- a/src/lib/components/Utils/api/api.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { LocalAPI } from '$lib/components/Utils/api/local-api'; -import { NanoforgeApi } from '$lib/components/Utils/api/nanoforge-api'; - -export const localApi = new LocalAPI(); -export const nanoforgeApi = new NanoforgeApi(); diff --git a/src/lib/components/Utils/api/local-api.ts b/src/lib/components/Utils/api/local-api.ts deleted file mode 100644 index c856ecd..0000000 --- a/src/lib/components/Utils/api/local-api.ts +++ /dev/null @@ -1,260 +0,0 @@ -import type { EditorComponentManifest } from '@nanoforge-dev/ecs-lib'; - -import { deserialize } from '$app/forms'; - -import { type DirectoryRec, ProjectApi } from '$lib/components/Utils/api/project-api'; -import { env, save } from '$lib/components/Widget/EditorGame/game.svelte'; -import type { IManifest } from '$lib/loader/client/types/manifest.type'; -import type { Save } from '$lib/loader/client/types/save.type'; - -import { FileSystemDirectory } from '@utils-client/file-system'; -import { projectFileSystem } from '@utils-client/local-file-system/project-file-system'; - -export class LocalAPI extends ProjectApi { - async createProject(formData: FormData): Promise { - const resp = await fetch('/cli?/new', { - method: 'POST', - body: JSON.stringify(Object.fromEntries(formData.entries())), - }); - const result = deserialize(await resp.text()); - if (result.type !== 'success') { - if (result.type === 'failure' && result.data) throw new Error(result.data.errorMsg as string); - throw new Error('Failed to load remote project'); - } - } - - async loadProject(formData: FormData): Promise { - const loadResp = await fetch('/load-project?/loadProject', { - method: 'POST', - body: JSON.stringify({ projectPath: formData.get('projectPath') }), - }); - const loadResult = deserialize(await loadResp.text()); - if (loadResult.type !== 'success') { - if (loadResult.type === 'failure' && loadResult.data) - throw new Error(loadResult.data.errorMsg as string); - throw new Error('Failed to load remote project'); - } - } - async buildProject(): Promise { - await this._generateProject(); - const resp = await fetch('/cli?/build', { - method: 'POST', - body: JSON.stringify({}), - }); - const result = deserialize(await resp.text()); - if (result.type !== 'success') { - if (result.type === 'failure' && result.data) throw new Error(result.data.errorMsg as string); - throw new Error('Failed to start project'); - } - } - - async addComponent(componentName: string): Promise { - const resp = await fetch('/cli?/addComponent', { - method: 'POST', - body: JSON.stringify({ - componentName, - }), - }); - const result = deserialize(await resp.text()); - if (result.type !== 'success') { - if (result.type === 'failure' && result.data) throw new Error(result.data.errorMsg as string); - throw new Error('Failed to start project'); - } - } - - async fetchSave(side: 'client' | 'server'): Promise { - const res = await fetch(`/game-loader?/getSave`, { - method: 'POST', - body: JSON.stringify({ side }), - }); - - const saveResult = deserialize(await res.text()); - if (saveResult.type !== 'success' || !saveResult.data) { - if (saveResult.type === 'failure' && saveResult.data) - throw new Error(saveResult.data.errorMsg as string); - throw new Error('Failed to read remote directory'); - } - save.set(saveResult.data.save as Save); - } - - async updateSave(save: Save, side: 'client' | 'server'): Promise { - const res = await fetch(`/game-loader?/updateSave`, { - method: 'POST', - body: JSON.stringify({ save, side }), - }); - - const saveResult = deserialize(await res.text()); - if (saveResult.type !== 'success' || !saveResult.data) { - if (saveResult.type === 'failure' && saveResult.data) - throw new Error(saveResult.data.errorMsg as string); - throw new Error('Failed to update save'); - } - } - - async fetchEnv(side: 'client' | 'server'): Promise { - const res = await fetch(`/game-loader?/getEnv`, { - method: 'POST', - body: JSON.stringify({ side }), - }); - - const envResult = deserialize(await res.text()); - if (envResult.type !== 'success' || !envResult.data) { - if (envResult.type === 'failure' && envResult.data) - throw new Error(envResult.data.errorMsg as string); - throw new Error('Failed to read remote directory'); - } - env.set(envResult.data.env as Record); - } - - async getComponentManifest( - componentPath: string, - side: 'client' | 'server', - ): Promise { - const res = await fetch(`/game-loader?/getComponentManifest`, { - method: 'POST', - body: JSON.stringify({ side, componentPath }), - }); - const manifestResult = deserialize(await res.text()); - if (manifestResult.type !== 'success' || !manifestResult.data) { - if (manifestResult.type === 'failure' && manifestResult.data) - throw new Error(manifestResult.data.errorMsg as string); - throw new Error('Failed to read remote directory'); - } - return manifestResult.data.manifest as EditorComponentManifest; - } - - async getGameLoadManifest(side: 'client' | 'server'): Promise { - const res = await fetch(`/game-loader?/getManifest`, { - method: 'POST', - body: JSON.stringify({ side }), - }); - const manifestResult = deserialize(await res.text()); - if (manifestResult.type !== 'success' || !manifestResult.data) { - if (manifestResult.type === 'failure' && manifestResult.data) - throw new Error(manifestResult.data.errorMsg as string); - throw new Error('Failed to read remote directory'); - } - return manifestResult.data.manifest as IManifest; - } - - async getGameBuildFile( - filePath: string, - encoding: string, - side: 'client' | 'server', - ): Promise { - const res = await fetch('/game-loader?/getBuildFile', { - method: 'POST', - body: JSON.stringify({ - side, - filePath, - encoding, - }), - }); - const fileResult = deserialize(await res.text()); - if (fileResult.type !== 'success' || !fileResult.data) { - if (fileResult.type === 'failure' && fileResult.data) { - throw Error(fileResult.data.errorMsg as string); - } - throw Error('Failed to read remote directory'); - } - return fileResult.data.fileContent as string; - } - - async _generateProject(): Promise { - const resp = await fetch('/cli?/generate', { - method: 'POST', - body: JSON.stringify({}), - }); - const result = deserialize(await resp.text()); - if (result.type !== 'success') { - if (result.type === 'failure' && result.data) throw new Error(result.data.errorMsg as string); - throw new Error('Failed to stop project'); - } - } - - async uploadFiles(): Promise { - await this._uploadDirectoryRec(await projectFileSystem.getDirectory('/'), []); - } - - async downloadFiles(): Promise[]> { - const readDirResp = await fetch('/fs?/readDirRec', { - method: 'POST', - body: JSON.stringify({ dirPath: '/' }), - }); - - const readDirResult = deserialize(await readDirResp.text()); - - if (readDirResult.type !== 'success' || !readDirResult.data) { - if (readDirResult.type === 'failure' && readDirResult.data) - throw new Error(readDirResult.data.errorMsg as string); - throw new Error('Failed to read remote directory'); - } - - await projectFileSystem.clear(); - return this._downloadDirectoryRec(readDirResult.data.dirContent as DirectoryRec); - } - - private async _uploadDirectoryRec(directory: FileSystemDirectory, path: string[]): Promise { - const children = await directory.getChildren(); - - for (const [name, handle] of children) { - const childPath = [...path, name]; - - if (handle instanceof FileSystemDirectory) { - await this._uploadDirectoryRec(handle, childPath); - } else { - const content = await handle.read(); - - const formData = new FormData(); - formData.append('filePath', childPath.join('/')); - formData.append('fileContent', content); - - await fetch('/fs?/writeFile', { - method: 'POST', - body: JSON.stringify({ - filePath: formData.get('filePath'), - fileContent: formData.get('fileContent'), - }), - }); - } - } - } - - private async _downloadDirectoryRec( - dir: DirectoryRec, - currentPath: string = '', - ): Promise[]> { - const promises: Promise[] = []; - - for (const file of dir.files) { - const filePath = '/' + currentPath + file; - const filePromise = fetch('/fs?/readFile', { - method: 'POST', - body: JSON.stringify({ filePath: filePath }), - }).then(async (fileRes) => { - const fileResult = deserialize(await fileRes.text()); - if (fileResult.type === 'success' && fileResult.data) { - const file = await projectFileSystem.getFile(filePath, true); - await file.write(fileResult.data.fileContent as string); - } - }); - promises.push(filePromise); - } - - for (const [dirName, children] of Object.entries(dir.directories)) { - await projectFileSystem.getDirectory(currentPath + dirName, true); - if (dirName !== 'node_modules') { - const dirPromise: Promise = this._downloadDirectoryRec( - children, - currentPath + dirName + '/', - ).then((subDirPromises) => { - promises.push(...subDirPromises); - return; - }); - - promises.push(dirPromise); - } - } - return promises; - } -} diff --git a/src/lib/components/Utils/api/nanoforge-api.ts b/src/lib/components/Utils/api/nanoforge-api.ts deleted file mode 100644 index 60924b9..0000000 --- a/src/lib/components/Utils/api/nanoforge-api.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { RegistryComponentManifest } from '$lib/components/Entity/types'; - -export class NanoforgeApi { - async getRegistryComponentManifest(componentName: string): Promise { - const res = await fetch('https://api.nanoforge.eu/registry/' + componentName, { - method: 'GET', - }); - return (await res.json()) as RegistryComponentManifest; - } -} diff --git a/src/lib/components/Utils/api/project-api.ts b/src/lib/components/Utils/api/project-api.ts deleted file mode 100644 index 5ab09f0..0000000 --- a/src/lib/components/Utils/api/project-api.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface DirectoryRec { - files: string[]; - directories: Record; -} - -export abstract class ProjectApi { - abstract createProject(formData: FormData): Promise; - abstract loadProject(formData: FormData): Promise; - - abstract buildProject(): Promise; - - abstract uploadFiles(): Promise; - abstract downloadFiles(): Promise[]>; -} diff --git a/src/lib/components/Widget/CodeEditor/MonacoEditor.svelte b/src/lib/components/Widget/CodeEditor/MonacoEditor.svelte index 5f08aa6..2ffdcb7 100644 --- a/src/lib/components/Widget/CodeEditor/MonacoEditor.svelte +++ b/src/lib/components/Widget/CodeEditor/MonacoEditor.svelte @@ -1,20 +1,27 @@ - - diff --git a/src/lib/components/Widget/ContentBrowser/ContentBrowserListFolder.svelte b/src/lib/components/Widget/ContentBrowser/ContentBrowserListFolder.svelte deleted file mode 100644 index b5a06c4..0000000 --- a/src/lib/components/Widget/ContentBrowser/ContentBrowserListFolder.svelte +++ /dev/null @@ -1,83 +0,0 @@ - - - - -{#if open && childFolders.size > 0} - {#each childFolders as [childName, handle] (childName)} - - {/each} -{/if} diff --git a/src/lib/components/Widget/ContentBrowser/ContentBrowserWidget.svelte b/src/lib/components/Widget/ContentBrowser/ContentBrowserWidget.svelte deleted file mode 100644 index 2281366..0000000 --- a/src/lib/components/Widget/ContentBrowser/ContentBrowserWidget.svelte +++ /dev/null @@ -1,90 +0,0 @@ - - -
-
- {#if contents && rootDirectoryHandle} - {#each rootDirectoryChildren.entries().filter(isDirectory) as [name, handle] (name)} - - {/each} - {/if} -
-
-
- - {#each foldersParent as folder, index (folder)} - {#if index < foldersParent.length} - - {/if} - - {/each} -
-
-
- {#if contents} - {#each contents as [name, handle] (name)} - - {/each} - {/if} -
-
-
-
diff --git a/src/lib/components/Widget/ContentBrowser/store.ts b/src/lib/components/Widget/ContentBrowser/store.ts deleted file mode 100644 index 2477dd4..0000000 --- a/src/lib/components/Widget/ContentBrowser/store.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type Writable, writable } from 'svelte/store'; - -import type { FileSystemDirectory } from '@utils-client/file-system'; - -export const CurrentDirectory: Writable = writable(); diff --git a/src/lib/components/Widget/ContentBrowser/types.ts b/src/lib/components/Widget/ContentBrowser/types.ts deleted file mode 100644 index d5404db..0000000 --- a/src/lib/components/Widget/ContentBrowser/types.ts +++ /dev/null @@ -1,25 +0,0 @@ -export interface ContentBrowserItem { - id: string; - name: string; - type: string; - children?: ContentBrowserItem[]; -} - -export interface ContentBrowserItemType { - type: string; - suffix: string; - icon: string; -} - -export const contentBrowserItemType: ContentBrowserItemType[] = [ - { type: 'folder', suffix: '/', icon: 'i-material-icon-theme-folder-interceptor' }, - { - type: 'ts', - suffix: '.ts', - icon: 'i-material-icon-theme-typescript', - }, - { type: 'fbx', suffix: '.fbx', icon: 'i-material-icon-theme-3d' }, - { type: 'song', suffix: '.mp3', icon: 'i-material-icon-theme-lyric' }, - { type: 'json', suffix: '.json', icon: 'i-material-icon-theme-json' }, - { type: 'git', suffix: '.gitignore', icon: 'i-material-icon-theme-git' }, -]; diff --git a/src/lib/components/Widget/ECSTree/ECSTree.svelte b/src/lib/components/Widget/ECSTree/ECSTree.svelte index cdced49..6fa5e02 100644 --- a/src/lib/components/Widget/ECSTree/ECSTree.svelte +++ b/src/lib/components/Widget/ECSTree/ECSTree.svelte @@ -1,40 +1,30 @@
- {#if !loading} -
- - -
- Entities -
- {#each $save.entities as entity (entity.id)} +
+ + +
+ Entities +
+ {#if save.save} + {#each save.save.entities as entity (entity.id)} {/each} -
- {/if} + {/if} +
diff --git a/src/lib/components/Widget/ECSTree/EntityItem.svelte b/src/lib/components/Widget/ECSTree/EntityItem.svelte index bc9d38c..d34400f 100644 --- a/src/lib/components/Widget/ECSTree/EntityItem.svelte +++ b/src/lib/components/Widget/ECSTree/EntityItem.svelte @@ -1,6 +1,6 @@ @@ -104,14 +100,14 @@
- +
diff --git a/src/lib/components/Widget/EntityInspector/component-creator.ts b/src/lib/components/Widget/EntityInspector/component-creator.ts index 92e0f66..383e642 100644 --- a/src/lib/components/Widget/EntityInspector/component-creator.ts +++ b/src/lib/components/Widget/EntityInspector/component-creator.ts @@ -1,21 +1,22 @@ -import type { EditorComponentManifest } from '@nanoforge-dev/ecs-lib'; import { get } from 'svelte/store'; -import { localApi } from '$lib/components/Utils/api/api'; +import { useProject } from '$lib/client/project'; import { save } from '$lib/components/Widget/EditorGame/game.svelte'; -import type { SaveComponent } from '$lib/loader/client/types/save.type'; + +import type { SaveComponent } from '@utils/types'; export async function createDefaultComponent( componentName: string, - side: 'client' | 'server', ): Promise<[string, Record]> { const savedComponent: SaveComponent[] = get(save).components; const componentToCreate = savedComponent?.find((c) => c.name === componentName); if (!componentToCreate) throw Error(`Can't create ${componentName}: not found`); - const componentManifest: EditorComponentManifest = await localApi.getComponentManifest( - componentToCreate.path, - side, - ); + + const { packages } = useProject(); + + const componentManifest = packages.getComponentManifest(componentToCreate.path); + + if (!componentManifest) throw Error(`Can't create ${componentName}: not found`); const defaultParams: Record = {}; componentManifest.params.forEach((param) => { diff --git a/src/lib/components/Widget/content-browser/content-item.svelte b/src/lib/components/Widget/content-browser/content-item.svelte new file mode 100644 index 0000000..56bb25c --- /dev/null +++ b/src/lib/components/Widget/content-browser/content-item.svelte @@ -0,0 +1,58 @@ + + + + + diff --git a/src/lib/components/Widget/content-browser/content-list.svelte b/src/lib/components/Widget/content-browser/content-list.svelte new file mode 100644 index 0000000..6a7221f --- /dev/null +++ b/src/lib/components/Widget/content-browser/content-list.svelte @@ -0,0 +1,30 @@ + + +
+
+ {#each items as item (item.name)} + + {/each} +
+
diff --git a/src/lib/components/Widget/content-browser/header.svelte b/src/lib/components/Widget/content-browser/header.svelte new file mode 100644 index 0000000..fbcedd3 --- /dev/null +++ b/src/lib/components/Widget/content-browser/header.svelte @@ -0,0 +1,36 @@ + + +
+ + + {#each dirs as dir, i (i)} + + + + + {/each} + + + + + +
diff --git a/src/lib/components/Widget/content-browser/icon.svelte b/src/lib/components/Widget/content-browser/icon.svelte new file mode 100644 index 0000000..b415ff8 --- /dev/null +++ b/src/lib/components/Widget/content-browser/icon.svelte @@ -0,0 +1,38 @@ + + +{#if item.type === 'dir'} + +{:else} + +{/if} diff --git a/src/lib/components/Widget/content-browser/index.ts b/src/lib/components/Widget/content-browser/index.ts new file mode 100644 index 0000000..b13a238 --- /dev/null +++ b/src/lib/components/Widget/content-browser/index.ts @@ -0,0 +1,3 @@ +import Widget from './widget.svelte'; + +export { Widget, Widget as ContentBrowserWidget }; diff --git a/src/lib/components/Widget/content-browser/side-item.svelte b/src/lib/components/Widget/content-browser/side-item.svelte new file mode 100644 index 0000000..9ad3633 --- /dev/null +++ b/src/lib/components/Widget/content-browser/side-item.svelte @@ -0,0 +1,45 @@ + + + + +{#if open} + +{/if} diff --git a/src/lib/components/Widget/content-browser/side-list.svelte b/src/lib/components/Widget/content-browser/side-list.svelte new file mode 100644 index 0000000..8e2156b --- /dev/null +++ b/src/lib/components/Widget/content-browser/side-list.svelte @@ -0,0 +1,18 @@ + + +{#each items as item (getPath(item.name))} + +{/each} diff --git a/src/lib/components/Widget/content-browser/skeleton.svelte b/src/lib/components/Widget/content-browser/skeleton.svelte new file mode 100644 index 0000000..481d2cf --- /dev/null +++ b/src/lib/components/Widget/content-browser/skeleton.svelte @@ -0,0 +1,27 @@ + + +
+
+ {#each { length: 6 }, i (i)} + + {/each} +
+
+
+ + +
+
+
+ {#each { length: 12 }, i (i)} +
+ + +
+ {/each} +
+
+
+
diff --git a/src/lib/components/Widget/content-browser/store.ts b/src/lib/components/Widget/content-browser/store.ts new file mode 100644 index 0000000..b7ffc30 --- /dev/null +++ b/src/lib/components/Widget/content-browser/store.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const currentDir = writable(''); diff --git a/src/lib/components/Widget/content-browser/types.ts b/src/lib/components/Widget/content-browser/types.ts new file mode 100644 index 0000000..1bdf57d --- /dev/null +++ b/src/lib/components/Widget/content-browser/types.ts @@ -0,0 +1,14 @@ +export type ContentBrowserItem = ContentBrowserItemFile | ContentBrowserItemDir; + +export type ContentBrowserItemBase = { + name: string; +}; + +export type ContentBrowserItemFile = ContentBrowserItemBase & { + type: 'file'; +}; + +export type ContentBrowserItemDir = ContentBrowserItemBase & { + type: 'dir'; + children: ContentBrowserItem[]; +}; diff --git a/src/lib/components/Widget/content-browser/utils.ts b/src/lib/components/Widget/content-browser/utils.ts new file mode 100644 index 0000000..176fd48 --- /dev/null +++ b/src/lib/components/Widget/content-browser/utils.ts @@ -0,0 +1 @@ +export const joinPath = (path: string, name: string) => `${path ? `${path}/` : ''}${name}`; diff --git a/src/lib/components/Widget/content-browser/widget.svelte b/src/lib/components/Widget/content-browser/widget.svelte new file mode 100644 index 0000000..f72ad67 --- /dev/null +++ b/src/lib/components/Widget/content-browser/widget.svelte @@ -0,0 +1,49 @@ + + +{#if query.isFetched && !query.isLoading && query.data} +
+
+ i.type === 'dir')} /> +
+
+ + +
+
+{:else} + +{/if} diff --git a/src/lib/components/Widget/widgets.ts b/src/lib/components/Widget/widgets.ts index 1eac3ba..8f0630f 100644 --- a/src/lib/components/Widget/widgets.ts +++ b/src/lib/components/Widget/widgets.ts @@ -1,11 +1,11 @@ import type { Component } from 'svelte'; import MonacoEditor from './CodeEditor/MonacoEditor.svelte'; -import ContentBrowserWidget from './ContentBrowser/ContentBrowserWidget.svelte'; import ECSTreeWidget from './ECSTree/ECSTree.svelte'; import EditorGame from './EditorGame/EditorGame.svelte'; import EntityInspectorWidget from './EntityInspector/EntityInspectorWidget.svelte'; import OutputLogWidget from './OutputLog/OutputLogWidget.svelte'; +import { ContentBrowserWidget } from './content-browser'; export interface WidgetType { id: string; @@ -27,7 +27,7 @@ export const widgetsTypes: WidgetType[] = [ }, { id: 'code-editor', - component: MonacoEditor, + component: MonacoEditor as Component, }, { id: 'output-log', diff --git a/src/lib/components/demo/code-example.ts b/src/lib/components/demo/code-example.ts deleted file mode 100644 index c23a09f..0000000 --- a/src/lib/components/demo/code-example.ts +++ /dev/null @@ -1,82 +0,0 @@ -export const codeExample = `import { type Context } from "@nanoforge-dev/common"; -import { type Registry } from "@nanoforge-dev/ecs"; -import { type InputLibrary } from "@nanoforge-dev/input"; -import { type SoundLibrary } from "@nanoforge-dev/sound"; - -import { checkCollisions } from "./collisions"; -import { - Bounce, - CircleComponent, - Controller, - Hitbox, - Position, - RectangleComponent, - Velocity, -} from "./components"; - -export function move(registry: Registry) { - const entities = registry.getZipper([Bounce, Position, Velocity]); - - entities.forEach((entity) => { - entity.Position.x += entity.Velocity.x; - entity.Position.y += entity.Velocity.y; - }); -} - -export function bounce(registry: Registry, ctx: Context) { - const entities = registry.getZipper([Bounce, Position, Velocity]); - - entities.forEach((entity) => { - if (entity.Position.x >= 1800 || entity.Position.x <= 100) { - entity.Velocity.x = -entity.Velocity.x; - - ctx.libs.getSound().play("test"); - } - if (entity.Position.y >= 1000 || entity.Position.y <= 100) { - entity.Velocity.y = -entity.Velocity.y; - ctx.libs.getSound().play("test"); - } - }); -} - -export function controlPlayer(registry: Registry, ctx: Context) { - const entities = registry.getZipper([Controller, Position, Hitbox, Velocity]); - - entities.forEach((entity) => { - if ( - ctx.libs.getInput().isKeyPressed(entity.Controller.up) && - !checkCollisions(registry, entity) - ) { - entity.Position.y -= entity.Velocity.y; - } else { - entity.Position.y += entity.Velocity.y; - } - if ( - ctx.libs.getInput().isKeyPressed(entity.Controller.down) && - !checkCollisions(registry, entity) - ) { - entity.Position.y += entity.Velocity.y; - } else { - entity.Position.y -= entity.Velocity.y; - } - }); -} - -export function drawCircle(registry: Registry) { - const entities = registry.getZipper([CircleComponent, Position]); - - entities.forEach((entity) => { - const pos = entity.Position; - entity.CircleComponent.component.setPosition(pos); - }); -} - -export function moveRectangle(registry: Registry) { - const entities = registry.getZipper([RectangleComponent, Position, Hitbox]); - - entities.forEach((entity) => { - const pos = entity.Position; - (entity.RectangleComponent as RectangleComponent).component.setPosition(pos); - }); -} -`; diff --git a/src/lib/components/demo/entities.ts b/src/lib/components/demo/entities.ts deleted file mode 100644 index 2bc751e..0000000 --- a/src/lib/components/demo/entities.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { ContentBrowserItem } from '../Widget/ContentBrowser/types'; - -export const entities: ContentBrowserItem[] = [ - { - id: 'id1', - name: 'Content', - type: 'folder', - children: [ - { - id: 'id2', - name: 'JumpOut', - type: 'folder', - children: [ - { - id: 'id3', - name: 'Player', - type: 'folder', - children: [ - { - id: 'id4', - name: 'Meshes', - type: 'folder', - children: [ - { - id: 'id5', - name: 'Character.fbx', - type: 'fbx', - }, - ], - }, - { - id: 'id6', - name: 'Systems.ts', - type: 'ts', - }, - ], - }, - ], - }, - ], - }, -]; diff --git a/src/lib/components/forms/Form.svelte b/src/lib/components/forms/Form.svelte new file mode 100644 index 0000000..83bf0b4 --- /dev/null +++ b/src/lib/components/forms/Form.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children()} +
diff --git a/src/lib/components/forms/FormField.svelte b/src/lib/components/forms/FormField.svelte new file mode 100644 index 0000000..5cc30b2 --- /dev/null +++ b/src/lib/components/forms/FormField.svelte @@ -0,0 +1,40 @@ + + + + + {#snippet children({ props })} + {#if label} + {label} + {/if} + {@render fieldChildren({ props })} + {/snippet} + + {#if description} + {description} + {/if} + + diff --git a/src/lib/components/forms/form.svelte.ts b/src/lib/components/forms/form.svelte.ts new file mode 100644 index 0000000..9524b59 --- /dev/null +++ b/src/lib/components/forms/form.svelte.ts @@ -0,0 +1,28 @@ +import { type SuperForm, defaults, superForm } from 'sveltekit-superforms'; +import { zod4, zodClient } from 'sveltekit-superforms/adapters'; +import type { ZodType } from 'zod'; + +export const useForm = >(config: { + schema: ZodType; + defaultValues?: Partial; + onSubmit?: (values: T) => void | Promise; +}): SuperForm => { + const result = superForm(defaults(zod4(config.schema as any)), { + SPA: true, + validators: zodClient(config.schema as any), + resetForm: false, + onUpdate: async ({ form: f }) => { + if (f.valid) { + await config.onSubmit?.(f.data as T); + } + }, + }); + + if (config.defaultValues) { + result.form.update((v) => ({ ...v, ...config.defaultValues })); + } + + return result as unknown as SuperForm; +}; + +export type FormInstance = SuperForm; diff --git a/src/lib/components/forms/form.type.ts b/src/lib/components/forms/form.type.ts new file mode 100644 index 0000000..396b9e7 --- /dev/null +++ b/src/lib/components/forms/form.type.ts @@ -0,0 +1 @@ +export type { FormInstance } from './form.svelte'; diff --git a/src/lib/components/forms/inputs/FormFieldInput.svelte b/src/lib/components/forms/inputs/FormFieldInput.svelte new file mode 100644 index 0000000..f5a3f2d --- /dev/null +++ b/src/lib/components/forms/inputs/FormFieldInput.svelte @@ -0,0 +1,44 @@ + + + + {#snippet children({ props })} + form.update((v) => ({ ...v, [name]: e.currentTarget.value }))} + /> + {/snippet} + diff --git a/src/lib/components/forms/inputs/FormFieldMultiSelect.svelte b/src/lib/components/forms/inputs/FormFieldMultiSelect.svelte new file mode 100644 index 0000000..7b39f85 --- /dev/null +++ b/src/lib/components/forms/inputs/FormFieldMultiSelect.svelte @@ -0,0 +1,50 @@ + + + + {#snippet children({ props })} + form.update((s) => ({ ...s, [name]: v }))} + /> + {/snippet} + diff --git a/src/lib/components/forms/inputs/FormFieldSelect.svelte b/src/lib/components/forms/inputs/FormFieldSelect.svelte new file mode 100644 index 0000000..91c0437 --- /dev/null +++ b/src/lib/components/forms/inputs/FormFieldSelect.svelte @@ -0,0 +1,59 @@ + + + + {#snippet children({ props })} + form.update((s) => ({ ...s, [name]: v }))} + > + + {triggerContent} + + + {#each options as option (option.value)} + + {/each} + + + {/snippet} + diff --git a/src/lib/components/forms/inputs/FormFieldSwitch.svelte b/src/lib/components/forms/inputs/FormFieldSwitch.svelte new file mode 100644 index 0000000..7740886 --- /dev/null +++ b/src/lib/components/forms/inputs/FormFieldSwitch.svelte @@ -0,0 +1,30 @@ + + + + {#snippet children({ props })} + form.update((s) => ({ ...s, [name]: v }))} + /> + {/snippet} + diff --git a/src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte b/src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte new file mode 100644 index 0000000..9a7d759 --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte @@ -0,0 +1,23 @@ + + + diff --git a/src/lib/components/ui/breadcrumb/breadcrumb-item.svelte b/src/lib/components/ui/breadcrumb/breadcrumb-item.svelte new file mode 100644 index 0000000..4796081 --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb-item.svelte @@ -0,0 +1,20 @@ + + +
  • + {@render children?.()} +
  • diff --git a/src/lib/components/ui/breadcrumb/breadcrumb-link.svelte b/src/lib/components/ui/breadcrumb/breadcrumb-link.svelte new file mode 100644 index 0000000..1b79573 --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb-link.svelte @@ -0,0 +1,31 @@ + + +{#if child} + {@render child({ props: attrs })} +{:else} + + {@render children?.()} + +{/if} diff --git a/src/lib/components/ui/breadcrumb/breadcrumb-list.svelte b/src/lib/components/ui/breadcrumb/breadcrumb-list.svelte new file mode 100644 index 0000000..dbdbe7f --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb-list.svelte @@ -0,0 +1,23 @@ + + +
      + {@render children?.()} +
    diff --git a/src/lib/components/ui/breadcrumb/breadcrumb-page.svelte b/src/lib/components/ui/breadcrumb/breadcrumb-page.svelte new file mode 100644 index 0000000..505525a --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb-page.svelte @@ -0,0 +1,23 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte b/src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte new file mode 100644 index 0000000..4aca93f --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte @@ -0,0 +1,27 @@ + + + diff --git a/src/lib/components/ui/breadcrumb/breadcrumb.svelte b/src/lib/components/ui/breadcrumb/breadcrumb.svelte new file mode 100644 index 0000000..4e73537 --- /dev/null +++ b/src/lib/components/ui/breadcrumb/breadcrumb.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/lib/components/ui/breadcrumb/index.ts b/src/lib/components/ui/breadcrumb/index.ts new file mode 100644 index 0000000..f99a0da --- /dev/null +++ b/src/lib/components/ui/breadcrumb/index.ts @@ -0,0 +1,25 @@ +import Ellipsis from './breadcrumb-ellipsis.svelte'; +import Item from './breadcrumb-item.svelte'; +import Link from './breadcrumb-link.svelte'; +import List from './breadcrumb-list.svelte'; +import Page from './breadcrumb-page.svelte'; +import Separator from './breadcrumb-separator.svelte'; +import Root from './breadcrumb.svelte'; + +export { + Root, + Ellipsis, + Item, + Separator, + Link, + List, + Page, + // + Root as Breadcrumb, + Ellipsis as BreadcrumbEllipsis, + Item as BreadcrumbItem, + Separator as BreadcrumbSeparator, + Link as BreadcrumbLink, + List as BreadcrumbList, + Page as BreadcrumbPage, +}; diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte new file mode 100644 index 0000000..5a572e1 --- /dev/null +++ b/src/lib/components/ui/button/button.svelte @@ -0,0 +1,89 @@ + + + + +{#if href} + + {@render children?.()} + +{:else} + +{/if} diff --git a/src/lib/components/ui/button/index.ts b/src/lib/components/ui/button/index.ts new file mode 100644 index 0000000..66c1087 --- /dev/null +++ b/src/lib/components/ui/button/index.ts @@ -0,0 +1,17 @@ +import Root, { + type ButtonProps, + type ButtonSize, + type ButtonVariant, + buttonVariants, +} from './button.svelte'; + +export { + Root, + type ButtonProps as Props, + // + Root as Button, + buttonVariants, + type ButtonProps, + type ButtonSize, + type ButtonVariant, +}; diff --git a/src/lib/components/ui/card/card-action.svelte b/src/lib/components/ui/card/card-action.svelte new file mode 100644 index 0000000..c855d69 --- /dev/null +++ b/src/lib/components/ui/card/card-action.svelte @@ -0,0 +1,23 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/card/card-content.svelte b/src/lib/components/ui/card/card-content.svelte new file mode 100644 index 0000000..6ce47b9 --- /dev/null +++ b/src/lib/components/ui/card/card-content.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/card/card-description.svelte b/src/lib/components/ui/card/card-description.svelte new file mode 100644 index 0000000..7dd1425 --- /dev/null +++ b/src/lib/components/ui/card/card-description.svelte @@ -0,0 +1,20 @@ + + +

    + {@render children?.()} +

    diff --git a/src/lib/components/ui/card/card-footer.svelte b/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 0000000..ea19c66 --- /dev/null +++ b/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,23 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/card/card-header.svelte b/src/lib/components/ui/card/card-header.svelte new file mode 100644 index 0000000..5fa96c3 --- /dev/null +++ b/src/lib/components/ui/card/card-header.svelte @@ -0,0 +1,23 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/card/card-title.svelte b/src/lib/components/ui/card/card-title.svelte new file mode 100644 index 0000000..668c1e1 --- /dev/null +++ b/src/lib/components/ui/card/card-title.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/card/card.svelte b/src/lib/components/ui/card/card.svelte new file mode 100644 index 0000000..c0de4f9 --- /dev/null +++ b/src/lib/components/ui/card/card.svelte @@ -0,0 +1,25 @@ + + +
    img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col', + className, + )} + {...restProps} +> + {@render children?.()} +
    diff --git a/src/lib/components/ui/card/index.ts b/src/lib/components/ui/card/index.ts new file mode 100644 index 0000000..c721e71 --- /dev/null +++ b/src/lib/components/ui/card/index.ts @@ -0,0 +1,25 @@ +import Action from './card-action.svelte'; +import Content from './card-content.svelte'; +import Description from './card-description.svelte'; +import Footer from './card-footer.svelte'; +import Header from './card-header.svelte'; +import Title from './card-title.svelte'; +import Root from './card.svelte'; + +export { + Root, + Content, + Description, + Footer, + Header, + Title, + Action, + // + Root as Card, + Content as CardContent, + Description as CardDescription, + Footer as CardFooter, + Header as CardHeader, + Title as CardTitle, + Action as CardAction, +}; diff --git a/src/lib/components/ui/checkbox/checkbox.svelte b/src/lib/components/ui/checkbox/checkbox.svelte new file mode 100644 index 0000000..0921fbd --- /dev/null +++ b/src/lib/components/ui/checkbox/checkbox.svelte @@ -0,0 +1,39 @@ + + + + {#snippet children({ checked, indeterminate })} +
    + {#if checked} + + {:else if indeterminate} + + {/if} +
    + {/snippet} +
    diff --git a/src/lib/components/ui/checkbox/index.ts b/src/lib/components/ui/checkbox/index.ts new file mode 100644 index 0000000..f52cb02 --- /dev/null +++ b/src/lib/components/ui/checkbox/index.ts @@ -0,0 +1,7 @@ +import Root from './checkbox.svelte'; + +export { + Root, + // + Root as Checkbox, +}; diff --git a/src/lib/components/ui/dialog/dialog-close.svelte b/src/lib/components/ui/dialog/dialog-close.svelte new file mode 100644 index 0000000..2f313f6 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-close.svelte @@ -0,0 +1,11 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-content.svelte b/src/lib/components/ui/dialog/dialog-content.svelte new file mode 100644 index 0000000..788a1b1 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-content.svelte @@ -0,0 +1,48 @@ + + + + + + {@render children?.()} + {#if showCloseButton} + + {#snippet child({ props })} + + {/snippet} + + {/if} + + diff --git a/src/lib/components/ui/dialog/dialog-description.svelte b/src/lib/components/ui/dialog/dialog-description.svelte new file mode 100644 index 0000000..fbd49a6 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-description.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-footer.svelte b/src/lib/components/ui/dialog/dialog-footer.svelte new file mode 100644 index 0000000..5283c65 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-footer.svelte @@ -0,0 +1,35 @@ + + +
    + {@render children?.()} + {#if showCloseButton} + + {#snippet child({ props })} + + {/snippet} + + {/if} +
    diff --git a/src/lib/components/ui/dialog/dialog-header.svelte b/src/lib/components/ui/dialog/dialog-header.svelte new file mode 100644 index 0000000..2a53a7b --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-header.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/dialog/dialog-overlay.svelte b/src/lib/components/ui/dialog/dialog-overlay.svelte new file mode 100644 index 0000000..fc4c0d3 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-overlay.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-portal.svelte b/src/lib/components/ui/dialog/dialog-portal.svelte new file mode 100644 index 0000000..4a9048a --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-title.svelte b/src/lib/components/ui/dialog/dialog-title.svelte new file mode 100644 index 0000000..3ae932e --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-trigger.svelte b/src/lib/components/ui/dialog/dialog-trigger.svelte new file mode 100644 index 0000000..434c574 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-trigger.svelte @@ -0,0 +1,11 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog.svelte b/src/lib/components/ui/dialog/dialog.svelte new file mode 100644 index 0000000..88b4799 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/dialog/index.ts b/src/lib/components/ui/dialog/index.ts new file mode 100644 index 0000000..7dc204c --- /dev/null +++ b/src/lib/components/ui/dialog/index.ts @@ -0,0 +1,34 @@ +import Close from './dialog-close.svelte'; +import Content from './dialog-content.svelte'; +import Description from './dialog-description.svelte'; +import Footer from './dialog-footer.svelte'; +import Header from './dialog-header.svelte'; +import Overlay from './dialog-overlay.svelte'; +import Portal from './dialog-portal.svelte'; +import Title from './dialog-title.svelte'; +import Trigger from './dialog-trigger.svelte'; +import Root from './dialog.svelte'; + +export { + Root, + Title, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + Close, + // + Root as Dialog, + Title as DialogTitle, + Portal as DialogPortal, + Footer as DialogFooter, + Header as DialogHeader, + Trigger as DialogTrigger, + Overlay as DialogOverlay, + Content as DialogContent, + Description as DialogDescription, + Close as DialogClose, +}; diff --git a/src/lib/components/ui/form/form-button.svelte b/src/lib/components/ui/form/form-button.svelte new file mode 100644 index 0000000..48d9e1d --- /dev/null +++ b/src/lib/components/ui/form/form-button.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/multi-select/index.ts b/src/lib/components/ui/multi-select/index.ts new file mode 100644 index 0000000..cbd18dc --- /dev/null +++ b/src/lib/components/ui/multi-select/index.ts @@ -0,0 +1,7 @@ +import Root from './multi-select.svelte'; + +export { + Root, + // + Root as MultiSelect, +}; diff --git a/src/lib/components/ui/multi-select/multi-select.svelte b/src/lib/components/ui/multi-select/multi-select.svelte new file mode 100644 index 0000000..7f05f98 --- /dev/null +++ b/src/lib/components/ui/multi-select/multi-select.svelte @@ -0,0 +1,106 @@ + + + + + {selectedLabels} + + + + + + + + onValueChange?.(v)} + class="flex flex-col p-1" + > + {#each options as option (option.value)} + + {/each} + + + + diff --git a/src/lib/components/ui/select/index.ts b/src/lib/components/ui/select/index.ts new file mode 100644 index 0000000..06762f3 --- /dev/null +++ b/src/lib/components/ui/select/index.ts @@ -0,0 +1,37 @@ +import Content from './select-content.svelte'; +import GroupHeading from './select-group-heading.svelte'; +import Group from './select-group.svelte'; +import Item from './select-item.svelte'; +import Label from './select-label.svelte'; +import Portal from './select-portal.svelte'; +import ScrollDownButton from './select-scroll-down-button.svelte'; +import ScrollUpButton from './select-scroll-up-button.svelte'; +import Separator from './select-separator.svelte'; +import Trigger from './select-trigger.svelte'; +import Root from './select.svelte'; + +export { + Root, + Group, + Label, + Item, + Content, + Trigger, + Separator, + ScrollDownButton, + ScrollUpButton, + GroupHeading, + Portal, + // + Root as Select, + Group as SelectGroup, + Label as SelectLabel, + Item as SelectItem, + Content as SelectContent, + Trigger as SelectTrigger, + Separator as SelectSeparator, + ScrollDownButton as SelectScrollDownButton, + ScrollUpButton as SelectScrollUpButton, + GroupHeading as SelectGroupHeading, + Portal as SelectPortal, +}; diff --git a/src/lib/components/ui/select/select-content.svelte b/src/lib/components/ui/select/select-content.svelte new file mode 100644 index 0000000..ba64c87 --- /dev/null +++ b/src/lib/components/ui/select/select-content.svelte @@ -0,0 +1,44 @@ + + + + + + + {@render children?.()} + + + + diff --git a/src/lib/components/ui/select/select-group-heading.svelte b/src/lib/components/ui/select/select-group-heading.svelte new file mode 100644 index 0000000..f73f87d --- /dev/null +++ b/src/lib/components/ui/select/select-group-heading.svelte @@ -0,0 +1,21 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/ui/select/select-group.svelte b/src/lib/components/ui/select/select-group.svelte new file mode 100644 index 0000000..4f2e5b7 --- /dev/null +++ b/src/lib/components/ui/select/select-group.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/select/select-item.svelte b/src/lib/components/ui/select/select-item.svelte new file mode 100644 index 0000000..5217b07 --- /dev/null +++ b/src/lib/components/ui/select/select-item.svelte @@ -0,0 +1,38 @@ + + + + {#snippet children({ selected, highlighted })} + + {#if selected} + + {/if} + + {#if childrenProp} + {@render childrenProp({ selected, highlighted })} + {:else} + {label || value} + {/if} + {/snippet} + diff --git a/src/lib/components/ui/select/select-label.svelte b/src/lib/components/ui/select/select-label.svelte new file mode 100644 index 0000000..c1e803d --- /dev/null +++ b/src/lib/components/ui/select/select-label.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/src/lib/components/ui/select/select-portal.svelte b/src/lib/components/ui/select/select-portal.svelte new file mode 100644 index 0000000..fa48d6a --- /dev/null +++ b/src/lib/components/ui/select/select-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/select/select-scroll-down-button.svelte b/src/lib/components/ui/select/select-scroll-down-button.svelte new file mode 100644 index 0000000..5cbf4cc --- /dev/null +++ b/src/lib/components/ui/select/select-scroll-down-button.svelte @@ -0,0 +1,23 @@ + + + + + diff --git a/src/lib/components/ui/select/select-scroll-up-button.svelte b/src/lib/components/ui/select/select-scroll-up-button.svelte new file mode 100644 index 0000000..387ab53 --- /dev/null +++ b/src/lib/components/ui/select/select-scroll-up-button.svelte @@ -0,0 +1,23 @@ + + + + + diff --git a/src/lib/components/ui/select/select-separator.svelte b/src/lib/components/ui/select/select-separator.svelte new file mode 100644 index 0000000..edee1b3 --- /dev/null +++ b/src/lib/components/ui/select/select-separator.svelte @@ -0,0 +1,18 @@ + + + diff --git a/src/lib/components/ui/select/select-trigger.svelte b/src/lib/components/ui/select/select-trigger.svelte new file mode 100644 index 0000000..a97cc85 --- /dev/null +++ b/src/lib/components/ui/select/select-trigger.svelte @@ -0,0 +1,29 @@ + + + + {@render children?.()} + + diff --git a/src/lib/components/ui/select/select.svelte b/src/lib/components/ui/select/select.svelte new file mode 100644 index 0000000..ec122f3 --- /dev/null +++ b/src/lib/components/ui/select/select.svelte @@ -0,0 +1,11 @@ + + + diff --git a/src/lib/components/ui/separator/index.ts b/src/lib/components/ui/separator/index.ts new file mode 100644 index 0000000..56b2767 --- /dev/null +++ b/src/lib/components/ui/separator/index.ts @@ -0,0 +1,7 @@ +import Root from './separator.svelte'; + +export { + Root, + // + Root as Separator, +}; diff --git a/src/lib/components/ui/separator/separator.svelte b/src/lib/components/ui/separator/separator.svelte new file mode 100644 index 0000000..2b33e4a --- /dev/null +++ b/src/lib/components/ui/separator/separator.svelte @@ -0,0 +1,23 @@ + + + diff --git a/src/lib/components/ui/skeleton/index.ts b/src/lib/components/ui/skeleton/index.ts new file mode 100644 index 0000000..2d93ff2 --- /dev/null +++ b/src/lib/components/ui/skeleton/index.ts @@ -0,0 +1,7 @@ +import Root from './skeleton.svelte'; + +export { + Root, + // + Root as Skeleton, +}; diff --git a/src/lib/components/ui/skeleton/skeleton.svelte b/src/lib/components/ui/skeleton/skeleton.svelte new file mode 100644 index 0000000..efc306c --- /dev/null +++ b/src/lib/components/ui/skeleton/skeleton.svelte @@ -0,0 +1,17 @@ + + +
    diff --git a/src/lib/components/ui/sonner/index.ts b/src/lib/components/ui/sonner/index.ts new file mode 100644 index 0000000..fcaf06b --- /dev/null +++ b/src/lib/components/ui/sonner/index.ts @@ -0,0 +1 @@ +export { default as Toaster } from './sonner.svelte'; diff --git a/src/lib/components/ui/sonner/sonner.svelte b/src/lib/components/ui/sonner/sonner.svelte new file mode 100644 index 0000000..b7b685c --- /dev/null +++ b/src/lib/components/ui/sonner/sonner.svelte @@ -0,0 +1,34 @@ + + + + {#snippet loadingIcon()} + + {/snippet} + {#snippet successIcon()} + + {/snippet} + {#snippet errorIcon()} + + {/snippet} + {#snippet infoIcon()} + + {/snippet} + {#snippet warningIcon()} + + {/snippet} + diff --git a/src/lib/components/ui/spinner/index.ts b/src/lib/components/ui/spinner/index.ts new file mode 100644 index 0000000..2e459c6 --- /dev/null +++ b/src/lib/components/ui/spinner/index.ts @@ -0,0 +1 @@ +export { default as Spinner } from './spinner.svelte'; diff --git a/src/lib/components/ui/spinner/spinner.svelte b/src/lib/components/ui/spinner/spinner.svelte new file mode 100644 index 0000000..4dafbdb --- /dev/null +++ b/src/lib/components/ui/spinner/spinner.svelte @@ -0,0 +1,26 @@ + + + diff --git a/src/lib/components/ui/switch/index.ts b/src/lib/components/ui/switch/index.ts new file mode 100644 index 0000000..19be952 --- /dev/null +++ b/src/lib/components/ui/switch/index.ts @@ -0,0 +1,7 @@ +import Root from './switch.svelte'; + +export { + Root, + // + Root as Switch, +}; diff --git a/src/lib/components/ui/switch/switch.svelte b/src/lib/components/ui/switch/switch.svelte new file mode 100644 index 0000000..10826a9 --- /dev/null +++ b/src/lib/components/ui/switch/switch.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/src/lib/components/ui/tooltip-text/index.ts b/src/lib/components/ui/tooltip-text/index.ts new file mode 100644 index 0000000..0dd33a6 --- /dev/null +++ b/src/lib/components/ui/tooltip-text/index.ts @@ -0,0 +1,3 @@ +import TooltipText from './tooltip-text.svelte'; + +export { TooltipText }; diff --git a/src/lib/components/ui/tooltip-text/tooltip-text.svelte b/src/lib/components/ui/tooltip-text/tooltip-text.svelte new file mode 100644 index 0000000..4746c28 --- /dev/null +++ b/src/lib/components/ui/tooltip-text/tooltip-text.svelte @@ -0,0 +1,23 @@ + + + + + + {@render children()} + + +

    {text}

    +
    +
    +
    diff --git a/src/lib/components/ui/tooltip/index.ts b/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 0000000..ace2ed2 --- /dev/null +++ b/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,19 @@ +import Content from './tooltip-content.svelte'; +import Portal from './tooltip-portal.svelte'; +import Provider from './tooltip-provider.svelte'; +import Trigger from './tooltip-trigger.svelte'; +import Root from './tooltip.svelte'; + +export { + Root, + Trigger, + Content, + Provider, + Portal, + // + Root as Tooltip, + Content as TooltipContent, + Trigger as TooltipTrigger, + Provider as TooltipProvider, + Portal as TooltipPortal, +}; diff --git a/src/lib/components/ui/tooltip/tooltip-content.svelte b/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..ef7ecf6 --- /dev/null +++ b/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,52 @@ + + + + + {@render children?.()} + + {#snippet child({ props })} +
    + {/snippet} +
    +
    +
    diff --git a/src/lib/components/ui/tooltip/tooltip-portal.svelte b/src/lib/components/ui/tooltip/tooltip-portal.svelte new file mode 100644 index 0000000..7b9e8f9 --- /dev/null +++ b/src/lib/components/ui/tooltip/tooltip-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/tooltip/tooltip-provider.svelte b/src/lib/components/ui/tooltip/tooltip-provider.svelte new file mode 100644 index 0000000..49f8379 --- /dev/null +++ b/src/lib/components/ui/tooltip/tooltip-provider.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/tooltip/tooltip-trigger.svelte b/src/lib/components/ui/tooltip/tooltip-trigger.svelte new file mode 100644 index 0000000..b7640e4 --- /dev/null +++ b/src/lib/components/ui/tooltip/tooltip-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/tooltip/tooltip.svelte b/src/lib/components/ui/tooltip/tooltip.svelte new file mode 100644 index 0000000..42a939b --- /dev/null +++ b/src/lib/components/ui/tooltip/tooltip.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/tristate-switch/index.ts b/src/lib/components/ui/tristate-switch/index.ts new file mode 100644 index 0000000..9a93349 --- /dev/null +++ b/src/lib/components/ui/tristate-switch/index.ts @@ -0,0 +1,8 @@ +import Root, { type TriState } from './tristate-switch.svelte'; + +export { + Root, + // + type TriState, + Root as TristateSwitch, +}; diff --git a/src/lib/components/ui/tristate-switch/tristate-switch.svelte b/src/lib/components/ui/tristate-switch/tristate-switch.svelte new file mode 100644 index 0000000..e968d04 --- /dev/null +++ b/src/lib/components/ui/tristate-switch/tristate-switch.svelte @@ -0,0 +1,63 @@ + + + + + + + diff --git a/src/lib/loader/client/fetchGameProps.ts b/src/lib/loader/client/fetchGameProps.ts deleted file mode 100644 index cf2c162..0000000 --- a/src/lib/loader/client/fetchGameProps.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { localApi } from '$lib/components/Utils/api/api'; -import { fetchGameFiles, loadGameFiles } from '$lib/loader/client/gameFiles'; - -export async function fetchGameProps(): Promise[]> { - const manifest = localApi.getGameLoadManifest('client'); - const files = fetchGameFiles(await manifest); - const env = localApi.fetchEnv('client'); - const loadFiles = loadGameFiles(files); - return [manifest, ...files, env, ...loadFiles]; -} diff --git a/src/lib/loader/client/game.ts b/src/lib/loader/client/game.ts deleted file mode 100644 index 86a60d0..0000000 --- a/src/lib/loader/client/game.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { get } from 'svelte/store'; - -import { env, files, mainModule, save } from '$lib/components/Widget/EditorGame/game.svelte'; -import type { IGameOptions } from '$lib/loader/client/types/game.type'; - -import { EventEmitter } from '@utils-client/event-emitter'; - -export const coreEvents = new EventEmitter(); -export const editorEvents = new EventEmitter(); - -export const runGame = (canvas: HTMLCanvasElement) => { - if (!get(mainModule)) throw new Error('Could not find main function'); - - const gameOptions: IGameOptions = { - files: get(files), - env: get(env), - editor: { - save: get(save), - coreEvents: coreEvents, - editorEvents: editorEvents, - }, - canvas, - }; - get(mainModule).main(gameOptions); -}; diff --git a/src/lib/loader/client/gameFiles.ts b/src/lib/loader/client/gameFiles.ts deleted file mode 100644 index b6defa2..0000000 --- a/src/lib/loader/client/gameFiles.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { get } from 'svelte/store'; - -import { localApi } from '$lib/components/Utils/api/api'; -import { files, mainModule } from '$lib/components/Widget/EditorGame/game.svelte'; - -import { projectFileSystem } from '@utils-client/local-file-system/project-file-system'; - -import { type IExtendedManifestFile, type IManifest } from './types/manifest.type'; - -export function loadGameFiles(filesProm: Promise[]): Promise[] { - files.set(new Map()); - mainModule.set(undefined); - return filesProm.map(async (fileProm) => { - const file = await fileProm; - if (file.gamePath === '/main.js') { - const resModule = await loadScript(file); - if (resModule) mainModule.set(resModule); - return; - } - files.set(get(files).set(file.gamePath, file.localPath)); - }); -} - -const loadScript = async (file: IExtendedManifestFile): Promise => { - const res = await import(/* @vite-ignore */ file.localPath); - if (res['main']) return res; -}; - -export function fetchGameFiles(manifest: IManifest): Promise[] { - return manifest.files.map(async (filePath: string): Promise => { - const fileIsWasm = filePath.endsWith('.wasm'); - const fileContent = await localApi.getGameBuildFile( - filePath, - fileIsWasm ? 'base64' : 'utf8', - 'client', - ); - const browserPath = '/.nanoforge/client/' + filePath; - const gameDir = await projectFileSystem.getDirectory( - browserPath.substring(0, browserPath.lastIndexOf('/')), - true, - ); - const gameFile = await gameDir.getFile( - browserPath.substring(browserPath.lastIndexOf('/') + 1), - true, - ); - if (fileIsWasm) { - await gameFile.writeBinary(fileContent); - } else { - await gameFile.write(fileContent); - } - const localPath = await gameFile.getUrl(fileIsWasm ? 'application/wasm' : 'text/javascript'); - return { - gamePath: filePath, - localPath, - }; - }); -} diff --git a/src/lib/loader/client/types/event-emitter.type.ts b/src/lib/loader/client/types/event-emitter.type.ts deleted file mode 100644 index 7941327..0000000 --- a/src/lib/loader/client/types/event-emitter.type.ts +++ /dev/null @@ -1,27 +0,0 @@ -export enum EventTypeEnum { - HOT_RELOAD = 'hot-reload', - HARD_RELOAD = 'hard-reload', - PAUSE_GAME = 'pause-game', - STOP_GAME = 'stop-game', - UNPAUSE_GAME = 'unpause-game', -} - -export type ListenerType = (...args: any[]) => void; - -export interface IEventEmitter { - listeners: Record; - eventQueue: { event: EventTypeEnum | string; args: any[] }[]; - - runEvents: () => void; - - emitEvent: (event: EventTypeEnum, ...args: any) => void; - - addListener: (event: EventTypeEnum | string, listener: ListenerType) => void; - on: (event: EventTypeEnum | string, listener: ListenerType) => void; - - removeListener: (event: EventTypeEnum | string, listener: ListenerType) => void; - off: (event: EventTypeEnum | string, listener: ListenerType) => void; - - removeListenersForEvent: (event: EventTypeEnum | string) => void; - removeAllListeners: () => void; -} diff --git a/src/lib/loader/client/types/game.type.ts b/src/lib/loader/client/types/game.type.ts deleted file mode 100644 index 05ca448..0000000 --- a/src/lib/loader/client/types/game.type.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { IEventEmitter } from './event-emitter.type'; -import type { Save } from './save.type'; - -export interface IGameOptions { - canvas: HTMLCanvasElement; - files: Map; - env: Record; - editor: { - save: Save; - coreEvents: IEventEmitter; - editorEvents: IEventEmitter; - }; -} diff --git a/src/lib/loader/server/env.ts b/src/lib/loader/server/env.ts deleted file mode 100644 index 885e804..0000000 --- a/src/lib/loader/server/env.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { env } from '$env/dynamic/private'; - -const PREFIX_CLIENT = 'NANOFORGE_CLIENT_'; -const PREFIX_SERVER = 'NANOFORGE_SERVER_'; -const PREFIX = 'NANOFORGE_'; - -export const getGameEnv = (side: 'client' | 'server'): { [key: string]: string | undefined } => { - return Object.fromEntries( - Object.entries(env) - .map(([key, value]) => { - if (side === 'server' && key.startsWith(PREFIX_SERVER)) { - return [key.slice(PREFIX_SERVER.length), value]; - } else if (side === 'client' && key.startsWith(PREFIX_CLIENT)) { - return [key.slice(PREFIX_CLIENT.length), value]; - } else if (key.startsWith(PREFIX)) { - return [key.slice(PREFIX.length), value]; - } - return undefined; - }) - .filter((e) => e !== undefined), - ); -}; diff --git a/src/lib/loader/server/index.ts b/src/lib/loader/server/index.ts deleted file mode 100644 index 35856bd..0000000 --- a/src/lib/loader/server/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { getGameEnv } from './env'; diff --git a/src/lib/server/actions/project/fs/readdir.action.ts b/src/lib/server/actions/project/fs/readdir.action.ts new file mode 100644 index 0000000..b7814a6 --- /dev/null +++ b/src/lib/server/actions/project/fs/readdir.action.ts @@ -0,0 +1,13 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export class ReaddirFsBody { + path?: string; +} + +export const readdirFsAction = useActionHandler( + async ({ project, body }) => { + const dir = project.client.fs.getDirectory(body.path ?? ''); + return dir.read(true); + }, + { body: ReaddirFsBody }, +); diff --git a/src/lib/server/actions/project/gateway.action.ts b/src/lib/server/actions/project/gateway.action.ts new file mode 100644 index 0000000..c3ffc12 --- /dev/null +++ b/src/lib/server/actions/project/gateway.action.ts @@ -0,0 +1,18 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export interface GatewayProject { + name: string; + gatewayId: string; +} + +export const getGatewayProjectsAction = useActionHandler( + async ({ api }) => { + const projects = await api.projects.getProjects(); + + return projects.map((project) => ({ + gatewayId: project.id, + name: project.name, + })); + }, + { onlineOnly: true, projectOptional: true }, +); diff --git a/src/lib/server/actions/project/info.action.ts b/src/lib/server/actions/project/info.action.ts new file mode 100644 index 0000000..b26704e --- /dev/null +++ b/src/lib/server/actions/project/info.action.ts @@ -0,0 +1,34 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export interface InfoProject { + name: string; + language: 'ts' | 'js'; + hasServer: boolean; +} + +export class InfoProjectBody { + name?: string; +} + +export const getInfoProjectAction = useActionHandler(async ({ fs }) => { + const configFile = fs.getFile('nanoforge.config.json'); + const config = await configFile.readJson(); + + return { + name: config.name, + language: config.language, + hasServer: config.server?.enabled ?? false, + }; +}); + +export const setInfoProjectAction = useActionHandler( + async ({ body, fs }) => { + const configFile = fs.getFile('nanoforge.config.json'); + const config = await configFile.readJson(); + + if (body.name) config.name = body.name; + + configFile.writeJson(config); + }, + { body: InfoProjectBody }, +); diff --git a/src/lib/server/actions/project/load.action.ts b/src/lib/server/actions/project/load.action.ts new file mode 100644 index 0000000..604101d --- /dev/null +++ b/src/lib/server/actions/project/load.action.ts @@ -0,0 +1,86 @@ +import { join } from 'path'; + +import { loadProject } from '$lib/server/project'; +import { loadProjectFromId } from '$lib/server/project/load-project'; +import type { SessionProject } from '$lib/server/session'; + +import { Exception } from '@utils/exception'; + +import { type Handler, useActionHandler } from '@utils-server/request-handler'; + +export class LoadProjectBody { + id?: string; + path?: string; + gitUrl?: string; + gatewayId?: string; +} + +const resolveSessionFromGatewayId = async ( + gatewayId: string, + { api, git, context }: Handler, +): Promise => { + if (!context.online) + throw new Exception('Bad Request', 'Cannot load project from gatewayId while offline', 400); + + const project = await api.projects.getProject(gatewayId); + const basePath = await git.clone(project.gatewayProjectRegistryUrl, { + sshKey: project.gatewayProjectRegistryMetadata.sshKey, + }); + return { + path: join(basePath, project.gatewayProjectRegistryMetadata.dir ?? ''), + gateway: { id: gatewayId, sshKey: project.gatewayProjectRegistryMetadata.sshKey }, + }; +}; + +const resolveSessionFromGitUrl = async ( + gitUrl: string, + { git, context }: Handler, +): Promise => { + if (context.online) + throw new Exception('Bad Request', 'Cannot load project from gitUrl while online', 400); + + const path = await git.clone(gitUrl); + return { path }; +}; + +const resolveSessionFromPath = async ( + path: string, + { context }: Handler, +): Promise => { + if (context.online) + throw new Exception('Bad Request', 'Cannot load project from path while online', 400); + return { path }; +}; + +const resolveSessionFunctions: Record< + keyof Omit, + (el: string, options: Handler) => Promise +> = { + path: resolveSessionFromPath, + gitUrl: resolveSessionFromGitUrl, + gatewayId: resolveSessionFromGatewayId, +}; + +export const loadProjectAction = useActionHandler( + async (handler) => { + const { body } = handler; + + if (body.id) return await loadProjectFromId(body.id, handler); + + const el = Object.entries(body).find(([, value]) => value) as [ + keyof Omit, + string, + ]; + if (!el) throw new Exception('Bad Request', 'No load origin provided', 400); + + const resolveSessionFunction = resolveSessionFunctions[el[0]]; + + const project = await resolveSessionFunction(el[1], handler); + + return await loadProject(project, handler); + }, + { + projectOptional: true, + body: LoadProjectBody, + }, +); diff --git a/src/lib/server/actions/project/loader/build.action.ts b/src/lib/server/actions/project/loader/build.action.ts new file mode 100644 index 0000000..cfbeae3 --- /dev/null +++ b/src/lib/server/actions/project/loader/build.action.ts @@ -0,0 +1,6 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export const buildProjectAction = useActionHandler(async ({ cli }) => { + cli.generate({ editor: true }); + cli.build({ editor: true }); +}); diff --git a/src/lib/server/actions/project/loader/env.action.ts b/src/lib/server/actions/project/loader/env.action.ts new file mode 100644 index 0000000..adc11ef --- /dev/null +++ b/src/lib/server/actions/project/loader/env.action.ts @@ -0,0 +1,5 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export const fetchEnvLoaderAction = useActionHandler(async ({ project }) => { + return project.client.loader.getEnv(); +}); diff --git a/src/lib/server/actions/project/loader/manifest.action.ts b/src/lib/server/actions/project/loader/manifest.action.ts new file mode 100644 index 0000000..89fec5d --- /dev/null +++ b/src/lib/server/actions/project/loader/manifest.action.ts @@ -0,0 +1,5 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export const fetchManifestLoaderAction = useActionHandler(async ({ project }) => { + return project.client.loader.getManifest(); +}); diff --git a/src/lib/server/actions/project/new.action.ts b/src/lib/server/actions/project/new.action.ts new file mode 100644 index 0000000..172bb60 --- /dev/null +++ b/src/lib/server/actions/project/new.action.ts @@ -0,0 +1,43 @@ +import { join } from 'path'; + +import { loadProject } from '$lib/server/project'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class CreateProjectBody { + projectName!: string; + + projectPath?: string; + packageManager?: 'npm' | 'pnpm' | 'yarn' | 'bun'; + language?: 'js' | 'ts'; + multiplayerServer?: boolean; + dockerContainerization?: boolean; + createGitRepository?: boolean; + gitRemote?: string | false; +} + +export const createProjectAction = useActionHandler( + async (handler) => { + const { body, cli } = handler; + + cli.new({ + editor: true, + directory: body.projectPath || undefined, + name: body.projectName, + path: body.projectName, + packageManager: body.packageManager, + language: body.language, + server: body.multiplayerServer, + docker: body.dockerContainerization, + git: body.createGitRepository, + gitRemote: body.gitRemote, + }); + + return await loadProject({ path: join(body.projectPath ?? '', body.projectName) }, handler); + }, + { + body: CreateProjectBody, + offlineOnly: true, + projectOptional: true, + }, +); diff --git a/src/lib/server/actions/project/package/add-components.action.ts b/src/lib/server/actions/project/package/add-components.action.ts new file mode 100644 index 0000000..670c0e6 --- /dev/null +++ b/src/lib/server/actions/project/package/add-components.action.ts @@ -0,0 +1,20 @@ +import type { NewComponentPackage } from '$lib/server/project/package/package.type'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class AddComponentBody { + componentNames!: [string, ...string[]]; +} + +export const addComponentsProjectAction = useActionHandler( + async ({ body, project }): Promise => { + return await Promise.all( + body.componentNames.map((componentName) => + project.client.package.installComponent(componentName), + ), + ); + }, + { + body: AddComponentBody, + }, +); diff --git a/src/lib/server/actions/project/package/add-systems.action.ts b/src/lib/server/actions/project/package/add-systems.action.ts new file mode 100644 index 0000000..96a4e92 --- /dev/null +++ b/src/lib/server/actions/project/package/add-systems.action.ts @@ -0,0 +1,18 @@ +import type { NewSystemPackage } from '$lib/server/project/package/package.type'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class AddSystemBody { + systemNames!: [string, ...string[]]; +} + +export const addSystemsProjectAction = useActionHandler( + async ({ body, project }): Promise => { + return await Promise.all( + body.systemNames.map((systemName) => project.client.package.installSystem(systemName)), + ); + }, + { + body: AddSystemBody, + }, +); diff --git a/src/lib/server/actions/project/package/create-component.action.ts b/src/lib/server/actions/project/package/create-component.action.ts new file mode 100644 index 0000000..01adc91 --- /dev/null +++ b/src/lib/server/actions/project/package/create-component.action.ts @@ -0,0 +1,16 @@ +import type { NewComponentPackage } from '$lib/server/project/package/package.type'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class CreateComponentBody { + componentName!: string; +} + +export const createComponentProjectAction = useActionHandler( + async ({ body, project }): Promise => { + return project.client.package.createComponent(body.componentName); + }, + { + body: CreateComponentBody, + }, +); diff --git a/src/lib/server/actions/project/package/create-system.action.ts b/src/lib/server/actions/project/package/create-system.action.ts new file mode 100644 index 0000000..12c102d --- /dev/null +++ b/src/lib/server/actions/project/package/create-system.action.ts @@ -0,0 +1,16 @@ +import type { NewSystemPackage } from '$lib/server/project/package/package.type'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class CreateSystemBody { + systemName!: string; +} + +export const createSystemProjectAction = useActionHandler( + async ({ body, project }): Promise => { + return project.client.package.createSystem(body.systemName); + }, + { + body: CreateSystemBody, + }, +); diff --git a/src/lib/server/actions/project/package/get-components-manifests.action.ts b/src/lib/server/actions/project/package/get-components-manifests.action.ts new file mode 100644 index 0000000..679bded --- /dev/null +++ b/src/lib/server/actions/project/package/get-components-manifests.action.ts @@ -0,0 +1,18 @@ +import type { EditorComponentManifest } from '@nanoforge-dev/ecs-lib'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class GetComponentManifestBody { + componentPaths!: [string, ...string[]]; +} + +export const getComponentsManifestsAction = useActionHandler( + async ({ body, project }): Promise => { + return await Promise.all( + body.componentPaths.map((path) => project.client.package.getComponentManifest(path)), + ); + }, + { + body: GetComponentManifestBody, + }, +); diff --git a/src/lib/server/actions/project/package/get-systems-manifests.action.ts b/src/lib/server/actions/project/package/get-systems-manifests.action.ts new file mode 100644 index 0000000..78bbbdd --- /dev/null +++ b/src/lib/server/actions/project/package/get-systems-manifests.action.ts @@ -0,0 +1,18 @@ +import type { EditorSystemManifest } from '@nanoforge-dev/ecs-lib'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class GetSystemManifestBody { + systemPaths!: [string, ...string[]]; +} + +export const getSystemsManifestsAction = useActionHandler( + async ({ body, project }): Promise => { + return await Promise.all( + body.systemPaths.map((path) => project.client.package.getSystemManifest(path)), + ); + }, + { + body: GetSystemManifestBody, + }, +); diff --git a/src/lib/server/actions/project/save/get-save.action.ts b/src/lib/server/actions/project/save/get-save.action.ts new file mode 100644 index 0000000..a2c7748 --- /dev/null +++ b/src/lib/server/actions/project/save/get-save.action.ts @@ -0,0 +1,5 @@ +import { useActionHandler } from '@utils-server/request-handler'; + +export const getSaveAction = useActionHandler(async ({ project }) => { + return project.client.save.getSave(); +}); diff --git a/src/lib/server/actions/project/save/set-save.action.ts b/src/lib/server/actions/project/save/set-save.action.ts new file mode 100644 index 0000000..ee46390 --- /dev/null +++ b/src/lib/server/actions/project/save/set-save.action.ts @@ -0,0 +1,16 @@ +import { type Save } from '@utils/types'; + +import { useActionHandler } from '@utils-server/request-handler'; + +export class SetSaveBody { + save!: Save; +} + +export const setSaveAction = useActionHandler( + async ({ project, body }) => { + return project.client.save.updateSave(body.save); + }, + { + body: SetSaveBody, + }, +); diff --git a/src/lib/server/utils/server-api/repository.ts b/src/lib/server/api/base.repository.ts similarity index 56% rename from src/lib/server/utils/server-api/repository.ts rename to src/lib/server/api/base.repository.ts index 88a4f27..bd48cd9 100644 --- a/src/lib/server/utils/server-api/repository.ts +++ b/src/lib/server/api/base.repository.ts @@ -1,49 +1,62 @@ import type { HttpClient, RequestOptions } from '@utils/http'; -export class Repository { +type FullRequestOptions = RequestOptions & { offline?: boolean }; + +export class BaseRepository { private readonly _client: HttpClient; + private readonly _online: boolean; - constructor(client: HttpClient) { + constructor(client: HttpClient, online: boolean = true) { this._client = client; + this._online = online; } - get(path: string, options?: RequestOptions): Promise { + protected get(path: string, options?: FullRequestOptions): Promise { return this.runRequest('get', path, options); } - post( + protected post( path: string, body?: I, - options?: RequestOptions, + options?: FullRequestOptions, ): Promise { return this.runRequestBody('post', path, body, options); } - put( + protected put( path: string, body?: I, - options?: RequestOptions, + options?: FullRequestOptions, ): Promise { return this.runRequestBody('put', path, body, options); } - patch( + protected patch( path: string, body?: I, - options?: RequestOptions, + options?: FullRequestOptions, ): Promise { return this.runRequestBody('patch', path, body, options); } - delete(path: string, options?: RequestOptions): Promise { + protected delete( + path: string, + options?: FullRequestOptions, + ): Promise { return this.runRequest('delete', path, options); } + private assertOnline() { + if (!this._online) throw new Error('This route is only available in online mode'); + } + private async runRequest( request: 'get' | 'delete', path: string, - options?: RequestOptions, + options?: FullRequestOptions, ): Promise { + if (!options?.offline) this.assertOnline(); + const res = await this._client[request](path, options); if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { @@ -56,8 +69,10 @@ export class Repository { request: 'post' | 'put' | 'patch', path: string, body?: I, - options?: RequestOptions, + options?: FullRequestOptions, ): Promise { + if (!options?.offline) this.assertOnline(); + const res = await this._client[request]( path, body === undefined ? undefined : JSON.stringify(body), diff --git a/src/lib/server/api/client.ts b/src/lib/server/api/client.ts new file mode 100644 index 0000000..d92da89 --- /dev/null +++ b/src/lib/server/api/client.ts @@ -0,0 +1,48 @@ +import type { Cookies } from '@sveltejs/kit'; + +import { env } from '$env/dynamic/private'; + +import { HttpClient } from '@utils/http'; + +import { useTokenMiddleware } from './middlewares/refresh-token.middleware'; +import { AuthRepository } from './repositories/auth.repository'; +import { ProjectRepository } from './repositories/projects.repository'; +import { RegistryRepository } from './repositories/registry.repository'; + +export interface Api { + auth: AuthRepository; + projects: ProjectRepository; + registry: RegistryRepository; +} + +const DEFAULT_API_URL = 'https://api.nanoforge.eu'; + +export const getNoAuthApi = (): Api => { + const client = new HttpClient(env.API_URL ?? DEFAULT_API_URL, { + headers: { + 'Content-Type': 'application/json', + }, + }); + const isOnline = env.PUBLIC_MODE === 'ONLINE'; + + return { + auth: new AuthRepository(client, isOnline), + registry: new RegistryRepository(client, isOnline), + } as Api; +}; + +export const getApi = (cookies: Cookies): Api => { + if (env.PUBLIC_MODE !== 'ONLINE') throw new Error('API is only available in online mode'); + if (!env.API_KEY) throw new Error('API_KEY is not defined'); + const client = new HttpClient(env.API_URL ?? DEFAULT_API_URL, { + headers: { + 'Content-Type': 'application/json', + 'Api-Key': env.API_KEY, + }, + }).useMiddlewares(useTokenMiddleware(cookies)); + return { + auth: new AuthRepository(client), + projects: new ProjectRepository(client), + registry: new RegistryRepository(client), + }; +}; diff --git a/src/lib/server/api/index.ts b/src/lib/server/api/index.ts new file mode 100644 index 0000000..4c57d22 --- /dev/null +++ b/src/lib/server/api/index.ts @@ -0,0 +1,2 @@ +export { getApi, getNoAuthApi, type Api } from './client'; +export * from './types'; diff --git a/src/lib/server/api/middlewares/refresh-token.middleware.ts b/src/lib/server/api/middlewares/refresh-token.middleware.ts new file mode 100644 index 0000000..c3f1c79 --- /dev/null +++ b/src/lib/server/api/middlewares/refresh-token.middleware.ts @@ -0,0 +1,57 @@ +import type { Cookies } from '@sveltejs/kit'; + +import { Exception } from '@utils/exception'; +import type { MiddlewareNext, MiddlewareParams } from '@utils/http'; + +import { setTokensInCookies } from '@utils-server/cookies'; + +import { getNoAuthApi } from '../client'; + +const refreshToken = async (cookies: Cookies, force: boolean = false): Promise => { + let accessToken = force ? undefined : cookies.get('accessToken'); + const refreshToken = cookies.get('refreshToken'); + + if (!accessToken) { + if (!refreshToken) { + throw new Exception('Unauthorized', 'No token found', 401); + } + + try { + const tokens = await getNoAuthApi().auth.refreshToken({ + refreshToken, + }); + + setTokensInCookies(cookies, tokens); + accessToken = tokens.accessToken; + } catch { + throw new Exception('Unauthorized', 'Invalid refresh token', 401); + } + } + + return accessToken; +}; + +const getRequestParams = (params: MiddlewareParams, token: string): MiddlewareParams => ({ + ...params, + options: { + ...params.options, + headers: { + ...params.options.headers, + Authorization: `Bearer ${token}`, + }, + }, +}); + +export const useTokenMiddleware = (cookies: Cookies) => { + return async (params: MiddlewareParams, next: MiddlewareNext) => { + const accessToken = cookies.get('accessToken') ?? (await refreshToken(cookies)); + + const res = await next(getRequestParams(params, accessToken)); + + if (res.status === 401) { + const newAccessToken = await refreshToken(cookies, true); + return await next(getRequestParams(params, newAccessToken)); + } + return res; + }; +}; diff --git a/src/lib/server/api/repositories/auth.repository.ts b/src/lib/server/api/repositories/auth.repository.ts new file mode 100644 index 0000000..184be28 --- /dev/null +++ b/src/lib/server/api/repositories/auth.repository.ts @@ -0,0 +1,8 @@ +import { BaseRepository } from '../base.repository'; +import type { RefreshTokenInput, TokenResponse } from '../types'; + +export class AuthRepository extends BaseRepository { + refreshToken(input: RefreshTokenInput): Promise { + return this.post(`/auth/refresh-token`, input); + } +} diff --git a/src/lib/server/api/repositories/projects.repository.ts b/src/lib/server/api/repositories/projects.repository.ts new file mode 100644 index 0000000..01c6de6 --- /dev/null +++ b/src/lib/server/api/repositories/projects.repository.ts @@ -0,0 +1,12 @@ +import { BaseRepository } from '../base.repository'; +import type { ApiProject } from '../types'; + +export class ProjectRepository extends BaseRepository { + getProject(id: string): Promise { + return this.get(`/editor/projects/${id}`); + } + + getProjects(): Promise { + return this.get(`/projects}`); + } +} diff --git a/src/lib/server/api/repositories/registry.repository.ts b/src/lib/server/api/repositories/registry.repository.ts new file mode 100644 index 0000000..9aba34a --- /dev/null +++ b/src/lib/server/api/repositories/registry.repository.ts @@ -0,0 +1,8 @@ +import { BaseRepository } from '../base.repository'; +import type { RegistryPackageType } from '../types'; + +export class RegistryRepository extends BaseRepository { + getPackage(packageName: string): Promise { + return this.get(`/registry/${packageName}`, { offline: true }); + } +} diff --git a/src/lib/server/utils/server-api/types.ts b/src/lib/server/api/types/auth.type.ts similarity index 80% rename from src/lib/server/utils/server-api/types.ts rename to src/lib/server/api/types/auth.type.ts index 8bd14d9..1d77249 100644 --- a/src/lib/server/utils/server-api/types.ts +++ b/src/lib/server/api/types/auth.type.ts @@ -1,4 +1,4 @@ -export interface Token { +export interface TokenResponse { accessToken: string; refreshToken: string; tokenExpiresAt: string; diff --git a/src/lib/server/api/types/index.ts b/src/lib/server/api/types/index.ts new file mode 100644 index 0000000..24d88b4 --- /dev/null +++ b/src/lib/server/api/types/index.ts @@ -0,0 +1,3 @@ +export * from './auth.type'; +export * from './project.type'; +export * from './registry.type'; diff --git a/src/lib/server/api/types/project.type.ts b/src/lib/server/api/types/project.type.ts new file mode 100644 index 0000000..f842348 --- /dev/null +++ b/src/lib/server/api/types/project.type.ts @@ -0,0 +1,11 @@ +export interface ApiProject { + id: string; + code: string; + name: string; + description: string; + gatewayProjectRegistryUrl: string; + gatewayProjectRegistryMetadata: { + dir: string | null; + sshKey: string; + }; +} diff --git a/src/lib/server/api/types/registry.type.ts b/src/lib/server/api/types/registry.type.ts new file mode 100644 index 0000000..b90b67f --- /dev/null +++ b/src/lib/server/api/types/registry.type.ts @@ -0,0 +1,7 @@ +export interface RegistryPackageType { + name: string; + type: string; + description: string; + tags: string[]; + _file: string; +} diff --git a/src/lib/server/cli/cli-defaults.ts b/src/lib/server/cli/cli-defaults.ts new file mode 100644 index 0000000..360d7d5 --- /dev/null +++ b/src/lib/server/cli/cli-defaults.ts @@ -0,0 +1,34 @@ +import type { WithOptional } from '@utils/types/base.type'; + +import type { + CliBuildOptions, + CliCreateOptions, + CliDevOptions, + CliGenerateOptions, + CliInstallOptions, + CliNewOptions, + CliStartOptions, +} from './cli.type'; + +export const CLI_NEW_DEFAULTS: WithOptional = { + packageManager: 'npm', + language: 'ts', + strict: false, + server: false, + skipInstall: false, + docker: false, + git: false, + gitRemote: false, +}; + +export const CLI_INSTALL_DEFAULTS: WithOptional = {}; + +export const CLI_BUILD_DEFAULTS: WithOptional = {}; + +export const CLI_START_DEFAULTS: WithOptional = {}; + +export const CLI_DEV_DEFAULTS: WithOptional = {}; + +export const CLI_GENERATE_DEFAULTS: WithOptional = {}; + +export const CLI_CREATE_DEFAULTS: WithOptional = {}; diff --git a/src/lib/server/cli/cli-error.ts b/src/lib/server/cli/cli-error.ts new file mode 100644 index 0000000..96007be --- /dev/null +++ b/src/lib/server/cli/cli-error.ts @@ -0,0 +1,7 @@ +import { Exception } from '@utils/exception'; + +export class CliError extends Exception { + constructor(message: string) { + super('Internal Server Error', message, 500); + } +} diff --git a/src/lib/server/cli/cli.ts b/src/lib/server/cli/cli.ts new file mode 100644 index 0000000..67f8da6 --- /dev/null +++ b/src/lib/server/cli/cli.ts @@ -0,0 +1,192 @@ +import { env } from '$env/dynamic/private'; + +import { + CLI_BUILD_DEFAULTS, + CLI_CREATE_DEFAULTS, + CLI_DEV_DEFAULTS, + CLI_GENERATE_DEFAULTS, + CLI_INSTALL_DEFAULTS, + CLI_NEW_DEFAULTS, + CLI_START_DEFAULTS, +} from '$lib/server/cli/cli-defaults'; + +import { camelToKebab } from '@utils/format'; + +import type { Context } from '@utils-server/request-handler'; + +import { CliError } from './cli-error'; +import type { + CliBuildOptions, + CliCreateOptions, + CliDevOptions, + CliGenerateOptions, + CliInstallOptions, + CliNewOptions, + CliPartial, + CliRunOptions, + CliStartOptions, +} from './cli.type'; + +export class Cli { + private readonly _projectPath?: string; + + constructor(context: Context) { + this._projectPath = context.project?.path; + } + + new(opts: CliPartial, runOpts?: CliRunOptions): void { + return this.runCommand('new', [], { ...opts }, CLI_NEW_DEFAULTS, runOpts); + } + + install( + pkgs: [string, ...string[]], + opts: CliPartial, + runOpts?: CliRunOptions, + ): void { + this.assertProject(); + return this.runCommand( + 'install', + pkgs, + { ...opts, directory: this._projectPath }, + CLI_INSTALL_DEFAULTS, + runOpts, + ); + } + + build(opts: CliPartial, runOpts?: CliRunOptions): void { + this.assertProject(); + return this.runCommand( + 'build', + [], + { ...opts, directory: this._projectPath }, + CLI_BUILD_DEFAULTS, + runOpts, + ); + } + + start(opts: CliPartial, runOpts?: CliRunOptions): void { + this.assertProject(); + return this.runCommand( + 'start', + [], + { ...opts, directory: this._projectPath }, + CLI_START_DEFAULTS, + runOpts, + ); + } + + dev(opts: CliPartial, runOpts?: CliRunOptions): void { + this.assertProject(); + return this.runCommand( + 'dev', + [], + { ...opts, directory: this._projectPath }, + CLI_DEV_DEFAULTS, + runOpts, + ); + } + + generate(opts: CliPartial, runOpts?: CliRunOptions): void { + this.assertProject(); + return this.runCommand( + 'generate', + [], + { ...opts, directory: this._projectPath }, + CLI_GENERATE_DEFAULTS, + runOpts, + ); + } + + create( + part: 'component' | 'system', + opts: CliPartial, + runOpts?: CliRunOptions, + ): void { + this.assertProject(); + return this.runCommand( + 'create', + [part], + { ...opts, directory: this._projectPath }, + CLI_CREATE_DEFAULTS, + runOpts, + ); + } + + private runCommand( + command: string, + params: string[], + opts: Record, + defaultOpts: Record, + { async = false }: CliRunOptions = {}, + ): void { + const fullCommand = [ + env.NF_CLI_PATH ?? 'nf', + command, + ...params, + ...this.resolveParams(opts, defaultOpts), + ]; + + if (async) { + const res = Bun.spawn(fullCommand, { + stdout: 'pipe', + stderr: 'pipe', + cwd: env.FS_ROOT ?? undefined, + }); + res.exited.then((exitCode) => { + if (exitCode !== 0) { + console.log(res.stdout.toString()); + console.error(res.stderr.toString()); + throw new CliError(res.stderr.toString()); + } + }); + } else { + const res = Bun.spawnSync(fullCommand, { + stdout: 'pipe', + stderr: 'pipe', + cwd: env.FS_ROOT ?? undefined, + }); + + if (res.exitCode !== 0) { + console.log(res.stdout.toString()); + console.error(res.stderr.toString()); + throw new CliError(res.stderr.toString()); + } + } + } + + private mergeParams( + ...opts: Record[] + ): Record { + const merged: Record = {}; + for (const opt of opts) { + for (const [key, value] of Object.entries(opt)) { + if (value === undefined) continue; + merged[key] = value; + } + } + return merged; + } + + private resolveParams( + opts: Record, + defaultOpts: Record, + ): string[] { + const params = []; + for (const [key, value] of Object.entries(this.mergeParams(defaultOpts, opts))) { + const name = camelToKebab(key); + + if (typeof value === 'boolean') { + if (value) params.push(`--${name}`); + else params.push(`--no-${name}`); + } else { + params.push(`--${name}`, `${value}`); + } + } + return params; + } + + private assertProject() { + if (!this._projectPath) throw new CliError('No project path set'); + if (!Bun.file(this._projectPath).exists()) throw new CliError('Project does not exist'); + } +} diff --git a/src/lib/server/cli/cli.type.ts b/src/lib/server/cli/cli.type.ts new file mode 100644 index 0000000..4b805fc --- /dev/null +++ b/src/lib/server/cli/cli.type.ts @@ -0,0 +1,75 @@ +export type CliPartial = (T extends { directory?: string } + ? Omit, 'directory'> + : Partial) & + Pick; + +export interface CliRunOptions { + async?: boolean; +} + +export interface CliNewOptions { + directory?: string; + name: string; + path?: string; + packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun'; + language: 'js' | 'ts'; + strict: boolean; + server: boolean; + initFunctions?: boolean; + skipInstall: boolean; + docker: boolean; + lint?: false; + editor?: true; + git: boolean; + gitRemote: string | false; +} + +export interface CliInstallOptions { + directory?: string; + lib?: true; + server?: true; +} + +export interface CliBuildOptions { + directory?: string; + config?: string; + clientEntry?: string; + serverEntry?: string; + clientStaticDir?: string; + serverStaticDir?: string; + clientOutDir?: string; + serverOutDir?: string; + editor?: true; + watch?: true; +} + +export interface CliStartOptions { + directory?: string; + config?: string; + clientDir?: string; + serverDir?: string; + watch?: true; + cert?: string; + key?: string; +} + +export interface CliDevOptions { + directory?: string; + config?: string; + generate?: true; +} + +export interface CliGenerateOptions { + directory?: string; + config?: string; + editor?: true; + watch?: true; +} + +export interface CliCreateOptions { + directory?: string; + config?: string; + name: string; + server?: true; + path?: string; +} diff --git a/src/lib/server/cli/index.ts b/src/lib/server/cli/index.ts new file mode 100644 index 0000000..52a6764 --- /dev/null +++ b/src/lib/server/cli/index.ts @@ -0,0 +1 @@ +export { Cli } from './cli'; diff --git a/src/lib/server/file-system/file-system-error.ts b/src/lib/server/file-system/file-system-error.ts new file mode 100644 index 0000000..401ec2e --- /dev/null +++ b/src/lib/server/file-system/file-system-error.ts @@ -0,0 +1,7 @@ +import { Exception } from '@utils/exception'; + +export class FileSystemError extends Exception { + constructor(message: string) { + super('Bad Request', message, 400); + } +} diff --git a/src/lib/server/file-system/file-system.functions.ts b/src/lib/server/file-system/file-system.functions.ts new file mode 100644 index 0000000..1872317 --- /dev/null +++ b/src/lib/server/file-system/file-system.functions.ts @@ -0,0 +1,9 @@ +import { resolve } from 'path'; + +import { env } from '$env/dynamic/private'; + +export const resolveRootPath = (userPath: string) => { + const rootPath = resolve(env.FS_ROOT ?? ''); + + return resolve(rootPath, userPath); +}; diff --git a/src/lib/server/file-system/file-system.ts b/src/lib/server/file-system/file-system.ts new file mode 100644 index 0000000..cd4376b --- /dev/null +++ b/src/lib/server/file-system/file-system.ts @@ -0,0 +1,32 @@ +import { Exception } from '@utils/exception'; + +import type { Context } from '@utils-server/request-handler/context'; + +import { resolveRootPath } from './file-system.functions'; +import { ProjectDirectory } from './project-directory'; +import { ProjectFile } from './project-file'; + +export class FileSystem { + private readonly _rootPath: string; + + constructor(arg: string | Context) { + if (typeof arg === 'string') { + this._rootPath = resolveRootPath(arg); + return; + } + + if (!arg.project) { + throw new Exception('Bad Request', 'Project is not defined', 400); + } + + this._rootPath = resolveRootPath(arg.project.path); + } + + getDirectory(path: string) { + return new ProjectDirectory(path, this._rootPath); + } + + getFile(path: string) { + return new ProjectFile(path, this._rootPath); + } +} diff --git a/src/lib/server/file-system/index.ts b/src/lib/server/file-system/index.ts new file mode 100644 index 0000000..a4b242d --- /dev/null +++ b/src/lib/server/file-system/index.ts @@ -0,0 +1,3 @@ +export { FileSystem } from './file-system'; +export { directoryContentToFileEntries, type ProjectDirectory } from './project-directory'; +export { type ProjectFile } from './project-file'; diff --git a/src/lib/server/utils/file-system/project-directory.ts b/src/lib/server/file-system/project-directory.ts similarity index 88% rename from src/lib/server/utils/file-system/project-directory.ts rename to src/lib/server/file-system/project-directory.ts index 9da8337..3821cd9 100644 --- a/src/lib/server/utils/file-system/project-directory.ts +++ b/src/lib/server/file-system/project-directory.ts @@ -1,11 +1,11 @@ import fs from 'node:fs'; -import path from 'node:path'; +import { dirname, resolve } from 'path'; import { FileSystemError } from './file-system-error'; export type DirectoryContent = { files: string[]; - directories: { [key: string]: DirectoryContent }; + directories: Record; }; export function directoryContentToFileEntries( @@ -18,6 +18,7 @@ export function directoryContentToFileEntries( entries.push(basePath + '/' + file); }); Object.entries(directoryContent.directories).forEach(([path, dirContent]) => { + if (!dirContent) return; entries.push(...directoryContentToFileEntries(dirContent, basePath + '/' + path)); }); return entries; @@ -28,12 +29,13 @@ export class ProjectDirectory { private readonly projectPath: string; constructor(dirPath: string, projectPath: string) { - this.path = path.resolve(projectPath, './' + dirPath); + this.path = resolve(projectPath, './' + dirPath); this.projectPath = projectPath; + + this._checkPathIsInsideProject(); } read(recursive: boolean = false): DirectoryContent { - this._checkPathIsInsideProject(); this._checkPathExists(); this._checkPathIsDir(); this._checkPathIsReadable(); @@ -41,14 +43,12 @@ export class ProjectDirectory { } create(): void { - this._checkPathIsInsideProject(); this._checkPathNotExists(); fs.mkdirSync(this.path, { recursive: true }); } delete(recursive: boolean = false): void { - this._checkPathIsInsideProject(); this._checkPathExists(); this._checkPathIsDir(); if (!recursive) { @@ -58,13 +58,12 @@ export class ProjectDirectory { } rename(newPath: string): void { - const absoluteNewDirPath = path.resolve(this.projectPath, './' + newPath); - this._checkPathIsInsideProject(); + const absoluteNewDirPath = resolve(this.projectPath, './' + newPath); this._checkPathIsInsideProject(absoluteNewDirPath); this._checkPathExists(); this._checkPathIsDir(); this._checkPathIsWritable(); - const newFolderPath = path.dirname(absoluteNewDirPath); + const newFolderPath = dirname(absoluteNewDirPath); this._checkPathExists(newFolderPath); this._checkPathIsWritable(newFolderPath); this._checkPathNotExists(absoluteNewDirPath); @@ -72,6 +71,12 @@ export class ProjectDirectory { this.path = absoluteNewDirPath; } + assertExists() { + this._checkPathExists(); + this._checkPathIsDir(); + this._checkPathIsReadable(); + } + private _checkPathIsInsideProject(path: string = this.path) { if (!path.startsWith(this.projectPath)) { throw new FileSystemError(`Path ${path} is outside of the project directory`); @@ -125,7 +130,7 @@ export class ProjectDirectory { } private _readDirContent(path: string = this.path, recursive: boolean = false): DirectoryContent { - const dirContent: { files: string[]; directories: { [key: string]: any } } = { + const dirContent: DirectoryContent = { files: [], directories: {}, }; @@ -135,7 +140,7 @@ export class ProjectDirectory { } else if (item.isDirectory()) { dirContent.directories[item.name] = recursive ? this._readDirContent(path + '/' + item.name, recursive) - : {}; + : null; } }); return dirContent; diff --git a/src/lib/server/utils/file-system/project-file.ts b/src/lib/server/file-system/project-file.ts similarity index 85% rename from src/lib/server/utils/file-system/project-file.ts rename to src/lib/server/file-system/project-file.ts index 606dd60..a17e3c5 100644 --- a/src/lib/server/utils/file-system/project-file.ts +++ b/src/lib/server/file-system/project-file.ts @@ -10,10 +10,11 @@ export class ProjectFile { constructor(filePath: string, projectPath: string) { this._path = path.resolve(projectPath, './' + filePath); this.projectPath = projectPath; + + this._checkPathIsInsideProject(); } get path(): string { - this._checkPathIsInsideProject(); this._checkPathExists(); return this._path; } @@ -23,26 +24,19 @@ export class ProjectFile { return fs.readFileSync(this._path).toString(encoding); } + readStream(): ReadableStream { + this.isReadable(); + const file = Bun.file(this._path); + return file.stream(); + } + readJson(): T { const raw = this.read(); return JSON.parse(raw) as T; } write(text: string): void { - const folderPath = path.dirname(this._path); - this._checkPathIsInsideProject(); - try { - this._checkPathExists(); - this._checkPathIsFile(); - this._checkPathIsWritable(); - } catch { - fs.mkdirSync(folderPath, { recursive: true }); - fs.writeFileSync(this._path, text, { flush: true }); - return; - } - this._checkPathExists(folderPath); - this._checkPathIsDir(folderPath); - this._checkPathIsWritable(folderPath); + this._checkWritableAndCreateFolder(); fs.writeFileSync(this._path, text, { flush: true }); } @@ -51,8 +45,12 @@ export class ProjectFile { this.write(raw); } + getWriteStream(): fs.WriteStream { + this._checkWritableAndCreateFolder(); + return fs.createWriteStream(this._path); + } + delete(): void { - this._checkPathIsInsideProject(); this._checkPathExists(); this._checkPathIsFile(); this._checkPathIsWritable(); @@ -74,12 +72,28 @@ export class ProjectFile { } isReadable(): void { - this._checkPathIsInsideProject(); this._checkPathExists(); this._checkPathIsFile(); this._checkPathIsReadable(); } + private _checkWritableAndCreateFolder(): void { + const folderPath = path.dirname(this._path); + try { + this._checkPathExists(folderPath); + } catch { + fs.mkdirSync(folderPath, { recursive: true }); + } + if (fs.existsSync(this._path)) { + this._checkPathIsFile(); + this._checkPathIsWritable(); + } else { + this._checkPathExists(folderPath); + this._checkPathIsDir(folderPath); + this._checkPathIsWritable(folderPath); + } + } + private _checkPathIsInsideProject(path: string = this._path) { if (!path.startsWith(this.projectPath)) { throw new FileSystemError(`Path ${path} is outside of the project directory`); diff --git a/src/lib/server/git/git.ts b/src/lib/server/git/git.ts new file mode 100644 index 0000000..4583737 --- /dev/null +++ b/src/lib/server/git/git.ts @@ -0,0 +1,57 @@ +import { $ } from 'bun'; +import { resolve } from 'path'; + +import { env } from '$env/dynamic/private'; + +import { generateKey } from '@utils/string'; + +export class Git { + private readonly _rootPath: string; + + constructor() { + this._rootPath = resolve(env.FS_ROOT ?? ''); + } + + async clone(url: string, options?: { sshKey?: string }): Promise { + const path = await this.resolvePath(url); + await this.runCommand('clone', `${url} ${path}`, { ...options }); + return path; + } + + private async runCommand( + command: string, + params: string, + options?: { path?: string; sshKey?: string }, + ) { + let sshPath = undefined; + if (options?.sshKey) { + sshPath = await this.createSshKeyFile(options.sshKey); + } + const sshConfig = sshPath ? `-c core.sshCommand="ssh -i ${sshPath}" ` : ''; + const cwd = resolve(this._rootPath, options?.path ?? ''); + + await $`git ${command} ${sshConfig}${params}`.cwd(cwd); + if (sshPath) await this.deleteSshKeyFile(sshPath); + } + + private async createSshKeyFile(sshKey: string): Promise { + const path = `/tmp/nanoforge/${generateKey()}`; + await Bun.file(path).write(sshKey); + return path; + } + + private async deleteSshKeyFile(path: string): Promise { + await Bun.file(path).delete(); + } + + private async resolvePath(url: string) { + const basePath = url.split('/').pop()?.replace('.git', ''); + if (!basePath) throw new Error('Invalid URL'); + + const fullBasePath = resolve(this._rootPath, basePath); + let path = fullBasePath; + + while (await Bun.file(path).exists()) path = resolve(fullBasePath, generateKey(5)); + return path; + } +} diff --git a/src/lib/server/git/index.ts b/src/lib/server/git/index.ts new file mode 100644 index 0000000..3a6f073 --- /dev/null +++ b/src/lib/server/git/index.ts @@ -0,0 +1 @@ +export { Git } from './git'; diff --git a/src/lib/server/project/index.ts b/src/lib/server/project/index.ts new file mode 100644 index 0000000..1df00d0 --- /dev/null +++ b/src/lib/server/project/index.ts @@ -0,0 +1,4 @@ +export { loadProject } from './load-project'; +export type { Project } from './project.type'; +export { ProjectHandler } from './project-handler'; +export { ProjectManager } from './project-manager'; diff --git a/src/lib/server/project/load-project.ts b/src/lib/server/project/load-project.ts new file mode 100644 index 0000000..a387c8d --- /dev/null +++ b/src/lib/server/project/load-project.ts @@ -0,0 +1,53 @@ +import { + type SessionProject, + addProjectToSession, + getOrCreateSession, + tryAddProjectSession, +} from '$lib/server/session'; +import { getProject } from '$lib/server/session/project/project-functions'; + +import { Exception } from '@utils/exception'; + +import { type Handler } from '@utils-server/request-handler'; + +import type { Project } from './project.type'; + +export const loadProject = async ( + projectSession: SessionProject, + handler: Handler, +): Promise => { + // @todo remake this route and session system as it's set before the project is loaded + + const session = await getOrCreateSession(handler.event.locals.session); + const projectId = tryAddProjectSession(projectSession); + addProjectToSession(session, projectId); + + handler.context = { ...handler.context, project: projectSession }; + + return { + id: projectId, + cacheResolvable: handler.context.online + ? (projectSession.gateway?.id as string) + : projectSession.path, + }; +}; + +export const loadProjectFromId = async (id: string, handler: Handler): Promise => { + // @todo remake this route and session system as it's set before the project is loaded + + const session = await getOrCreateSession(handler.event.locals.session); + const projectSession = getProject(id, session); + + if (!projectSession) throw new Exception('Bad Request', 'Project not found', 400); + + addProjectToSession(session, id); + + handler.context = { ...handler.context, project: projectSession }; + + return { + id, + cacheResolvable: handler.context.online + ? (projectSession.gateway?.id as string) + : projectSession.path, + }; +}; diff --git a/src/lib/server/project/loader/env.ts b/src/lib/server/project/loader/env.ts new file mode 100644 index 0000000..c4834d0 --- /dev/null +++ b/src/lib/server/project/loader/env.ts @@ -0,0 +1,32 @@ +import { config } from 'dotenv'; +import { resolve } from 'path'; + +import type { Part } from '@utils/types'; + +const PREFIX_CLIENT = 'NANOFORGE_CLIENT_'; +const PREFIX_SERVER = 'NANOFORGE_SERVER_'; +const PREFIX = 'NANOFORGE_'; + +const loadEnv = (path: string): Record => { + const env = {}; + config({ path, processEnv: env }); + return env; +}; + +const parseEnv = (part: Part, env: Record): Record => { + const partPrefix = part === 'client' ? PREFIX_CLIENT : PREFIX_SERVER; + return Object.fromEntries( + Object.entries(env) + .filter( + ([key]) => + key.startsWith(PREFIX) && + ((part === 'client' && !key.startsWith(PREFIX_SERVER)) || + (part === 'server' && !key.startsWith(PREFIX_CLIENT))), + ) + .map(([key, value]) => [key.replace(new RegExp(`^${partPrefix}|${PREFIX}`), ''), value]), + ); +}; + +export const resolveEnv = (part: Part, projectPath: string) => { + return parseEnv(part, loadEnv(resolve(projectPath, '.env'))); +}; diff --git a/src/lib/server/project/loader/index.ts b/src/lib/server/project/loader/index.ts new file mode 100644 index 0000000..0223844 --- /dev/null +++ b/src/lib/server/project/loader/index.ts @@ -0,0 +1 @@ +export { Loader } from './loader'; diff --git a/src/lib/server/project/loader/loader.ts b/src/lib/server/project/loader/loader.ts new file mode 100644 index 0000000..2ec3b53 --- /dev/null +++ b/src/lib/server/project/loader/loader.ts @@ -0,0 +1,39 @@ +import { join } from 'path'; + +import { + FileSystem, + type ProjectFile, + directoryContentToFileEntries, +} from '$lib/server/file-system'; + +import { type ProjectHandler } from '../project-handler'; +import { resolveEnv } from './env'; +import type { Manifest } from './types'; + +export class Loader { + private readonly handler: ProjectHandler; + private readonly _fs: FileSystem; + private readonly _basePath: string; + + constructor(handler: ProjectHandler) { + this.handler = handler; + this._basePath = join(this.handler._path, '.nanoforge', this.handler._part); + this._fs = new FileSystem(this._basePath); + } + + getEnv(): Record { + return resolveEnv(this.handler._part, this.handler._path); + } + + getManifest(): Manifest { + const entries = directoryContentToFileEntries(this._fs.getDirectory('.').read(true)); + return { + version: '1.0.0', + files: entries.map((path) => ({ path })), + }; + } + + getFile(path: string): ProjectFile { + return this._fs.getFile(path); + } +} diff --git a/src/lib/server/project/loader/types.ts b/src/lib/server/project/loader/types.ts new file mode 100644 index 0000000..7973dea --- /dev/null +++ b/src/lib/server/project/loader/types.ts @@ -0,0 +1,4 @@ +export interface Manifest { + version: string; + files: { path: string }[]; +} diff --git a/src/lib/server/project/package/manifest-resolver.ts b/src/lib/server/project/package/manifest-resolver.ts new file mode 100644 index 0000000..74f666e --- /dev/null +++ b/src/lib/server/project/package/manifest-resolver.ts @@ -0,0 +1,67 @@ +import ts, { type Expression, type ObjectLiteralElementLike } from 'typescript'; + +import { PackageTypeEnum } from './package.type'; + +export const MANIFEST_TITLES = { + [PackageTypeEnum.COMPONENT]: 'EDITOR_COMPONENT_MANIFEST', + [PackageTypeEnum.SYSTEM]: 'EDITOR_SYSTEM_MANIFEST', +} as const; + +const findManifestNode = (title: string, source: ts.SourceFile): ts.VariableDeclaration | null => { + let res = null; + source.forEachChild((node) => { + if (!ts.isVariableStatement(node)) return; + node.declarationList.declarations.forEach((decl) => { + if (!ts.isVariableDeclaration(decl)) return; + if (decl.name.getText() === title) res = decl; + }); + }); + return res; +}; + +const parseProperty = (prop: ObjectLiteralElementLike): any => { + if (!ts.isPropertyAssignment(prop)) return {}; + + const name = prop.name.getText(); + const value = prop.initializer; + if (!value) return {}; + + return { [name]: parseElement(value) }; +}; + +const parseElement = (value: Expression): any => { + if (ts.isStringLiteral(value)) return value.text; + if (ts.isNumericLiteral(value)) return Number(value.text); + if (ts.isLiteralTypeLiteral(value)) { + const txt = value.getText(); + if (txt === 'true') return true; + if (txt === 'false') return false; + if (txt === 'null') return null; + if (txt === 'undefined') return undefined; + } + if (ts.isArrayLiteralExpression(value)) return value.elements.map((el) => parseElement(el)); + if (ts.isObjectLiteralExpression(value)) + return value.properties.reduce((acc, prop) => { + return { ...acc, ...parseProperty(prop) }; + }, {}); + throw new Error('Unknown element type'); +}; + +const getManifestFromNode = (source: ts.VariableDeclaration | null): any | null => { + if (!source) return null; + + const init = source.initializer; + if (!init) return null; + if (!ts.isObjectLiteralExpression(init)) return null; + + return parseElement(init); +}; + +const parseManifest = (title: string, source: ts.SourceFile): any | null => { + return getManifestFromNode(findManifestNode(title, source)); +}; + +export const resolveManifest = (type: PackageTypeEnum, content: string): any | null => { + const source = ts.createSourceFile('tmp.ts', content, ts.ScriptTarget.ESNext, true); + return parseManifest(MANIFEST_TITLES[type], source); +}; diff --git a/src/lib/server/project/package/package-handler.ts b/src/lib/server/project/package/package-handler.ts new file mode 100644 index 0000000..4ec20ed --- /dev/null +++ b/src/lib/server/project/package/package-handler.ts @@ -0,0 +1,139 @@ +import type { EditorComponentManifest, EditorSystemManifest } from '@nanoforge-dev/ecs-lib'; +import { join } from 'path'; + +import { FileSystemError } from '$lib/server/file-system/file-system-error'; +import { type ProjectHandler } from '$lib/server/project'; + +import { toCamelCase, toKebabCase, toPascalCase } from '@utils/format'; + +import { resolveManifest } from './manifest-resolver'; +import { type NewComponentPackage, type NewSystemPackage, PackageTypeEnum } from './package.type'; + +export class PackageHandler { + private readonly handler: ProjectHandler; + + constructor(handler: ProjectHandler) { + this.handler = handler; + } + + async installComponent(name: string): Promise { + const rc = await this.handler._api.registry.getPackage(name); + if (rc.type !== 'component') throw new Error(`Can only add component: ${name} is a ${rc.type}`); + this.handler._cli.install([name], { server: this.handler._part === 'server' || undefined }); + + return this._getNewComponentPackage(rc.name, rc._file); + } + + async installSystem(name: string): Promise { + const rs = await this.handler._api.registry.getPackage(name); + if (rs.type !== 'system') throw new Error(`Can only add system: ${name} is a ${rs.type}`); + this.handler._cli.install([name], { server: this.handler._part === 'server' || undefined }); + + return this._getNewSystemPackage(rs.name, rs._file); + } + + /** + * Create a new component in the project + * @beta function to be reworked + * + * @param {string} name - Name of the component + */ + createComponent(name: string): NewComponentPackage { + this._createPackage(PackageTypeEnum.COMPONENT, name); + return this._getNewComponentPackage( + toPascalCase(name) + 'Component', + toKebabCase(name) + '.component', + ); + } + + /** + * Create a new system in the project and update the save file + * @beta function to be reworked + * + * @param {string} name - Name of the system + */ + createSystem(name: string): NewSystemPackage { + this._createPackage(PackageTypeEnum.SYSTEM, name); + return this._getNewSystemPackage(toCamelCase(name) + 'System', toKebabCase(name) + '.system'); + } + + /** + * Get the manifest of the component + * @beta function to be reworked + * + * @param {string} path - Path from `/` + * + * @returns Manifest of the component + */ + getComponentManifest(path: string): EditorComponentManifest { + return this._getPackageManifest(PackageTypeEnum.COMPONENT, path); + } + + /** + * Get the manifest of the system + * @beta function to be reworked + * + * @param {string} path - Path from `/` + * + * @returns Manifest of the system + */ + getSystemManifest(path: string): EditorSystemManifest { + return this._getPackageManifest(PackageTypeEnum.SYSTEM, path); + } + + private _getNewComponentPackage(name: string, fileName: string): NewComponentPackage { + const path = `./components/${fileName}`; + + const manifest = this._findPackageManifest(this.getComponentManifest, path); + + return { + manifest, + save: { + name, + path, + paramsNames: manifest.params.map(({ name }) => name), + }, + }; + } + + private _getNewSystemPackage(name: string, fileName: string): NewSystemPackage { + const path = `./systems/${fileName}`; + return { + manifest: this._findPackageManifest(this.getSystemManifest, path), + save: { name, path }, + }; + } + + private _findPackageManifest(manifestGetter: (path: string) => T, path: string): T { + const manifest = ['', '.ts', '.js'].reduce((result: T | undefined, p) => { + if (result) return result; + + try { + return manifestGetter(path + p); + } catch (e) { + if (!(e instanceof FileSystemError)) throw e; + } + }, undefined); + + if (!manifest) { + throw new FileSystemError("Can't find package manifest"); + } + return manifest; + } + + private _createPackage(type: PackageTypeEnum, name: string): void { + this.handler._cli.create(type, { + name, + server: this.handler._part === 'server' || undefined, + }); + } + + private _getPackageManifest(type: PackageTypeEnum, path: string): any { + const content = this.handler._rootFs.getFile(this._resolvePartPath(path)).read(); + return resolveManifest(type, content); + } + + private _resolvePartPath(path: string): string { + return join(this.handler._part, path); + } +} diff --git a/src/lib/server/project/package/package.type.ts b/src/lib/server/project/package/package.type.ts new file mode 100644 index 0000000..ce231b2 --- /dev/null +++ b/src/lib/server/project/package/package.type.ts @@ -0,0 +1,18 @@ +import type { EditorComponentManifest, EditorSystemManifest } from '@nanoforge-dev/ecs-lib'; + +import type { SaveComponent, SaveSystem } from '@utils/types'; + +export enum PackageTypeEnum { + COMPONENT = 'component', + SYSTEM = 'system', +} + +export interface NewComponentPackage { + manifest: EditorComponentManifest; + save: SaveComponent; +} + +export interface NewSystemPackage { + manifest: EditorSystemManifest; + save: SaveSystem; +} diff --git a/src/lib/server/project/project-handler.ts b/src/lib/server/project/project-handler.ts new file mode 100644 index 0000000..f5af6fd --- /dev/null +++ b/src/lib/server/project/project-handler.ts @@ -0,0 +1,63 @@ +import { join } from 'path'; + +import { type Api } from '$lib/server/api'; +import { type Cli } from '$lib/server/cli'; +import { FileSystem } from '$lib/server/file-system'; + +import { Exception } from '@utils/exception'; +import type { Part } from '@utils/types'; + +import { type Context, type Handler } from '@utils-server/request-handler'; + +import { Loader } from './loader'; +import { PackageHandler } from './package/package-handler'; +import { SaveHandler } from './save/save-handler'; + +export class ProjectHandler { + public readonly _path: string; + public readonly _part: Part; + public readonly _cli: Cli; + public readonly _api: Api; + public readonly _rootFs: FileSystem; + + private _fs: FileSystem | undefined; + private _loader: Loader | undefined; + private _save: SaveHandler | undefined; + private _package: PackageHandler | undefined; + + constructor(handler: Handler, context: Context, part: Part) { + if (!context.project) throw new Exception('Bad Request', 'Project missing in context', 400); + this._path = context.project.path; + this._part = part; + this._cli = handler.cli; + this._api = handler.api; + this._rootFs = handler.fs; + } + + /** + * Get the file system of the project content + * This file system has his root at / + */ + get fs(): FileSystem { + if (!this._fs) this._fs = new FileSystem(join(this._path, this._part)); + return this._fs; + } + + /** + * Get the loader functions of the project + */ + get loader(): Loader { + if (!this._loader) this._loader = new Loader(this); + return this._loader; + } + + get save(): SaveHandler { + if (!this._save) this._save = new SaveHandler(this); + return this._save; + } + + get package(): PackageHandler { + if (!this._package) this._package = new PackageHandler(this); + return this._package; + } +} diff --git a/src/lib/server/project/project-manager.ts b/src/lib/server/project/project-manager.ts new file mode 100644 index 0000000..4edb79d --- /dev/null +++ b/src/lib/server/project/project-manager.ts @@ -0,0 +1,34 @@ +import { ProjectHandler } from '$lib/server/project/project-handler'; + +import type { Context, Handler } from '@utils-server/request-handler'; + +export class ProjectManager { + private readonly _handler: Handler; + private readonly _context: Context; + + private _client: ProjectHandler | undefined; + private _server: ProjectHandler | undefined; + + constructor(handler: Handler, context: Context) { + this._handler = handler; + this._context = context; + } + + /** + * Get the client project handler + * @beta The separation between client and server projects is not the final goal of the project manager. + */ + get client(): ProjectHandler { + if (!this._client) this._client = new ProjectHandler(this._handler, this._context, 'client'); + return this._client; + } + + /** + * Get the server project handler + * @beta The separation between client and server projects is not the final goal of the project manager. + */ + get server(): ProjectHandler { + if (!this._server) this._server = new ProjectHandler(this._handler, this._context, 'server'); + return this._server; + } +} diff --git a/src/lib/server/project/project.type.ts b/src/lib/server/project/project.type.ts new file mode 100644 index 0000000..d1324d0 --- /dev/null +++ b/src/lib/server/project/project.type.ts @@ -0,0 +1,4 @@ +export interface Project { + id: string; + cacheResolvable: string; +} diff --git a/src/lib/server/project/save/save-handler.ts b/src/lib/server/project/save/save-handler.ts new file mode 100644 index 0000000..53af39b --- /dev/null +++ b/src/lib/server/project/save/save-handler.ts @@ -0,0 +1,23 @@ +import { type ProjectHandler } from '$lib/server/project'; + +import type { Save } from '@utils/types'; + +export class SaveHandler { + private readonly handler: ProjectHandler; + + constructor(handler: ProjectHandler) { + this.handler = handler; + } + + async getSave(): Promise { + return this.handler._rootFs.getFile(this.resolveSavePath()).readJson(); + } + + async updateSave(save: Save): Promise { + this.handler._rootFs.getFile(this.resolveSavePath()).writeJson(save); + } + + private resolveSavePath(): string { + return `.nanoforge/${this.handler._part}.save.json`; + } +} diff --git a/src/lib/server/session/index.ts b/src/lib/server/session/index.ts new file mode 100644 index 0000000..6be6a3a --- /dev/null +++ b/src/lib/server/session/index.ts @@ -0,0 +1,5 @@ +export * from './session-handle'; +export { resolveSession, addProjectToSession, getOrCreateSession } from './session-functions'; +export type { Session } from './session.type'; +export { resolveProject, tryAddProjectSession } from './project/project-functions'; +export type { SessionProject } from './project/project.type'; diff --git a/src/lib/server/session/project/project-functions.ts b/src/lib/server/session/project/project-functions.ts new file mode 100644 index 0000000..85a511e --- /dev/null +++ b/src/lib/server/session/project/project-functions.ts @@ -0,0 +1,35 @@ +import { SESSION_PROJECT_HEADER } from '@utils/const'; +import { generateKey } from '@utils/string'; + +import type { Session } from '../session.type'; +import { projectStore } from './project.store'; +import type { SessionProject } from './project.type'; + +export const projectExists = (id: string | null | undefined) => { + return !!id && projectStore.has(id); +}; + +export const hasRightToAccessProject = (id: string | null | undefined, session: Session) => { + return projectExists(id) && session.projects.includes(id as string); +}; + +export const resolveProject = (headers: Headers, session: Session) => { + if (!session) return null; + if (!session.projects.length) return null; + + const id = headers.get(SESSION_PROJECT_HEADER); + return getProject(id, session); +}; + +export const getProject = (id: string | null, session: Session) => { + if (!hasRightToAccessProject(id, session)) return null; + + return projectStore.get(id as string) ?? null; +}; + +export const tryAddProjectSession = (session: SessionProject): string => { + let id = generateKey(10); + while (projectStore.has(id)) id = generateKey(10); + projectStore.set(id, session); + return id; +}; diff --git a/src/lib/server/session/project/project.store.ts b/src/lib/server/session/project/project.store.ts new file mode 100644 index 0000000..1563222 --- /dev/null +++ b/src/lib/server/session/project/project.store.ts @@ -0,0 +1,3 @@ +import type { SessionProject } from '$lib/server/session/project/project.type'; + +export const projectStore = new Map(); diff --git a/src/lib/server/session/project/project.type.ts b/src/lib/server/session/project/project.type.ts new file mode 100644 index 0000000..6d0a5cb --- /dev/null +++ b/src/lib/server/session/project/project.type.ts @@ -0,0 +1,7 @@ +export interface SessionProject { + path: string; + gateway?: { + id: string; + sshKey: string; + }; +} diff --git a/src/lib/server/session/session-functions.ts b/src/lib/server/session/session-functions.ts new file mode 100644 index 0000000..c6d6285 --- /dev/null +++ b/src/lib/server/session/session-functions.ts @@ -0,0 +1,52 @@ +import { type Session as SvelteSession } from 'svelte-kit-sessions'; + +import { Exception } from '@utils/exception'; +import { generateKey } from '@utils/string'; + +import { PUBLIC_PATHS } from './session.const'; +import { sessionStore } from './session.store'; +import type { Session } from './session.type'; + +export const isPublicPath = (url: URL) => { + return PUBLIC_PATHS.includes(url.pathname) || url.pathname.startsWith('/actions'); +}; + +export const resolveSession = async (sessionHandler: SvelteSession): Promise => { + const id = sessionHandler.data.id; + + if (!id) return null; + + if (!sessionStore.has(id)) { + await resetSession(sessionHandler); + throw new Exception('Bad Request', 'Invalid session', 400); + } + return sessionStore.get(id) as Session; +}; + +export const isSessionExist = (id: string) => sessionStore.has(id); + +export const resetSession = (sessionHandler: SvelteSession): Promise => { + return sessionHandler.destroy(); +}; + +export const addProjectToSession = (session: Session, projectId: string): void => { + if (!sessionStore.has(session.id)) { + throw new Exception('Bad Request', 'Invalid session', 400); + } + + sessionStore.set(session.id, { + ...session, + projects: Array.from(new Set([...session.projects, projectId]).values()), + }); +}; + +export const getOrCreateSession = async (sessionHandler: SvelteSession): Promise => { + const session = await resolveSession(sessionHandler); + if (session) return session; + + const id = generateKey(10); + sessionStore.set(id, { id, projects: [] }); + await sessionHandler.setData({ id }); + await sessionHandler.save(); + return sessionStore.get(id) as Session; +}; diff --git a/src/lib/server/session/session-handle.ts b/src/lib/server/session/session-handle.ts new file mode 100644 index 0000000..b6a3593 --- /dev/null +++ b/src/lib/server/session/session-handle.ts @@ -0,0 +1,24 @@ +import { type Handle, redirect } from '@sveltejs/kit'; +import { sveltekitSessionHandle } from 'svelte-kit-sessions'; + +import { env } from '$env/dynamic/private'; + +import { generateKey } from '@utils/string'; + +import { isPublicPath, isSessionExist, resetSession } from './session-functions'; + +export const sessionHandle = sveltekitSessionHandle({ + secret: env.SESSION_SECRET || generateKey(), +}); + +export const checkAuthorizationHandle: Handle = async ({ event, resolve }) => { + const sessionData = event.locals.session.data; + + if (isPublicPath(event.url)) return resolve(event); + + if (!isSessionExist(sessionData.id)) { + await resetSession(event.locals.session); + throw redirect(302, '/'); + } + return resolve(event); +}; diff --git a/src/lib/server/session/session.const.ts b/src/lib/server/session/session.const.ts new file mode 100644 index 0000000..fda8772 --- /dev/null +++ b/src/lib/server/session/session.const.ts @@ -0,0 +1 @@ +export const PUBLIC_PATHS = ['/', '/load']; diff --git a/src/lib/server/session/session.store.ts b/src/lib/server/session/session.store.ts new file mode 100644 index 0000000..d38664c --- /dev/null +++ b/src/lib/server/session/session.store.ts @@ -0,0 +1,3 @@ +import type { Session } from './session.type'; + +export const sessionStore = new Map(); diff --git a/src/lib/server/session/session.type.ts b/src/lib/server/session/session.type.ts new file mode 100644 index 0000000..f1e09ff --- /dev/null +++ b/src/lib/server/session/session.type.ts @@ -0,0 +1,4 @@ +export interface Session { + id: string; + projects: string[]; +} diff --git a/src/lib/server/utils/cli/cli-error.ts b/src/lib/server/utils/cli/cli-error.ts deleted file mode 100644 index 834113b..0000000 --- a/src/lib/server/utils/cli/cli-error.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class CliError extends Error { - message: string; - constructor(message: string) { - super(); - this.message = message; - } -} diff --git a/src/lib/server/utils/cli/cli-interface.ts b/src/lib/server/utils/cli/cli-interface.ts deleted file mode 100644 index d46f481..0000000 --- a/src/lib/server/utils/cli/cli-interface.ts +++ /dev/null @@ -1,99 +0,0 @@ -import child_process from 'node:child_process'; - -import { env } from '$env/dynamic/private'; - -import { CliError } from '@utils-server/cli/cli-error'; - -export class CliInterface { - private readonly projectPath: string; - - constructor(projectPath: string) { - this.projectPath = projectPath; - } - - new( - projectName: string, - packageManager: 'npm' | 'yarn' | 'pnpm' | 'bun', - language: 'js' | 'ts', - strictTypeChecking?: boolean, - multiplayerServer?: boolean, - dockerContainerization?: boolean, - generateLintFiles?: boolean, - editor?: boolean, - createGitRepository?: boolean, - gitRemote?: string, - ) { - this._runCliSync([ - `new`, - `-d`, - this.projectPath, - `--name`, - projectName, - `--package-manager`, - packageManager, - `--language`, - language, - strictTypeChecking ? '--strict' : '--no-strict', - multiplayerServer ? '--server' : '--no-server', - '--init-functions', - '--no-skip-install', - dockerContainerization ? '--docker' : '--no-docker', - generateLintFiles ? undefined : '--no-lint', - editor ? '--editor' : undefined, - createGitRepository ? '--git' : '--no-git', - gitRemote ? '--git-remote' : '--no-git-remote', - gitRemote, - ]); - } - - build(editor?: boolean) { - this._runCliSync(['build', `-d`, this.projectPath, editor ? '--editor' : undefined]); - } - - generate(editor?: boolean) { - this._runCliSync(['generate', `-d`, this.projectPath, editor ? '--editor' : undefined]); - } - - addComponent(componentName: string) { - this._runCliSync(['add', `-d`, this.projectPath, componentName]); - } - - private _runCliSync(params: (string | undefined)[]) { - const res = child_process.spawnSync( - env.NF_CLI_PATH, - params.filter((e) => e !== undefined), - ); - if (res.status === null) { - throw new CliError(`Executable ${env.NF_CLI_PATH} cannot be found or executed`); - } - if (res.status !== 0) { - console.log(res.stdout.toString()); - console.error(res.stderr.toString()); - throw new CliError(res.stderr.toString()); - } - } - - private _runCliAsync(params: string[]): number { - const res = child_process.spawn(env.NF_CLI_PATH, params); - - const startTime = Date.now(); - while (res.pid === undefined && Date.now() - startTime < 100) { - /* if I remove this comment the linter is crying */ - } - if (res.pid === undefined) { - throw new CliError('Failed to start process: pid not available'); - } - - res.on('error', () => { - throw new CliError(res.stderr.toString()); - }); - res.on('exit', (code) => { - if (code !== 0 && code !== null) { - console.log(res.stdout.read()?.toString()); - console.log(res.stderr.read()?.toString()); - throw new CliError(`Process exited with code ${code}`); - } - }); - return res.pid; - } -} diff --git a/src/lib/server/utils/server-api/utils.ts b/src/lib/server/utils/cookies/index.ts similarity index 58% rename from src/lib/server/utils/server-api/utils.ts rename to src/lib/server/utils/cookies/index.ts index de635f4..2c4e110 100644 --- a/src/lib/server/utils/server-api/utils.ts +++ b/src/lib/server/utils/cookies/index.ts @@ -1,12 +1,12 @@ -import type { Cookies, RequestEvent } from '@sveltejs/kit'; +import type { Cookies } from '@sveltejs/kit'; import { env } from '$env/dynamic/private'; -import type { Token } from './types'; +import type { TokenResponse } from '$lib/server/api'; export const setTokensInCookies = ( cookies: Cookies, - { accessToken, refreshToken, tokenExpiresAt }: Token, + { accessToken, refreshToken, tokenExpiresAt }: TokenResponse, ) => { cookies.set('accessToken', accessToken, { httpOnly: true, @@ -24,10 +24,3 @@ export const setTokensInCookies = ( maxAge: 60 * 60 * 24 * 30, // 30 days }); }; - -export const resetTokensInCookies = (event: RequestEvent) => { - const { cookies } = event; - - cookies.delete('accessToken', { path: '/' }); - cookies.delete('refreshToken', { path: '/' }); -}; diff --git a/src/lib/server/utils/file-system/file-system-error.ts b/src/lib/server/utils/file-system/file-system-error.ts deleted file mode 100644 index 00de3d5..0000000 --- a/src/lib/server/utils/file-system/file-system-error.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class FileSystemError extends Error { - message: string; - constructor(message: string) { - super(); - this.message = message; - } -} diff --git a/src/lib/server/utils/request-handler/action-handler.ts b/src/lib/server/utils/request-handler/action-handler.ts new file mode 100644 index 0000000..46216fc --- /dev/null +++ b/src/lib/server/utils/request-handler/action-handler.ts @@ -0,0 +1,38 @@ +import { type Action, type ActionFailure, fail } from '@sveltejs/kit'; + +import { Exception } from '@utils/exception'; + +import { parseFormDataBody } from './body'; +import { getContext } from './context'; +import { Handler } from './handler'; +import { assertRequest } from './request.policy'; +import type { Callback, RequestHandlerOptions } from './types'; + +const handleError = (e: unknown): ActionFailure<{ error: string; message: unknown }> => { + console.error(e); + if (e instanceof Exception) { + return fail(e.status, { error: e.error, message: e.message }); + } + return fail(500, { error: 'Internal Server Error', message: (e as any).toString() }); +}; + +export const useActionHandler = ( + callback: Callback, + options?: RequestHandlerOptions, +): Action => { + return async (event) => { + try { + const context = await getContext(event); + + const body = parseFormDataBody(await event.request.formData(), options?.body); + + assertRequest(context, options); + + const handler = new Handler(context, event, body); + + return await callback(handler); + } catch (e) { + return handleError(e); + } + }; +}; diff --git a/src/lib/server/utils/request-handler/body.ts b/src/lib/server/utils/request-handler/body.ts new file mode 100644 index 0000000..5c67287 --- /dev/null +++ b/src/lib/server/utils/request-handler/body.ts @@ -0,0 +1,17 @@ +import type { ClassType } from '@utils/types'; + +export const parseFormDataBody = ( + rawBody: FormData, + c: ClassType | undefined, +): Body => { + const baseBody = Object.fromEntries( + Array.from(rawBody.entries()).map(([key, value]) => [key, JSON.parse(value)]), + ); + return parseBody(baseBody, c); +}; + +export const parseBody = (baseBody: any, c: ClassType | undefined): Body => { + // @todo add class validation and class transformation + void c; + return baseBody as Body; +}; diff --git a/src/lib/server/utils/request-handler/context.ts b/src/lib/server/utils/request-handler/context.ts new file mode 100644 index 0000000..2163d91 --- /dev/null +++ b/src/lib/server/utils/request-handler/context.ts @@ -0,0 +1,27 @@ +import type { RequestEvent } from '@sveltejs/kit'; + +import { env } from '$env/dynamic/private'; + +import { + type Session, + type SessionProject, + resolveProject, + resolveSession, +} from '$lib/server/session'; + +export interface Context { + online: boolean; + session: Session; + project: SessionProject; +} + +export const getContext = async (event: RequestEvent): Promise => { + const session = (await resolveSession(event.locals.session)) as Session; + const project = resolveProject(event.request.headers, session) as SessionProject; + + return { + online: env.PUBLIC_MODE === 'ONLINE', + session, + project, + }; +}; diff --git a/src/lib/server/utils/request-handler/handler.ts b/src/lib/server/utils/request-handler/handler.ts new file mode 100644 index 0000000..6660f00 --- /dev/null +++ b/src/lib/server/utils/request-handler/handler.ts @@ -0,0 +1,74 @@ +import type { RequestEvent } from '@sveltejs/kit'; + +import { type Api, getApi, getNoAuthApi } from '$lib/server/api'; +import { Cli } from '$lib/server/cli'; +import { FileSystem } from '$lib/server/file-system'; +import { Git } from '$lib/server/git'; +import { ProjectManager } from '$lib/server/project'; + +import type { Context } from '@utils-server/request-handler/context'; + +export class Handler { + private _context: Context; + private readonly _event: RequestEvent; + private readonly _body: Body; + + private _apiCache: Api | undefined; + private _cliCache: Cli | undefined; + private _fsCache: FileSystem | undefined; + private _gitCache: Git | undefined; + private _projectCache: ProjectManager | undefined; + + constructor(context: Context, event: RequestEvent, body: Body) { + this._context = context; + this._event = event; + this._body = body; + } + + get context(): Context { + return this._context; + } + + set context(context: Context) { + this._context = context; + + this._apiCache = undefined; + this._cliCache = undefined; + this._fsCache = undefined; + this._gitCache = undefined; + } + + get event(): RequestEvent { + return this._event; + } + + get body(): Body { + return this._body; + } + + get api(): Api { + if (!this._apiCache) + this._apiCache = this._context.online ? getApi(this._event.cookies) : getNoAuthApi(); + return this._apiCache; + } + + get cli(): Cli { + if (!this._cliCache) this._cliCache = new Cli(this._context); + return this._cliCache; + } + + get fs(): FileSystem { + if (!this._fsCache) this._fsCache = new FileSystem(this._context); + return this._fsCache; + } + + get git(): Git { + if (!this._gitCache) this._gitCache = new Git(); + return this._gitCache; + } + + get project(): ProjectManager { + if (!this._projectCache) this._projectCache = new ProjectManager(this, this._context); + return this._projectCache; + } +} diff --git a/src/lib/server/utils/request-handler/index.ts b/src/lib/server/utils/request-handler/index.ts new file mode 100644 index 0000000..a2343e0 --- /dev/null +++ b/src/lib/server/utils/request-handler/index.ts @@ -0,0 +1,5 @@ +export * from './action-handler'; +export * from './request-handler'; +export * from './context'; +export * from './handler'; +export * from './types'; diff --git a/src/lib/server/utils/request-handler/request-handler.ts b/src/lib/server/utils/request-handler/request-handler.ts new file mode 100644 index 0000000..0915e8c --- /dev/null +++ b/src/lib/server/utils/request-handler/request-handler.ts @@ -0,0 +1,37 @@ +import type { RequestEvent } from '@sveltejs/kit'; + +import { Exception } from '@utils/exception'; +import type { MaybePromise } from '@utils/types'; + +import { getContext } from './context'; +import { Handler } from './handler'; +import { assertRequest } from './request.policy'; +import type { RequestHandlerOptions } from './types'; + +type Callback = (opts: Handler) => MaybePromise; + +const handleError = (e: unknown): Response => { + if (e instanceof Exception) { + return Response.json({ error: e.error, message: e.message }, { status: e.status }); + } + return Response.json({ error: 'Internal Server Error', message: e }, { status: 500 }); +}; + +export const useRequestHandler = ( + callback: Callback, + options?: RequestHandlerOptions, +): ((event: RequestEvent) => MaybePromise) => { + return async (event: RequestEvent) => { + try { + const context = await getContext(event); + + assertRequest(context, options); + + const handler = new Handler(context, event, {}); + + return await callback(handler); + } catch (e) { + return handleError(e); + } + }; +}; diff --git a/src/lib/server/utils/request-handler/request.policy.ts b/src/lib/server/utils/request-handler/request.policy.ts new file mode 100644 index 0000000..47fbbbc --- /dev/null +++ b/src/lib/server/utils/request-handler/request.policy.ts @@ -0,0 +1,37 @@ +import { Exception } from '@utils/exception'; + +import type { Context } from './context'; +import type { RequestHandlerOptions } from './types'; + +const DEFAULT_OPTIONS: RequestHandlerOptions = { + onlineOnly: false, + offlineOnly: false, + projectOptional: false, +}; + +const assertProject = (context: Context, options: RequestHandlerOptions): void | never => { + if (options.projectOptional) return; + + if (!context.session) throw new Exception('Bad Request', 'No session', 400); + if (!context.project) throw new Exception('Bad Request', 'Request required a project', 400); + + if (context.online && !context.project.gateway) + throw new Exception('Internal Server Error', "Project don't have gateway on online mode", 500); +}; + +const assertMode = (context: Context, options: RequestHandlerOptions): void | never => { + if (options.onlineOnly && !context.online) + throw new Exception('Method Not Allowed', 'This action is not available offline', 405); + if (options.offlineOnly && context.online) + throw new Exception('Method Not Allowed', 'This action is not available online', 405); +}; + +export const assertRequest = ( + context: Context, + rawOptions?: RequestHandlerOptions, +): void | never => { + const options = { ...DEFAULT_OPTIONS, ...rawOptions }; + + assertMode(context, options); + assertProject(context, options); +}; diff --git a/src/lib/server/utils/request-handler/types.ts b/src/lib/server/utils/request-handler/types.ts new file mode 100644 index 0000000..945b41f --- /dev/null +++ b/src/lib/server/utils/request-handler/types.ts @@ -0,0 +1,12 @@ +import type { ClassType, MaybePromise } from '@utils/types'; + +import { type Handler } from './handler'; + +export type Callback = (opts: Handler) => MaybePromise; + +export interface RequestHandlerOptions { + onlineOnly?: boolean; + offlineOnly?: boolean; + projectOptional?: boolean; + body?: ClassType; +} diff --git a/src/lib/server/utils/server-api/clients.ts b/src/lib/server/utils/server-api/clients.ts deleted file mode 100644 index 37e505e..0000000 --- a/src/lib/server/utils/server-api/clients.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { env } from '$env/dynamic/private'; - -import { HttpClient } from '@utils/http'; - -import { Repository } from './repository'; - -const client = new HttpClient(env.API_URL ?? ''); - -export const serverApi = new Repository(client); - -export const withAuth = (token: string) => { - return new Repository( - new HttpClient(env.API_URL ?? '', { - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - }), - ); -}; diff --git a/src/lib/server/utils/server-api/guards/auth.guard.ts b/src/lib/server/utils/server-api/guards/auth.guard.ts deleted file mode 100644 index ef0372c..0000000 --- a/src/lib/server/utils/server-api/guards/auth.guard.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { type Cookies, json } from '@sveltejs/kit'; - -import { serverApi, withAuth } from '../clients'; -import type { Repository } from '../index'; -import type { RefreshTokenInput, Token } from '../types'; -import { setTokensInCookies } from '../utils'; -import { errorGuard } from './error.guard'; - -export const authGuard = async ( - callback: (httpClient: Repository) => Promise, - cookies: Cookies, -): Promise => { - return errorGuard(async () => { - let accessToken = cookies.get('accessToken'); - - if (!accessToken) { - const refreshToken = cookies.get('refreshToken'); - - if (!refreshToken) { - return json({ error: 'Unauthorized', message: 'No token found' }, { status: 401 }); - } - - try { - const tokens = await serverApi.post('/auth/refresh-token', { - refreshToken, - }); - - setTokensInCookies(cookies, tokens); - accessToken = tokens.accessToken; - } catch { - return json({ error: 'Unauthorized', message: 'Invalid refresh token' }, { status: 401 }); - } - } - - return callback(withAuth(accessToken)); - }); -}; diff --git a/src/lib/server/utils/server-api/guards/error.guard.ts b/src/lib/server/utils/server-api/guards/error.guard.ts deleted file mode 100644 index 95b6e29..0000000 --- a/src/lib/server/utils/server-api/guards/error.guard.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { json } from '@sveltejs/kit'; -import { STATUS_CODES } from 'node:http'; - -export const errorGuard = async (callback: () => Promise): Promise => { - try { - return await callback(); - } catch (error: any) { - const data: - | { - statusCode: number; - path: string; - error: { - message: string | string[]; - timestamp: string; - cause?: { - message: string; - }; - }; - } - | undefined = error?.cause; - - const statusCode = data?.statusCode ?? 500; - - return json( - { - error: STATUS_CODES[statusCode] || 'Unknown error', - message: data?.error?.message || 'Unknown error', - cause: data?.error?.cause?.message || undefined, - }, - { status: statusCode }, - ); - } -}; diff --git a/src/lib/server/utils/server-api/guards/params.guard.ts b/src/lib/server/utils/server-api/guards/params.guard.ts deleted file mode 100644 index 2073c67..0000000 --- a/src/lib/server/utils/server-api/guards/params.guard.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { type RequestEvent, json } from '@sveltejs/kit'; - -export const parseParams = (event: RequestEvent, params: string[], regex: RegExp) => { - const searchParams = event.url.pathname.match(regex)?.slice(1); - - const res: Record = {}; - let i = 0; - - for (const param of params) { - res[param] = searchParams?.[i] ?? null; - i++; - } - - return res; -}; - -export const paramsGuard = async ( - event: RequestEvent, - rawParams: string[], - regex: RegExp, - callback: (params: Record) => Promise, -): Promise => { - const params = parseParams(event, rawParams, regex); - - for (const param in params) { - if (!params[param]) { - return json({ error: 'Missing required parameters' }, { status: 400 }); - } - } - - return callback(params as Record); -}; diff --git a/src/lib/server/utils/server-api/index.ts b/src/lib/server/utils/server-api/index.ts deleted file mode 100644 index fcdf960..0000000 --- a/src/lib/server/utils/server-api/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { serverApi } from './clients'; -export { Repository } from './repository'; -export type { Token } from './types'; -export { resetTokensInCookies, setTokensInCookies } from './utils'; - -export { authGuard } from './guards/auth.guard'; -export { errorGuard } from './guards/error.guard'; -export { paramsGuard } from './guards/params.guard'; diff --git a/src/lib/utils-client/event-emitter.ts b/src/lib/utils-client/event-emitter.ts deleted file mode 100644 index 68fd197..0000000 --- a/src/lib/utils-client/event-emitter.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - type EventTypeEnum, - type IEventEmitter, - type ListenerType, -} from '$lib/loader/client/types/event-emitter.type'; - -export class EventEmitter implements IEventEmitter { - public listeners: Record = {}; - public eventQueue: { event: EventTypeEnum | string; args: any[] }[] = []; - - public runEvents = () => { - this.eventQueue.forEach(({ event, args }) => { - this.listeners[event]?.forEach((listener) => { - try { - listener(...args); - } catch (error) { - console.error(`Error handling event [${event}] : ${error}`); - } - }); - }); - this.eventQueue = []; - }; - - public emitEvent(event: EventTypeEnum | string, ...args: any[]) { - this.eventQueue.push({ event, args }); - } - - public addListener(event: EventTypeEnum | string, listener: ListenerType): void { - if (!this.listeners[event]) this.listeners[event] = []; - this.listeners[event].push(listener); - } - public on(event: EventTypeEnum | string, listener: ListenerType): void { - this.addListener(event, listener); - } - - public removeListener(event: EventTypeEnum | string, listener: ListenerType): void { - if (!this.listeners[event]) return; - const index = this.listeners[event].indexOf(listener); - if (index >= 0) { - this.listeners[event].splice(index, 1); - } - } - public off(event: EventTypeEnum | string, listener: ListenerType): void { - this.removeListener(event, listener); - } - - public removeListenersForEvent(event: EventTypeEnum | string): void { - if (!this.listeners[event]) return; - this.listeners[event] = []; - } - public removeAllListeners(): void { - this.listeners = {}; - } -} diff --git a/src/lib/utils-client/file-system/file-system-file.ts b/src/lib/utils-client/file-system/file-system-file.ts deleted file mode 100644 index a3d9737..0000000 --- a/src/lib/utils-client/file-system/file-system-file.ts +++ /dev/null @@ -1,53 +0,0 @@ -export class FileSystemFile { - readonly handle: FileSystemFileHandle; - - constructor(handle: FileSystemFileHandle) { - this.handle = handle; - } - - getName(): string { - return this.handle.name; - } - - getFile(): Promise { - return this.handle.getFile(); - } - - async isSameFile(file: FileSystemFile): Promise { - return await this.handle.isSameEntry(file.handle); - } - - async read(): Promise { - const file = await this.handle.getFile(); - return file.text(); - } - - async readJson(): Promise { - const raw = await this.read(); - return JSON.parse(raw) as T; - } - - async write(text: string): Promise { - const writable = await this.handle.createWritable(); - await writable.write(text); - await writable.close(); - } - - async writeBinary(base64: string): Promise { - const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)); - const writable = await this.handle.createWritable(); - await writable.write(binary); - await writable.close(); - } - - async writeJson(content: any): Promise { - const raw = JSON.stringify(content); - return this.write(raw); - } - - async getUrl(fileType: string): Promise { - const file = await this.handle.getFile(); - const blob = new Blob([await file.arrayBuffer()], { type: fileType }); - return URL.createObjectURL(blob); - } -} diff --git a/src/lib/utils-client/local-file-system/project-file-system.ts b/src/lib/utils-client/local-file-system/project-file-system.ts deleted file mode 100644 index 5c9cae9..0000000 --- a/src/lib/utils-client/local-file-system/project-file-system.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { FileSystemManager } from '@utils-client/file-system'; - -export const projectFileSystem: FileSystemManager = new FileSystemManager('/'); diff --git a/src/lib/utils/const.ts b/src/lib/utils/const.ts new file mode 100644 index 0000000..53c0e25 --- /dev/null +++ b/src/lib/utils/const.ts @@ -0,0 +1 @@ +export const SESSION_PROJECT_HEADER = 'x-project-id'; diff --git a/src/lib/utils/exception.ts b/src/lib/utils/exception.ts new file mode 100644 index 0000000..e779554 --- /dev/null +++ b/src/lib/utils/exception.ts @@ -0,0 +1,10 @@ +export class Exception extends Error { + constructor( + public error: string, + public message: string, + public status: number, + options?: { cause?: Error }, + ) { + super(`${error}: ${message}`, options); + } +} diff --git a/src/lib/utils/format.ts b/src/lib/utils/format.ts new file mode 100644 index 0000000..de3e61e --- /dev/null +++ b/src/lib/utils/format.ts @@ -0,0 +1,33 @@ +const toWords = (str: string): string[] => { + return str + .replace(/([a-z])([A-Z])/g, '$1 $2') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2') + .replace(/[-_]+/g, ' ') + .trim() + .split(/\s+/) + .filter(Boolean); +}; + +export const toKebabCase = (str: string): string => { + return toWords(str) + .map((word) => word.toLowerCase()) + .join('-'); +}; + +export const toPascalCase = (str: string): string => { + return toWords(str) + .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(''); +}; + +export const toCamelCase = (str: string): string => { + const words = toWords(str); + return words + .map((word, i) => + i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(), + ) + .join(''); +}; + +export const camelToKebab = (str: string) => + str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`); diff --git a/src/lib/server/client.ts b/src/lib/utils/http/client.ts similarity index 78% rename from src/lib/server/client.ts rename to src/lib/utils/http/client.ts index b74bf1a..6fdd45a 100644 --- a/src/lib/server/client.ts +++ b/src/lib/utils/http/client.ts @@ -6,16 +6,14 @@ export interface MiddlewareParams { options: RequestOptions; } -export type FullResponse = Response & { content: any }; - -export type MiddlewareNext = (params?: MiddlewareParams) => Promise; +export type MiddlewareNext = (params?: MiddlewareParams) => Promise; export type Middleware = ( params: MiddlewareParams, next: MiddlewareNext, -) => Promise | undefined; +) => Promise | undefined; -type BaseRequest = (path: string, options: RequestOptions) => Promise; +type BaseRequest = (path: string, options: RequestOptions) => Promise; export class HttpClient { private readonly _baseUrl: string; @@ -32,7 +30,7 @@ export class HttpClient { this._middlewares = []; } - get(path: string, options?: RequestOptions): Promise { + get(path: string, options?: RequestOptions): Promise { return this._applyMiddlewares(path, options, (newPath, newOptions) => { return this._request(newPath, { ...newOptions, @@ -41,7 +39,7 @@ export class HttpClient { }); } - post(path: string, body?: string, options?: RequestOptions): Promise { + post(path: string, body?: string | FormData, options?: RequestOptions): Promise { return this._applyMiddlewares(path, options, (newPath, newOptions) => { return this._request(newPath, { ...newOptions, @@ -51,7 +49,7 @@ export class HttpClient { }); } - put(path: string, body?: string, options?: RequestOptions): Promise { + put(path: string, body?: string, options?: RequestOptions): Promise { return this._applyMiddlewares(path, options, (newPath, newOptions) => { return this._request(newPath, { ...newOptions, @@ -61,7 +59,7 @@ export class HttpClient { }); } - patch(path: string, body?: string, options?: RequestOptions): Promise { + patch(path: string, body?: string, options?: RequestOptions): Promise { return this._applyMiddlewares(path, options, async (newPath, newOptions) => { return this._request(newPath, { ...newOptions, @@ -71,12 +69,12 @@ export class HttpClient { }); } - delete(path: string, options?: RequestOptions): Promise { + delete(path: string, options?: RequestOptions): Promise { return this._applyMiddlewares(path, options, (newPath, newOptions) => { return this._request(newPath, { ...newOptions, method: 'DELETE', - }) as Promise; + }) as Promise; }); } @@ -85,17 +83,15 @@ export class HttpClient { return this; } - private async _request(path: string, request: RequestInit): Promise { - const res = (await fetch(path, request)) as FullResponse; - res.content = null; - return res; + private _request(path: string, request: RequestInit): Promise { + return fetch(path, request); } private _applyMiddlewares( path: string, options: RequestOptions | undefined, callback: BaseRequest, - ): Promise { + ): Promise { const baseParams = { path, fullPath: this._getUrl(path), @@ -105,14 +101,14 @@ export class HttpClient { }, }; const middlewares = this._middlewares.slice(); - let response: FullResponse; + let response: Response; - const execution = async (params?: MiddlewareParams): Promise => { + const execution = async (params?: MiddlewareParams): Promise => { if (!params) params = baseParams; const middleware = middlewares.shift(); - if (!middleware) response = (await callback(params.fullPath, params.options)) as FullResponse; + if (!middleware) response = (await callback(params.fullPath, params.options)) as Response; else response = (await middleware(params, execution)) ?? response; return response; diff --git a/src/lib/utils/http/index.ts b/src/lib/utils/http/index.ts index 866345e..2d6ee12 100644 --- a/src/lib/utils/http/index.ts +++ b/src/lib/utils/http/index.ts @@ -3,4 +3,4 @@ export { type MiddlewareNext, type MiddlewareParams, type RequestOptions, -} from '../../server/client'; +} from './client'; diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts deleted file mode 100644 index c202386..0000000 --- a/src/lib/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './http'; diff --git a/src/lib/utils/null.ts b/src/lib/utils/null.ts new file mode 100644 index 0000000..2aa9bb9 --- /dev/null +++ b/src/lib/utils/null.ts @@ -0,0 +1,3 @@ +export const isNullish = (value: any): boolean => { + return value === undefined || value === null; +}; diff --git a/src/lib/utils/object.ts b/src/lib/utils/object.ts new file mode 100644 index 0000000..a293376 --- /dev/null +++ b/src/lib/utils/object.ts @@ -0,0 +1,27 @@ +import { isNullish } from '@utils/null'; + +export const cloneDeep = (obj: T): T => JSON.parse(JSON.stringify(obj)); + +type AssignType = { + [K in keyof T]: T[K] extends object ? AssignType : V; +}; + +export const assignDeep = , V>(obj: T, value: V): AssignType => { + const copy: any = {}; + for (const key in obj) { + copy[key] = + !isNullish(obj[key]) && typeof obj[key] === 'object' ? assignDeep(obj[key], value) : value; + } + return copy; +}; + +export const flatObjectValues = (object: any): any[] => { + let results: any[] = []; + + for (const value of Object.values(object)) { + const values = typeof value === 'object' ? flatObjectValues(value) : [value]; + results = [...results, ...values]; + } + + return results; +}; diff --git a/src/lib/utils/string.ts b/src/lib/utils/string.ts new file mode 100644 index 0000000..08c33af --- /dev/null +++ b/src/lib/utils/string.ts @@ -0,0 +1,6 @@ +import crypto from 'crypto'; + +export const generateKey = (size = 50) => { + const buffer = crypto.randomBytes(size); + return buffer.toString('base64url').substring(0, size); +}; diff --git a/src/lib/utils/types/base.type.ts b/src/lib/utils/types/base.type.ts new file mode 100644 index 0000000..c5187d9 --- /dev/null +++ b/src/lib/utils/types/base.type.ts @@ -0,0 +1 @@ +export type WithOptional = Omit & Partial>; diff --git a/src/lib/utils/types/class.type.ts b/src/lib/utils/types/class.type.ts new file mode 100644 index 0000000..3b2428a --- /dev/null +++ b/src/lib/utils/types/class.type.ts @@ -0,0 +1 @@ +export type ClassType = new (...args: any[]) => T; diff --git a/src/lib/utils/types/index.ts b/src/lib/utils/types/index.ts new file mode 100644 index 0000000..0db0202 --- /dev/null +++ b/src/lib/utils/types/index.ts @@ -0,0 +1,5 @@ +export * from './base.type'; +export * from './class.type'; +export * from './part.type'; +export * from './promise.type'; +export * from './save.type'; diff --git a/src/lib/utils/types/part.type.ts b/src/lib/utils/types/part.type.ts new file mode 100644 index 0000000..b51b16c --- /dev/null +++ b/src/lib/utils/types/part.type.ts @@ -0,0 +1 @@ +export type Part = 'client' | 'server'; diff --git a/src/lib/utils/types/promise.type.ts b/src/lib/utils/types/promise.type.ts new file mode 100644 index 0000000..9cd354b --- /dev/null +++ b/src/lib/utils/types/promise.type.ts @@ -0,0 +1 @@ +export type MaybePromise = T | Promise; diff --git a/src/lib/loader/client/types/save.type.ts b/src/lib/utils/types/save.type.ts similarity index 100% rename from src/lib/loader/client/types/save.type.ts rename to src/lib/utils/types/save.type.ts diff --git a/src/lib/utils/ui.ts b/src/lib/utils/ui.ts new file mode 100644 index 0000000..ebfd273 --- /dev/null +++ b/src/lib/utils/ui.ts @@ -0,0 +1,10 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export type { WithElementRef, WithoutChild, WithChildren, WithoutChildrenOrChild } from 'bits-ui'; + +export type WithoutChildren = Omit; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 2394612..164f29d 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,8 +1,25 @@ -{@render children()} + + + + {@render children()} + diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 0749576..ec11de2 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,58 +1,120 @@ -
    -
    -
    - - Logo - -
    - - -
    -
    -
    - - - -
    -
    -
    - {#key $tabsStore.selectedTabId} - {#if Component && tab} - - {/if} - {/key} +
    + + +
    + + +
    +

    Projects

    + + {#if isOnline} + + {:else} + + {/if} + + + +
    + + + +
    +

    Recent

    + + {#if cacheQuery.isLoading || !cacheQuery.isFetched} + + {:else if cacheQuery.data && cacheQuery.data.length > 0} +
    + {#each cacheQuery.data as project (project.id)} + handleCacheProject(project)} + onRemove={() => handleCacheRemoveProject(project)} + /> + {/each} +
    + + + {:else} +
    +

    No recent projects

    +
    + {/if} +
    +
    +
    diff --git a/src/routes/actions/project/+page.server.ts b/src/routes/actions/project/+page.server.ts new file mode 100644 index 0000000..cd017b8 --- /dev/null +++ b/src/routes/actions/project/+page.server.ts @@ -0,0 +1,15 @@ +import { getGatewayProjectsAction } from '$lib/server/actions/project/gateway.action'; +import { + getInfoProjectAction, + setInfoProjectAction, +} from '$lib/server/actions/project/info.action'; +import { loadProjectAction } from '$lib/server/actions/project/load.action'; +import { createProjectAction } from '$lib/server/actions/project/new.action'; + +export const actions = { + load: loadProjectAction, + new: createProjectAction, + 'get-info': getInfoProjectAction, + 'set-info': setInfoProjectAction, + 'get-gateway-projects': getGatewayProjectsAction, +}; diff --git a/src/routes/actions/project/fs/+page.server.ts b/src/routes/actions/project/fs/+page.server.ts new file mode 100644 index 0000000..d1eae25 --- /dev/null +++ b/src/routes/actions/project/fs/+page.server.ts @@ -0,0 +1,5 @@ +import { readdirFsAction } from '$lib/server/actions/project/fs/readdir.action'; + +export const actions = { + readdir: readdirFsAction, +}; diff --git a/src/routes/actions/project/loader/+page.server.ts b/src/routes/actions/project/loader/+page.server.ts new file mode 100644 index 0000000..6a0272f --- /dev/null +++ b/src/routes/actions/project/loader/+page.server.ts @@ -0,0 +1,9 @@ +import { buildProjectAction } from '$lib/server/actions/project/loader/build.action'; +import { fetchEnvLoaderAction } from '$lib/server/actions/project/loader/env.action'; +import { fetchManifestLoaderAction } from '$lib/server/actions/project/loader/manifest.action'; + +export const actions = { + build: buildProjectAction, + env: fetchEnvLoaderAction, + manifest: fetchManifestLoaderAction, +}; diff --git a/src/routes/actions/project/package/+page.server.ts b/src/routes/actions/project/package/+page.server.ts new file mode 100644 index 0000000..c3e244e --- /dev/null +++ b/src/routes/actions/project/package/+page.server.ts @@ -0,0 +1,15 @@ +import { addComponentsProjectAction } from '$lib/server/actions/project/package/add-components.action'; +import { addSystemsProjectAction } from '$lib/server/actions/project/package/add-systems.action'; +import { createComponentProjectAction } from '$lib/server/actions/project/package/create-component.action'; +import { createSystemProjectAction } from '$lib/server/actions/project/package/create-system.action'; +import { getComponentsManifestsAction } from '$lib/server/actions/project/package/get-components-manifests.action'; +import { getSystemsManifestsAction } from '$lib/server/actions/project/package/get-systems-manifests.action'; + +export const actions = { + 'add-components': addComponentsProjectAction, + 'add-systems': addSystemsProjectAction, + 'create-component': createComponentProjectAction, + 'create-system': createSystemProjectAction, + 'get-components-manifests': getComponentsManifestsAction, + 'get-systems-manifests': getSystemsManifestsAction, +}; diff --git a/src/routes/actions/project/save/+page.server.ts b/src/routes/actions/project/save/+page.server.ts new file mode 100644 index 0000000..67ebdf1 --- /dev/null +++ b/src/routes/actions/project/save/+page.server.ts @@ -0,0 +1,7 @@ +import { getSaveAction } from '$lib/server/actions/project/save/get-save.action'; +import { setSaveAction } from '$lib/server/actions/project/save/set-save.action'; + +export const actions = { + get: getSaveAction, + set: setSaveAction, +}; diff --git a/src/routes/cli/+page.server.ts b/src/routes/cli/+page.server.ts deleted file mode 100644 index 0ce73a1..0000000 --- a/src/routes/cli/+page.server.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { fail } from '@sveltejs/kit'; - -import { CliError } from '@utils-server/cli/cli-error'; -import { CliInterface } from '@utils-server/cli/cli-interface'; - -import type { Actions } from './$types'; - -export const actions = { - new: async ({ request }) => { - const data = await request.json(); - - if (!data.projectPath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'projectPath'" }); - } - if (!data.projectName) { - return fail(403, { success: false, errorMsg: "Missing arg: 'projectName'" }); - } - if (!data.packageManager) { - return fail(403, { success: false, errorMsg: "Missing arg: 'packageManager'" }); - } - if (!data.language) { - return fail(403, { success: false, errorMsg: "Missing arg: 'language'" }); - } - - try { - new CliInterface(data.projectPath).new( - data.projectName, - data.packageManager, - data.language, - false, - data.multiplayerServer, - data.dockerContainerization, - false, - true, - data.createGitRepository, - data.gitRemote, - ); - return { - success: true, - }; - } catch (e: unknown) { - if (e instanceof CliError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - generate: async ({ locals }) => { - try { - new CliInterface(locals.session.data.path).generate(true); - return { - success: true, - }; - } catch (e: unknown) { - if (e instanceof CliError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - build: async ({ locals }) => { - try { - new CliInterface(locals.session.data.path).build(true); - return { - success: true, - }; - } catch (e: unknown) { - if (e instanceof CliError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - addComponent: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.componentName) { - return fail(403, { success: false, errorMsg: "Missing arg: 'componentName'" }); - } - - try { - new CliInterface(locals.session.data.path).addComponent(data.componentName); - return { - success: true, - }; - } catch (e: unknown) { - if (e instanceof CliError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, -} satisfies Actions; diff --git a/src/routes/components/cache-project-list-skeleton.svelte b/src/routes/components/cache-project-list-skeleton.svelte new file mode 100644 index 0000000..c21d554 --- /dev/null +++ b/src/routes/components/cache-project-list-skeleton.svelte @@ -0,0 +1,15 @@ + + +
    + {#each { length: 3 }, i (i)} +
    + +
    + + +
    +
    + {/each} +
    diff --git a/src/routes/components/cache-project.svelte b/src/routes/components/cache-project.svelte new file mode 100644 index 0000000..b06f35e --- /dev/null +++ b/src/routes/components/cache-project.svelte @@ -0,0 +1,56 @@ + + +
    + +
    + {#if isLoading} + + {:else} + + {/if} +
    +
    diff --git a/src/routes/components/create-project-dialog.svelte b/src/routes/components/create-project-dialog.svelte new file mode 100644 index 0000000..8ee55f1 --- /dev/null +++ b/src/routes/components/create-project-dialog.svelte @@ -0,0 +1,20 @@ + + + + + + + diff --git a/src/routes/components/create-project-form.svelte b/src/routes/components/create-project-form.svelte new file mode 100644 index 0000000..21ebb5e --- /dev/null +++ b/src/routes/components/create-project-form.svelte @@ -0,0 +1,181 @@ + + +
    + + + + + + + +
    diff --git a/src/routes/components/header.svelte b/src/routes/components/header.svelte new file mode 100644 index 0000000..48d9061 --- /dev/null +++ b/src/routes/components/header.svelte @@ -0,0 +1,10 @@ + + +
    +
    + Logo + Nanoforge - Editor +
    +
    diff --git a/src/routes/components/index.ts b/src/routes/components/index.ts new file mode 100644 index 0000000..b767279 --- /dev/null +++ b/src/routes/components/index.ts @@ -0,0 +1,21 @@ +import CacheProjectListSkeleton from './cache-project-list-skeleton.svelte'; +import CacheProject from './cache-project.svelte'; +import CreateProjectDialog from './create-project-dialog.svelte'; +import CreateProjectForm from './create-project-form.svelte'; +import Header from './header.svelte'; +import OfflineProjectButtons from './offline-project-buttons.svelte'; +import OnlineProjectButtons from './online-project-buttons.svelte'; +import OpenProjectDialog from './open-project-dialog.svelte'; +import OpenProjectForm from './open-project-form.svelte'; + +export default { + CacheProject, + CacheProjectListSkeleton, + CreateProjectDialog, + CreateProjectForm, + Header, + OfflineProjectButtons, + OnlineProjectButtons, + OpenProjectDialog, + OpenProjectForm, +}; diff --git a/src/routes/components/offline-project-buttons.svelte b/src/routes/components/offline-project-buttons.svelte new file mode 100644 index 0000000..c7ce14f --- /dev/null +++ b/src/routes/components/offline-project-buttons.svelte @@ -0,0 +1,30 @@ + + + + + diff --git a/src/routes/components/online-project-buttons.svelte b/src/routes/components/online-project-buttons.svelte new file mode 100644 index 0000000..799fd21 --- /dev/null +++ b/src/routes/components/online-project-buttons.svelte @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/src/routes/components/open-project-dialog.svelte b/src/routes/components/open-project-dialog.svelte new file mode 100644 index 0000000..1b43c0f --- /dev/null +++ b/src/routes/components/open-project-dialog.svelte @@ -0,0 +1,20 @@ + + + + + + + diff --git a/src/routes/components/open-project-form.svelte b/src/routes/components/open-project-form.svelte new file mode 100644 index 0000000..82846d1 --- /dev/null +++ b/src/routes/components/open-project-form.svelte @@ -0,0 +1,79 @@ + + +
    + + + + + + + +
    diff --git a/src/routes/dashboard/+page.svelte b/src/routes/dashboard/+page.svelte new file mode 100644 index 0000000..7f9dc37 --- /dev/null +++ b/src/routes/dashboard/+page.svelte @@ -0,0 +1,130 @@ + + +{#if loaded} +
    +
    +
    + Logo +
    + + +
    +
    +
    + + + +
    +
    +
    + {#key $tabsStore.selectedTabId} + {#if Component && tab} + + {/if} + {/key} +
    +
    +{:else} +
    + + + + Project loading... + Retrieving save + + + + + + +
    +{/if} diff --git a/src/routes/fs/+page.server.ts b/src/routes/fs/+page.server.ts deleted file mode 100644 index c97dcaa..0000000 --- a/src/routes/fs/+page.server.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { fail } from '@sveltejs/kit'; - -import { FileSystemError } from '@utils-server/file-system/file-system-error'; -import { ProjectDirectory } from '@utils-server/file-system/project-directory'; -import { ProjectFile } from '@utils-server/file-system/project-file'; - -import type { Actions } from './$types'; - -export const actions = { - readFile: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.filePath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'filePath'" }); - } - - try { - return { - success: true, - fileContent: new ProjectFile(data.filePath, locals.session.data.path).read(), - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - readDir: async ({ request, locals }) => { - const data = await request.json(); - - try { - return { - success: true, - dirContent: new ProjectDirectory( - data.dirPath ? data.dirPath : '/', - locals.session.data.path, - ).read(), - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - readDirRec: async ({ request, locals }) => { - const data = await request.json(); - - try { - return { - success: true, - dirContent: new ProjectDirectory( - data.dirPath ? data.dirPath : '/', - locals.session.data.path, - ).read(true), - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - writeFile: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.filePath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'filePath'" }); - } - if (!data.fileContent) { - return fail(403, { success: false, errorMsg: "Missing arg: 'fileContent'" }); - } - - try { - new ProjectFile(data.filePath, locals.session.data.path).write(data.fileContent); - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - return { success: true }; - }, - - deleteFile: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.filePath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'filePath'" }); - } - - try { - new ProjectFile(data.filePath, locals.session.data.path).delete(); - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - return { success: true }; - }, - - renameFile: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.filePath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'filePath'" }); - } - if (!data.newFilePath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'newFilePath'" }); - } - - try { - new ProjectFile(data.filePath, locals.session.data.path).rename(data.newFilePath); - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - return { success: true }; - }, - - createDir: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.dirPath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'dirPath'" }); - } - - try { - new ProjectDirectory(data.dirPath, locals.session.data.path).create(); - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - return { success: true }; - }, - - renameDir: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.dirPath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'dirPath'" }); - } - if (!data.newDirPath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'newDirPath'" }); - } - - try { - new ProjectDirectory(data.dirPath, locals.session.data.path).rename(data.newDirPath); - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - return { success: true }; - }, - deleteDir: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.dirPath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'dirPath'" }); - } - - try { - new ProjectDirectory(data.dirPath, locals.session.data.path).delete(data.recursive === true); - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - return { success: true }; - }, -} satisfies Actions; diff --git a/src/routes/fs/build/+server.ts b/src/routes/fs/build/+server.ts new file mode 100644 index 0000000..1250905 --- /dev/null +++ b/src/routes/fs/build/+server.ts @@ -0,0 +1,20 @@ +import { Exception } from '@utils/exception'; + +import { useRequestHandler } from '@utils-server/request-handler'; + +/** + * To request a built file, use the following URL: + * /fs/build?path=path/to/file + * The path must be relative to /.nanoforge/client + * Only the client is handled for now + */ +export const GET = useRequestHandler(({ event, project }) => { + const path = event.url.searchParams.get('path'); + if (!path) throw new Exception('Bad Request', 'Missing path query param', 400); + + const file = project.client.loader.getFile(decodeURIComponent(path).replace(/\?url$/, '')); + + const stream = file.readStream(); + + return new Response(stream); +}); diff --git a/src/routes/fs/project/+server.ts b/src/routes/fs/project/+server.ts new file mode 100644 index 0000000..0856a26 --- /dev/null +++ b/src/routes/fs/project/+server.ts @@ -0,0 +1,20 @@ +import { Exception } from '@utils/exception'; + +import { useRequestHandler } from '@utils-server/request-handler'; + +/** + * To request a project file, use the following URL: + * /fs/project?path=path/to/file + * The path must be relative to /client + * Only the client is handled for now + */ +export const GET = useRequestHandler(({ event, project }) => { + const path = event.url.searchParams.get('path'); + if (!path) throw new Exception('Bad Request', 'Missing path query param', 400); + + const file = project.client.fs.getFile(decodeURIComponent(path).replace(/\?url$/, '')); + + const stream = file.readStream(); + + return new Response(stream); +}); diff --git a/src/routes/game-loader/+page.server.ts b/src/routes/game-loader/+page.server.ts deleted file mode 100644 index f709658..0000000 --- a/src/routes/game-loader/+page.server.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { fail } from '@sveltejs/kit'; - -import type { Save } from '$lib/loader/client/types/save.type'; -import { getGameEnv } from '$lib/loader/server/env'; - -import { FileSystemError } from '@utils-server/file-system/file-system-error'; -import { - ProjectDirectory, - directoryContentToFileEntries, -} from '@utils-server/file-system/project-directory'; -import { ProjectFile } from '@utils-server/file-system/project-file'; - -import type { Actions } from './$types'; - -export const actions = { - getManifest: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.side) { - return fail(403, { success: false, errorMsg: "Missing arg: 'side'" }); - } - if (data.side !== 'server' && data.side !== 'client') { - return fail(403, { success: false, errorMsg: "Arg 'side' can only be 'server' or 'client'" }); - } - - try { - return { - success: true, - manifest: { - files: directoryContentToFileEntries( - new ProjectDirectory(`/.nanoforge/${data.side}/`, locals.session.data.path).read(true), - ), - version: '0.0.0', - }, - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - getSave: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.side) { - return fail(403, { success: false, errorMsg: "Missing arg: 'side'" }); - } - if (data.side !== 'server' && data.side !== 'client') { - return fail(403, { success: false, errorMsg: "Arg 'side' can only be 'server' or 'client'" }); - } - - try { - return { - success: true, - save: new ProjectFile( - `/.nanoforge/${data.side}.save.json`, - locals.session.data.path, - ).readJson(), - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - updateSave: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.side) { - return fail(403, { success: false, errorMsg: "Missing arg: 'side'" }); - } - if (data.side !== 'server' && data.side !== 'client') { - return fail(403, { success: false, errorMsg: "Arg 'side' can only be 'server' or 'client'" }); - } - if (!data.save) { - return fail(403, { success: false, errorMsg: "Missing arg: 'save'" }); - } - - try { - new ProjectFile(`/.nanoforge/${data.side}.save.json`, locals.session.data.path).writeJson( - data.save, - ); - return { - success: true, - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - getComponentManifest: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.side) { - return fail(403, { success: false, errorMsg: "Missing arg: 'side'" }); - } - if (data.side !== 'server' && data.side !== 'client') { - return fail(403, { success: false, errorMsg: "Arg 'side' can only be 'server' or 'client'" }); - } - if (!data.componentPath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'componentPath'" }); - } - try { - const projectComponentFile = new ProjectFile( - `/${data.side}/${data.componentPath}`, - locals.session.data.path, - ); - projectComponentFile.isReadable(); - const componentModule = await import(/* @vite-ignore */ projectComponentFile.path); - return { - success: true, - manifest: componentModule['EDITOR_COMPONENT_MANIFEST'], - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - getBuildFile: async ({ request, locals }) => { - const data = await request.json(); - - if (!data.side) { - return fail(403, { success: false, errorMsg: "Missing arg: 'side'" }); - } - if (data.side !== 'server' && data.side !== 'client') { - return fail(403, { success: false, errorMsg: "Arg 'side' can only be 'server' or 'client'" }); - } - if (!data.filePath) { - return fail(403, { success: false, errorMsg: "Missing arg: 'filePath'" }); - } - - try { - return { - success: true, - fileContent: new ProjectFile( - `/.nanoforge/${data.side}/${data.filePath}`, - locals.session.data.path, - ).read(data.encoding), - }; - } catch (e: unknown) { - if (e instanceof FileSystemError) { - return fail(403, { success: false, errorMsg: e.message }); - } - throw e; - } - }, - getEnv: async ({ request }) => { - const data = await request.json(); - - if (!data.side) { - return fail(403, { success: false, errorMsg: "Missing arg: 'side'" }); - } - if (data.side !== 'server' && data.side !== 'client') { - return fail(403, { success: false, errorMsg: "Arg 'side' can only be 'server' or 'client'" }); - } - return { - success: true, - env: getGameEnv(data.side), - }; - }, -} satisfies Actions; diff --git a/src/routes/game-loader/+page.svelte b/src/routes/game-loader/+page.svelte deleted file mode 100644 index 2ea1c65..0000000 --- a/src/routes/game-loader/+page.svelte +++ /dev/null @@ -1,142 +0,0 @@ - - -
    -
    -
    - - Logo - -
    -
    -
    { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const response = await fetch('/game-loader?/getManifest', { - method: 'POST', - body: JSON.stringify({ side: formData.get('side') }), - }); - const result = deserialize(await response.text()); - if (result.type === 'success' && result.data) { - manifest = result.data.manifest.files; - } - }} - > - - -
    - {#if manifest.length > 0} -
    - {manifest.join('\n')} -
    - {/if} -
    { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const response = await fetch('/game-loader?/getBuildFile', { - method: 'POST', - body: JSON.stringify({ - side: formData.get('side'), - filePath: formData.get('filePath'), - }), - }); - const result = deserialize(await response.text()); - if (result.type === 'success' && result.data) { - buildFile = result.data.fileContent; - } - }} - > - - - -
    - {#if buildFile} -
    - {buildFile} -
    - {/if} -
    { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const response = await fetch('/game-loader?/getComponentManifest', { - method: 'POST', - body: JSON.stringify({ - side: formData.get('side'), - componentPath: formData.get('componentPath'), - }), - }); - const result = deserialize(await response.text()); - if (result.type === 'success' && result.data) { - componentManifest = result.data.manifest; - } - }} - > - - - -
    - {#if componentManifest} -
    - {JSON.stringify(componentManifest)} -
    - {/if} -
    { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const response = await fetch('/game-loader?/getSave', { - method: 'POST', - body: JSON.stringify({ side: formData.get('side') }), - }); - const result = deserialize(await response.text()); - if (result.type === 'success' && result.data) { - save = result.data.save; - } - }} - > - - -
    - {#if save} -
    - {JSON.stringify(save)} -
    - {/if} -
    { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const response = await fetch('/game-loader?/getEnv', { - method: 'POST', - body: formData, - }); - const result = deserialize(await response.text()); - if (result.type === 'success' && result.data) { - env = result.data.env; - } - }} - > - -
    - {#if env} -
    - {JSON.stringify(env)} -
    - {/if} -
    -
    -
    -
    -
    diff --git a/src/routes/load-project/+page.server.ts b/src/routes/load-project/+page.server.ts deleted file mode 100644 index 4de722e..0000000 --- a/src/routes/load-project/+page.server.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { fail } from '@sveltejs/kit'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; - -import { env } from '$env/dynamic/private'; - -import { authGuard } from '@utils-server/server-api'; - -export const actions = { - loadProject: async ({ request, locals, cookies }) => { - const data = await request.json(); - - const projectPath = data.projectPath; - const projectId = data.projectId; - let absoluteProjectPath: string = ''; - if (projectPath) { - if (env.API_URL) { - return fail(403, { - success: false, - errorMsg: 'Cannot load local project if API_URL is present', - }); - } - absoluteProjectPath = projectPath; - } else if (projectId) { - if (!env.API_URL) { - return fail(403, { success: false, errorMsg: 'Missing API_URL' }); - } - - const serverProjectPath = await authGuard(async (httpClient) => { - return await httpClient.post(`${env.API_URL}/editor/projects/${projectId}`); - }, cookies); - if (serverProjectPath.status !== 200) { - return fail(403, { success: false, errorMsg: 'Cannot retrieve project from API' }); - } - absoluteProjectPath = (await serverProjectPath.json())['projectPath']; - } else { - return fail(403, { - success: false, - creationPanel: env.API_URL ? 'api' : 'local', - errorMsg: `No project provided: ${ - env.API_URL - ? 'Go back to the NanoForge project manager to access a project' - : 'Select or create a local project' - }`, - }); - } - - try { - const stats = fs.lstatSync(absoluteProjectPath); - if (!stats.isDirectory()) { - return fail(403, { - success: false, - errorMsg: `Project folder ${projectPath} is not a folder`, - }); - } - } catch { - return fail(403, { - success: false, - errorMsg: `Project folder ${projectPath} does not exist`, - }); - } - try { - fs.accessSync(absoluteProjectPath, fs.constants.W_OK); - } catch { - return fail(403, { - success: false, - errorMsg: `Project folder ${projectPath} does not have the good rights`, - }); - } - absoluteProjectPath = path.resolve(absoluteProjectPath); - - const session = locals.session; - - await session.setData({ path: absoluteProjectPath }); - await session.save(); - - return { - success: true, - }; - }, -}; diff --git a/src/routes/load-project/+page.svelte b/src/routes/load-project/+page.svelte deleted file mode 100644 index a0f0a0b..0000000 --- a/src/routes/load-project/+page.svelte +++ /dev/null @@ -1,146 +0,0 @@ - - -
    -
    -
    - - Logo - -
    -
    -
    -
    -
    - - -
    - -
    - {#if projectListCache.length > 0} -
    - {#each projectListCache as project (project)} - - {/each} -
    - - {:else} -
    - No project created -
    - {/if} -
    -
    -
    -
    - - - goto(resolve('/'))} -/> diff --git a/src/routes/load-project/load-project.spec.ts b/src/routes/load-project/load-project.spec.ts deleted file mode 100644 index b7ed956..0000000 --- a/src/routes/load-project/load-project.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; - -import { actions } from './+page.server'; - -describe('actions.loadProject', () => { - it('retourne success true avec un projectPath local', async () => { - const session = { - setData: vi.fn(), - save: vi.fn(), - }; - - const event = { - request: { - json: vi.fn().mockResolvedValue({ projectPath: '/tmp' }), - }, - locals: { session }, - cookies: {}, - } as any; - - const result = (await actions.loadProject(event)) as any; - - expect(result.success).toBe(true); - }); -}); diff --git a/src/stores/auth.store.ts b/src/stores/auth.store.ts deleted file mode 100644 index b8fcb5f..0000000 --- a/src/stores/auth.store.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { writable } from 'svelte/store'; - -export const authStore = writable<{ - accessToken: string | null; - refreshToken: string | null; - tokenExpiresAt: Date | null; -}>({ - accessToken: null, - refreshToken: null, - tokenExpiresAt: null, -}); diff --git a/src/stores/project.ts b/src/stores/project.ts deleted file mode 100644 index 74a9c72..0000000 --- a/src/stores/project.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { type Writable, writable } from 'svelte/store'; - -export const projectPathStore: Writable = writable(''); diff --git a/svelte.config.js b/svelte.config.js index 5e2c92e..2552e30 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -14,8 +14,11 @@ export default { }), alias: { '@utils/*': './src/lib/utils/*', - '@utils-client/*': './src/lib/utils-client/*', + '@utils-client/*': './src/lib/client/utils/*', '@utils-server/*': './src/lib/server/utils/*', }, + files: { + assets: 'public', + }, }, }; diff --git a/tsconfig.json b/tsconfig.json index 40b3c10..b6a9dfb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "strict": true, "moduleResolution": "bundler", "types": ["bun"], - "lib": ["DOM.AsyncIterable"] + "lib": ["esnext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"] } // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files diff --git a/uno.config.ts b/uno.config.ts index 80773b1..fe69817 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -11,14 +11,134 @@ import { } from 'unocss'; export default defineConfig({ + theme: { + colors: { + background: 'oklch(var(--background))', + foreground: 'oklch(var(--foreground))', + border: 'oklch(var(--border))', + input: 'oklch(var(--input))', + ring: 'oklch(var(--ring))', + card: { + DEFAULT: 'oklch(var(--card))', + foreground: 'oklch(var(--card-foreground))', + }, + popover: { + DEFAULT: 'oklch(var(--popover))', + foreground: 'oklch(var(--popover-foreground))', + }, + primary: { + DEFAULT: 'oklch(var(--primary))', + foreground: 'oklch(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'oklch(var(--secondary))', + foreground: 'oklch(var(--secondary-foreground))', + }, + muted: { + DEFAULT: 'oklch(var(--muted))', + foreground: 'oklch(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'oklch(var(--accent))', + foreground: 'oklch(var(--accent-foreground))', + }, + success: { + DEFAULT: 'oklch(var(--success))', + foreground: 'oklch(var(--success-foreground))', + }, + destructive: { + DEFAULT: 'oklch(var(--destructive))', + foreground: 'oklch(var(--destructive-foreground))', + }, + }, + }, + rules: [ + // animate-in / animate-out base classes (tailwindcss-animate equivalent) + [ + 'animate-in', + { + 'animation-name': 'enter', + 'animation-duration': 'var(--un-duration,150ms)', + '--un-enter-opacity': 'initial', + '--un-enter-scale': 'initial', + '--un-enter-rotate': 'initial', + '--un-enter-translate-x': 'initial', + '--un-enter-translate-y': 'initial', + }, + ], + [ + 'animate-out', + { + 'animation-name': 'exit', + 'animation-duration': 'var(--un-duration,150ms)', + '--un-exit-opacity': 'initial', + '--un-exit-scale': 'initial', + '--un-exit-rotate': 'initial', + '--un-exit-translate-x': 'initial', + '--un-exit-translate-y': 'initial', + }, + ], + [/^fade-in-(\d+)$/, ([, n]) => ({ '--un-enter-opacity': `${Number(n) / 100}` })], + [/^fade-out-(\d+)$/, ([, n]) => ({ '--un-exit-opacity': `${Number(n) / 100}` })], + [/^zoom-in-(\d+)$/, ([, n]) => ({ '--un-enter-scale': `${Number(n) / 100}` })], + [/^zoom-out-(\d+)$/, ([, n]) => ({ '--un-exit-scale': `${Number(n) / 100}` })], + [ + /^slide-in-from-top-(\d+)$/, + ([, n]) => ({ '--un-enter-translate-y': `-${Number(n) * 0.25}rem` }), + ], + [ + /^slide-in-from-bottom-(\d+)$/, + ([, n]) => ({ '--un-enter-translate-y': `${Number(n) * 0.25}rem` }), + ], + [ + /^slide-in-from-left-(\d+)$/, + ([, n]) => ({ '--un-enter-translate-x': `-${Number(n) * 0.25}rem` }), + ], + [ + /^slide-in-from-right-(\d+)$/, + ([, n]) => ({ '--un-enter-translate-x': `${Number(n) * 0.25}rem` }), + ], + [ + /^slide-out-to-top-(\d+)$/, + ([, n]) => ({ '--un-exit-translate-y': `-${Number(n) * 0.25}rem` }), + ], + [ + /^slide-out-to-bottom-(\d+)$/, + ([, n]) => ({ '--un-exit-translate-y': `${Number(n) * 0.25}rem` }), + ], + [ + /^slide-out-to-left-(\d+)$/, + ([, n]) => ({ '--un-exit-translate-x': `-${Number(n) * 0.25}rem` }), + ], + [ + /^slide-out-to-right-(\d+)$/, + ([, n]) => ({ '--un-exit-translate-x': `${Number(n) * 0.25}rem` }), + ], + ], shortcuts: [ [ - 'btn', - 'px-4 py-1 rounded inline-block bg-teal-700 text-white cursor-pointer !outline-none hover:bg-teal-800 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50', + 'modal-overlay', + 'fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 p-4', + ], + ['modal-card', 'bg-card rounded-2xl w-full max-w-md overflow-hidden'], + ['modal-header', 'px-6 pt-7 pb-5 flex items-center gap-3.5'], + ['modal-body', 'px-6 py-5 flex flex-col gap-5'], + ['modal-footer', 'px-6 pb-6 flex items-center justify-end gap-2'], + [ + 'modal-icon-badge', + 'shrink-0 size-10 rounded-xl bg-primary/10 flex items-center justify-center', + ], + ['modal-divider', 'h-px bg-white/[0.04]'], + [ + 'toggle-row', + 'flex items-center justify-between px-3 py-2.5 rounded-lg hover:bg-muted/40 transition-colors text-left', ], + ['toggle-row-title', 'text-sm text-foreground font-medium leading-tight'], + ['toggle-row-desc', 'text-xs text-muted-foreground mt-0.5'], + ['btn-ghost', 'px-4 py-2 text-sm rounded-lg transition-all duration-150 cursor-pointer'], [ - 'icon-btn', - 'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600', + 'btn-primary', + 'flex items-center hover:bg-primary/80 gap-2 px-5 py-2 text-sm font-medium rounded-lg transition-colors duration-150 disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer', ], ], presets: [ @@ -48,5 +168,6 @@ export default defineConfig({ 'i-ic-baseline-folder', 'i-material-icon-theme-json', 'i-ic-baseline-upload', + 'i-ic-baseline-folder-open', ], });