Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2140d06fb5 | |||
| 6e24b68a08 | |||
| 239bf163e8 | |||
| 16248416e7 | |||
| 7d9ff9ff2b | |||
| 2e16cf9d51 |
@@ -6,5 +6,3 @@ AUTH_NEXTCLOUD_ID=asdf
|
|||||||
AUTH_NEXTCLOUD_SECRET=adsf
|
AUTH_NEXTCLOUD_SECRET=adsf
|
||||||
AUTH_NEXTCLOUD_ISSUER="https://cloud.schreifuchs.ch"
|
AUTH_NEXTCLOUD_ISSUER="https://cloud.schreifuchs.ch"
|
||||||
AUTH_TRUST_HOST=true
|
AUTH_TRUST_HOST=true
|
||||||
|
|
||||||
ECAMP_BASE_URL=http://localhost:3000/api
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Project Review & Refactoring TODOs
|
||||||
|
|
||||||
|
This document contains the prioritized list of refactoring tasks, architectural improvements, and testing strategies for the Aktiteil project.
|
||||||
|
|
||||||
|
## 🚨 Must do (Security & Critical Best Practices)
|
||||||
|
|
||||||
|
- [ ] **Fix Critical XSS Vulnerability (`{@html}` without sanitization)**
|
||||||
|
- **Where:** `src/routes/akti/[aktiId]/+page.svelte`
|
||||||
|
- **Why:** Rendering user input via `{@html data.akti.body}` without sanitization allows malicious scripts to be injected.
|
||||||
|
- **Fix:** Use the already installed `sanitize-html` library on the server to sanitize `changeRequest.body` before updating/inserting into the database.
|
||||||
|
|
||||||
|
- [ ] **Move Server-Only Code to `$lib/server`**
|
||||||
|
- **Where:** `src/lib/auth.ts`
|
||||||
|
- **Why:** It imports from `./server/db`. Keeping server-side dependencies in the general `$lib` folder risks accidental imports by client components, breaking the Vite build and potentially leaking server logic.
|
||||||
|
- **Fix:** Move and rename it to `src/lib/server/session.ts` (or `authUtils.ts`) and update imports in `.server.ts` files.
|
||||||
|
|
||||||
|
- [ ] **Fix Action Validation Error Handling**
|
||||||
|
- **Where:** `src/routes/akti/[aktiId]/+page.server.ts` and `src/routes/akti/[aktiId]/comment/+page.server.ts`
|
||||||
|
- **Why:** Currently returning `error(400)` on validation failure, which wipes form data and shows a generic error page.
|
||||||
|
- **Fix:** Use SvelteKit's `fail(400, { message: 'Invalid data' })` to keep the user on the page and preserve their input.
|
||||||
|
|
||||||
|
- [ ] **Fix Hacky Fallback in Auth Query**
|
||||||
|
- **Where:** `src/lib/auth.ts` -> `getSession()`
|
||||||
|
- **Why:** Querying the DB with a fallback UUID (`eaf930...`) when email is missing is an anti-pattern.
|
||||||
|
- **Fix:** Implement an early return (`if (!session?.user?.email) return null;`) before hitting the database.
|
||||||
|
|
||||||
|
## 🛠️ Should do (Performance & Architecture)
|
||||||
|
|
||||||
|
- [ ] **Parallelize Database Queries**
|
||||||
|
- **Where:** `src/routes/akti/[aktiId]/+page.server.ts` (load function)
|
||||||
|
- **Why:** Queries are running sequentially.
|
||||||
|
- **Fix:** Use `Promise.all([ db.query.aktis.findFirst(...), db.query.ratings.findMany(...) ])` to run concurrently.
|
||||||
|
|
||||||
|
- [ ] **Implement Pagination / Limit for the Dashboard**
|
||||||
|
- **Where:** `src/routes/+page.server.ts`
|
||||||
|
- **Why:** Querying all records joined with ratings will scale poorly.
|
||||||
|
- **Fix:** Add a `.limit()` clause and consider basic pagination or infinite scrolling.
|
||||||
|
|
||||||
|
- [ ] **Extend Auth.js Types Globally**
|
||||||
|
- **Where:** `src/app.d.ts`
|
||||||
|
- **Why:** TypeScript doesn't inherently know `session.user.id` exists, leading to hacky workarounds.
|
||||||
|
- **Fix:** Override `@auth/sveltekit` Session types in `app.d.ts` to include `id` and `email` strictly.
|
||||||
|
|
||||||
|
- [ ] **Consider Adopting a Form Library**
|
||||||
|
- **Where:** `src/lib/extractFormData.ts`
|
||||||
|
- **Why:** Custom form extractors lack instant client-side validation and seamless server-side error mapping.
|
||||||
|
- **Fix:** Consider switching to `sveltekit-superforms` which integrates well with Valibot.
|
||||||
|
|
||||||
|
## ✨ Nice to have (UX & Polish)
|
||||||
|
|
||||||
|
- [ ] **Clarify File Naming (`auth.ts` vs `auth.ts`)**
|
||||||
|
- Rename `src/lib/auth.ts` to `session.ts` or similar to distinguish from `src/auth.ts` (Auth.js setup).
|
||||||
|
|
||||||
|
- [ ] **Abstract Heavy Database Queries**
|
||||||
|
- Move complex aggregations (like computing averages in `src/routes/+page.server.ts`) into a dedicated `src/lib/server/db/queries.ts` file to keep routes clean.
|
||||||
|
|
||||||
|
- [ ] **Clean up Redundant Imports**
|
||||||
|
- In `src/routes/+layout.server.ts`, change `import { getSession as getSession }` to `import { getSession }`.
|
||||||
|
|
||||||
|
## 🧪 Testing Plan
|
||||||
|
|
||||||
|
- [ ] **Add Playwright (End-to-End Testing)**
|
||||||
|
- Install Playwright to test SvelteKit server actions, DB integration, and Flowbite forms holistically.
|
||||||
|
- [ ] **Add Vitest + Svelte Testing Library (Unit/Component Testing)**
|
||||||
|
- Set up Vitest to test UI components (`AktiCard`, `AktiEditor`) and utility functions (`extractFormData`) in isolation.
|
||||||
+1
-1
@@ -3,7 +3,7 @@ services:
|
|||||||
image: postgres
|
image: postgres
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 5433:5432
|
- 5432:5432
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: root
|
POSTGRES_USER: root
|
||||||
POSTGRES_PASSWORD: mysecretpassword
|
POSTGRES_PASSWORD: mysecretpassword
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import svelteConfig from './svelte.config.js';
|
|||||||
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
|
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
|
||||||
|
|
||||||
export default defineConfig(
|
export default defineConfig(
|
||||||
{ ignores: ['src/lib/server/ecamp/clent/**'] },
|
|
||||||
includeIgnoreFile(gitignorePath),
|
includeIgnoreFile(gitignorePath),
|
||||||
js.configs.recommended,
|
js.configs.recommended,
|
||||||
...ts.configs.recommended,
|
...ts.configs.recommended,
|
||||||
|
|||||||
+2
-4
@@ -16,8 +16,7 @@
|
|||||||
"db:push": "drizzle-kit push",
|
"db:push": "drizzle-kit push",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
"db:migrate": "drizzle-kit migrate",
|
"db:migrate": "drizzle-kit migrate",
|
||||||
"db:studio": "drizzle-kit studio",
|
"db:studio": "drizzle-kit studio"
|
||||||
"ecamp:generate": "openapi-ts -i src/lib/server/ecamp/openapi.yaml -o src/lib/server/ecamp/clent"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@auth/core": "0.41.1",
|
"@auth/core": "0.41.1",
|
||||||
@@ -25,13 +24,13 @@
|
|||||||
"@eslint/compat": "^1.4.1",
|
"@eslint/compat": "^1.4.1",
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
"@flowbite-svelte-plugins/texteditor": "^0.25.6",
|
"@flowbite-svelte-plugins/texteditor": "^0.25.6",
|
||||||
"@hey-api/openapi-ts": "0.94.5",
|
|
||||||
"@sveltejs/adapter-node": "^5.4.0",
|
"@sveltejs/adapter-node": "^5.4.0",
|
||||||
"@sveltejs/kit": "^2.49.0",
|
"@sveltejs/kit": "^2.49.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||||
"@tailwindcss/vite": "^4.1.17",
|
"@tailwindcss/vite": "^4.1.17",
|
||||||
"@tiptap/core": "3.7.2",
|
"@tiptap/core": "3.7.2",
|
||||||
"@types/node": "^20.19.25",
|
"@types/node": "^20.19.25",
|
||||||
|
"@types/sanitize-html": "^2.16.1",
|
||||||
"drizzle-kit": "^0.31.7",
|
"drizzle-kit": "^0.31.7",
|
||||||
"drizzle-orm": "^0.44.7",
|
"drizzle-orm": "^0.44.7",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
@@ -56,7 +55,6 @@
|
|||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"postgres": "^3.4.7",
|
"postgres": "^3.4.7",
|
||||||
"sanitize-html": "^2.17.0",
|
"sanitize-html": "^2.17.0",
|
||||||
"set-cookie-parser": "^3.1.0",
|
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
"valibot": "^1.1.0"
|
"valibot": "^1.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+26
-356
@@ -20,9 +20,6 @@ importers:
|
|||||||
sanitize-html:
|
sanitize-html:
|
||||||
specifier: ^2.17.0
|
specifier: ^2.17.0
|
||||||
version: 2.17.0
|
version: 2.17.0
|
||||||
set-cookie-parser:
|
|
||||||
specifier: ^3.1.0
|
|
||||||
version: 3.1.0
|
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^3.4.0
|
specifier: ^3.4.0
|
||||||
version: 3.4.0
|
version: 3.4.0
|
||||||
@@ -45,9 +42,6 @@ importers:
|
|||||||
'@flowbite-svelte-plugins/texteditor':
|
'@flowbite-svelte-plugins/texteditor':
|
||||||
specifier: ^0.25.6
|
specifier: ^0.25.6
|
||||||
version: 0.25.6(@tiptap/extension-collaboration@2.27.1(@tiptap/core@3.7.2(@tiptap/pm@3.7.2))(@tiptap/pm@3.7.2)(y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27)))(emojibase@17.0.0)(highlight.js@11.11.1)(svelte@5.43.14)(tailwindcss@4.1.17)(y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))
|
version: 0.25.6(@tiptap/extension-collaboration@2.27.1(@tiptap/core@3.7.2(@tiptap/pm@3.7.2))(@tiptap/pm@3.7.2)(y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27)))(emojibase@17.0.0)(highlight.js@11.11.1)(svelte@5.43.14)(tailwindcss@4.1.17)(y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))
|
||||||
'@hey-api/openapi-ts':
|
|
||||||
specifier: 0.94.5
|
|
||||||
version: 0.94.5(typescript@5.9.3)
|
|
||||||
'@sveltejs/adapter-node':
|
'@sveltejs/adapter-node':
|
||||||
specifier: ^5.4.0
|
specifier: ^5.4.0
|
||||||
version: 5.4.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.43.14)(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)))
|
version: 5.4.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.43.14)(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)))
|
||||||
@@ -66,6 +60,9 @@ importers:
|
|||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.19.25
|
specifier: ^20.19.25
|
||||||
version: 20.19.25
|
version: 20.19.25
|
||||||
|
'@types/sanitize-html':
|
||||||
|
specifier: ^2.16.1
|
||||||
|
version: 2.16.1
|
||||||
drizzle-kit:
|
drizzle-kit:
|
||||||
specifier: ^0.31.7
|
specifier: ^0.31.7
|
||||||
version: 0.31.7
|
version: 0.31.7
|
||||||
@@ -521,31 +518,6 @@ packages:
|
|||||||
svelte: ^5.0.0
|
svelte: ^5.0.0
|
||||||
tailwindcss: ^4.1.4
|
tailwindcss: ^4.1.4
|
||||||
|
|
||||||
'@hey-api/codegen-core@0.7.4':
|
|
||||||
resolution: {integrity: sha512-DGd9yeSQzflOWO3Y5mt1GRXkXH9O/yIMgbxPjwLI3jwu/3nAjoXXD26lEeFb6tclYlg0JAqTIs5d930G/qxHeA==}
|
|
||||||
engines: {node: '>=20.19.0'}
|
|
||||||
|
|
||||||
'@hey-api/json-schema-ref-parser@1.3.1':
|
|
||||||
resolution: {integrity: sha512-7atnpUkT8TyUPHYPLk91j/GyaqMuwTEHanLOe50Dlx0EEvNuQqFD52Yjg8x4KU0UFL1mWlyhE+sUE/wAtQ1N2A==}
|
|
||||||
engines: {node: '>=20.19.0'}
|
|
||||||
|
|
||||||
'@hey-api/openapi-ts@0.94.5':
|
|
||||||
resolution: {integrity: sha512-fCR/kIexbDarnt/WGKvjJb4K30JaFzO2F/528kHpyWT7vopPS0JeqtRQMjJg+Gk09N/05nbv1OaFOQXcy0BiVQ==}
|
|
||||||
engines: {node: '>=20.19.0'}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
typescript: '>=5.5.3 || >=6.0.0 || 6.0.1-rc'
|
|
||||||
|
|
||||||
'@hey-api/shared@0.2.6':
|
|
||||||
resolution: {integrity: sha512-ZZrsWbazJcJO688tJVEBeei03B4miPI7OauW+qLMYP/9KL6NadmA5MjqsIIwgfvb0HKMAR7lt4AINKzv0Zwdgw==}
|
|
||||||
engines: {node: '>=20.19.0'}
|
|
||||||
|
|
||||||
'@hey-api/spec-types@0.1.0':
|
|
||||||
resolution: {integrity: sha512-StS4RrAO5pyJCBwe6uF9MAuPflkztriW+FPnVb7oEjzDYv1sxPwP+f7fL6u6D+UVrKpZ/9bPNx/xXVdkeWPU6A==}
|
|
||||||
|
|
||||||
'@hey-api/types@0.1.4':
|
|
||||||
resolution: {integrity: sha512-thWfawrDIP7wSI9ioT13I5soaaqB5vAPIiZmgD8PbeEVKNrkonc0N/Sjj97ezl7oQgusZmaNphGdMKipPO6IBg==}
|
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
@@ -578,9 +550,6 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
'@jsdevtools/ono@7.1.3':
|
|
||||||
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
|
|
||||||
|
|
||||||
'@panva/hkdf@1.2.1':
|
'@panva/hkdf@1.2.1':
|
||||||
resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
|
resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
|
||||||
|
|
||||||
@@ -1281,6 +1250,9 @@ packages:
|
|||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
|
'@types/sanitize-html@2.16.1':
|
||||||
|
resolution: {integrity: sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==}
|
||||||
|
|
||||||
'@types/unist@3.0.3':
|
'@types/unist@3.0.3':
|
||||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||||
|
|
||||||
@@ -1359,10 +1331,6 @@ packages:
|
|||||||
ajv@6.12.6:
|
ajv@6.12.6:
|
||||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||||
|
|
||||||
ansi-colors@4.1.3:
|
|
||||||
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
|
|
||||||
ansi-styles@4.3.0:
|
ansi-styles@4.3.0:
|
||||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1393,18 +1361,6 @@ packages:
|
|||||||
buffer-from@1.1.2:
|
buffer-from@1.1.2:
|
||||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
bundle-name@4.1.0:
|
|
||||||
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
c12@3.3.3:
|
|
||||||
resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==}
|
|
||||||
peerDependencies:
|
|
||||||
magicast: '*'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
magicast:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
callsites@3.1.0:
|
callsites@3.1.0:
|
||||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -1417,16 +1373,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||||
engines: {node: '>= 14.16.0'}
|
engines: {node: '>= 14.16.0'}
|
||||||
|
|
||||||
chokidar@5.0.0:
|
|
||||||
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
|
|
||||||
engines: {node: '>= 20.19.0'}
|
|
||||||
|
|
||||||
citty@0.1.6:
|
|
||||||
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
|
|
||||||
|
|
||||||
citty@0.2.1:
|
|
||||||
resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==}
|
|
||||||
|
|
||||||
clsx@2.1.1:
|
clsx@2.1.1:
|
||||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -1438,14 +1384,6 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
color-support@1.1.3:
|
|
||||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
commander@14.0.3:
|
|
||||||
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
|
|
||||||
engines: {node: '>=20'}
|
|
||||||
|
|
||||||
commander@8.3.0:
|
commander@8.3.0:
|
||||||
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
|
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
@@ -1456,13 +1394,6 @@ packages:
|
|||||||
concat-map@0.0.1:
|
concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
|
||||||
confbox@0.2.4:
|
|
||||||
resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==}
|
|
||||||
|
|
||||||
consola@3.4.2:
|
|
||||||
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
|
|
||||||
engines: {node: ^14.18.0 || >=16.10.0}
|
|
||||||
|
|
||||||
cookie@0.6.0:
|
cookie@0.6.0:
|
||||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -1498,28 +1429,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
default-browser-id@5.0.1:
|
|
||||||
resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
default-browser@5.5.0:
|
|
||||||
resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
define-lazy-prop@3.0.0:
|
|
||||||
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
|
|
||||||
defu@6.1.4:
|
|
||||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
|
||||||
|
|
||||||
dequal@2.0.3:
|
dequal@2.0.3:
|
||||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
destr@2.0.5:
|
|
||||||
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
|
||||||
|
|
||||||
detect-libc@2.1.2:
|
detect-libc@2.1.2:
|
||||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1543,10 +1456,6 @@ packages:
|
|||||||
domutils@3.2.2:
|
domutils@3.2.2:
|
||||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||||
|
|
||||||
dotenv@17.3.1:
|
|
||||||
resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
|
|
||||||
drizzle-kit@0.31.7:
|
drizzle-kit@0.31.7:
|
||||||
resolution: {integrity: sha512-hOzRGSdyKIU4FcTSFYGKdXEjFsncVwHZ43gY3WU5Bz9j5Iadp6Rh6hxLSQ1IWXpKLBKt/d5y1cpSPcV+FcoQ1A==}
|
resolution: {integrity: sha512-hOzRGSdyKIU4FcTSFYGKdXEjFsncVwHZ43gY3WU5Bz9j5Iadp6Rh6hxLSQ1IWXpKLBKt/d5y1cpSPcV+FcoQ1A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1663,6 +1572,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
|
entities@7.0.1:
|
||||||
|
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
esbuild-register@3.6.0:
|
esbuild-register@3.6.0:
|
||||||
resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
|
resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1743,9 +1656,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
exsolve@1.0.8:
|
|
||||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
|
||||||
|
|
||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
@@ -1819,13 +1729,6 @@ packages:
|
|||||||
get-tsconfig@4.13.0:
|
get-tsconfig@4.13.0:
|
||||||
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
||||||
|
|
||||||
get-tsconfig@4.13.6:
|
|
||||||
resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==}
|
|
||||||
|
|
||||||
giget@2.0.0:
|
|
||||||
resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
glob-parent@6.0.2:
|
glob-parent@6.0.2:
|
||||||
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
|
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
@@ -1856,6 +1759,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
|
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
htmlparser2@10.1.0:
|
||||||
|
resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==}
|
||||||
|
|
||||||
htmlparser2@8.0.2:
|
htmlparser2@8.0.2:
|
||||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||||
|
|
||||||
@@ -1884,11 +1790,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-docker@3.0.0:
|
|
||||||
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
is-emoji-supported@0.0.5:
|
is-emoji-supported@0.0.5:
|
||||||
resolution: {integrity: sha512-WOlXUhDDHxYqcSmFZis+xWhhqXiK2SU0iYiqmth5Ip0FHLZQAt9rKL5ahnilE8/86WH8tZ3bmNNNC+bTzamqlw==}
|
resolution: {integrity: sha512-WOlXUhDDHxYqcSmFZis+xWhhqXiK2SU0iYiqmth5Ip0FHLZQAt9rKL5ahnilE8/86WH8tZ3bmNNNC+bTzamqlw==}
|
||||||
|
|
||||||
@@ -1900,15 +1801,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
is-in-ssh@1.0.0:
|
|
||||||
resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==}
|
|
||||||
engines: {node: '>=20'}
|
|
||||||
|
|
||||||
is-inside-container@1.0.0:
|
|
||||||
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
|
|
||||||
engines: {node: '>=14.16'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
is-module@1.0.0:
|
is-module@1.0.0:
|
||||||
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||||
|
|
||||||
@@ -1922,10 +1814,6 @@ packages:
|
|||||||
is-reference@3.0.3:
|
is-reference@3.0.3:
|
||||||
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
|
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
|
||||||
|
|
||||||
is-wsl@3.1.1:
|
|
||||||
resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
|
|
||||||
engines: {node: '>=16'}
|
|
||||||
|
|
||||||
isexe@2.0.0:
|
isexe@2.0.0:
|
||||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
|
|
||||||
@@ -2118,24 +2006,9 @@ packages:
|
|||||||
natural-compare@1.4.0:
|
natural-compare@1.4.0:
|
||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
|
|
||||||
node-fetch-native@1.6.7:
|
|
||||||
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
|
|
||||||
|
|
||||||
nypm@0.6.5:
|
|
||||||
resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
oauth4webapi@3.8.3:
|
oauth4webapi@3.8.3:
|
||||||
resolution: {integrity: sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw==}
|
resolution: {integrity: sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw==}
|
||||||
|
|
||||||
ohash@2.0.11:
|
|
||||||
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
|
||||||
|
|
||||||
open@11.0.0:
|
|
||||||
resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==}
|
|
||||||
engines: {node: '>=20'}
|
|
||||||
|
|
||||||
optionator@0.9.4:
|
optionator@0.9.4:
|
||||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -2169,12 +2042,6 @@ packages:
|
|||||||
path-parse@1.0.7:
|
path-parse@1.0.7:
|
||||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
|
|
||||||
pathe@2.0.3:
|
|
||||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
|
||||||
|
|
||||||
perfect-debounce@2.1.0:
|
|
||||||
resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==}
|
|
||||||
|
|
||||||
picocolors@1.1.1:
|
picocolors@1.1.1:
|
||||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
@@ -2182,9 +2049,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
pkg-types@2.3.0:
|
|
||||||
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
|
|
||||||
|
|
||||||
postcss-load-config@3.1.4:
|
postcss-load-config@3.1.4:
|
||||||
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
|
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
@@ -2221,10 +2085,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==}
|
resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
powershell-utils@0.1.0:
|
|
||||||
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
|
|
||||||
engines: {node: '>=20'}
|
|
||||||
|
|
||||||
preact-render-to-string@6.5.11:
|
preact-render-to-string@6.5.11:
|
||||||
resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==}
|
resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2314,17 +2174,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
rc9@2.1.2:
|
|
||||||
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
|
|
||||||
|
|
||||||
readdirp@4.1.2:
|
readdirp@4.1.2:
|
||||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||||
engines: {node: '>= 14.18.0'}
|
engines: {node: '>= 14.18.0'}
|
||||||
|
|
||||||
readdirp@5.0.0:
|
|
||||||
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
|
||||||
engines: {node: '>= 20.19.0'}
|
|
||||||
|
|
||||||
resolve-from@4.0.0:
|
resolve-from@4.0.0:
|
||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -2345,10 +2198,6 @@ packages:
|
|||||||
rope-sequence@1.3.4:
|
rope-sequence@1.3.4:
|
||||||
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
|
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
|
||||||
|
|
||||||
run-applescript@7.1.0:
|
|
||||||
resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
sade@1.8.1:
|
sade@1.8.1:
|
||||||
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2364,9 +2213,6 @@ packages:
|
|||||||
set-cookie-parser@2.7.2:
|
set-cookie-parser@2.7.2:
|
||||||
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
||||||
|
|
||||||
set-cookie-parser@3.1.0:
|
|
||||||
resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==}
|
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -2443,10 +2289,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
tinyexec@1.0.4:
|
|
||||||
resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
tinyglobby@0.2.15:
|
tinyglobby@0.2.15:
|
||||||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -2564,10 +2406,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
wsl-utils@0.3.1:
|
|
||||||
resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==}
|
|
||||||
engines: {node: '>=20'}
|
|
||||||
|
|
||||||
y-prosemirror@1.3.7:
|
y-prosemirror@1.3.7:
|
||||||
resolution: {integrity: sha512-NpM99WSdD4Fx4if5xOMDpPtU3oAmTSjlzh5U4353ABbRHl1HtAFUx6HlebLZfyFxXN9jzKMDkVbcRjqOZVkYQg==}
|
resolution: {integrity: sha512-NpM99WSdD4Fx4if5xOMDpPtU3oAmTSjlzh5U4353ABbRHl1HtAFUx6HlebLZfyFxXN9jzKMDkVbcRjqOZVkYQg==}
|
||||||
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
|
||||||
@@ -2917,55 +2755,6 @@ snapshots:
|
|||||||
- highlight.js
|
- highlight.js
|
||||||
- y-prosemirror
|
- y-prosemirror
|
||||||
|
|
||||||
'@hey-api/codegen-core@0.7.4':
|
|
||||||
dependencies:
|
|
||||||
'@hey-api/types': 0.1.4
|
|
||||||
ansi-colors: 4.1.3
|
|
||||||
c12: 3.3.3
|
|
||||||
color-support: 1.1.3
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- magicast
|
|
||||||
|
|
||||||
'@hey-api/json-schema-ref-parser@1.3.1':
|
|
||||||
dependencies:
|
|
||||||
'@jsdevtools/ono': 7.1.3
|
|
||||||
'@types/json-schema': 7.0.15
|
|
||||||
js-yaml: 4.1.1
|
|
||||||
|
|
||||||
'@hey-api/openapi-ts@0.94.5(typescript@5.9.3)':
|
|
||||||
dependencies:
|
|
||||||
'@hey-api/codegen-core': 0.7.4
|
|
||||||
'@hey-api/json-schema-ref-parser': 1.3.1
|
|
||||||
'@hey-api/shared': 0.2.6
|
|
||||||
'@hey-api/spec-types': 0.1.0
|
|
||||||
'@hey-api/types': 0.1.4
|
|
||||||
ansi-colors: 4.1.3
|
|
||||||
color-support: 1.1.3
|
|
||||||
commander: 14.0.3
|
|
||||||
get-tsconfig: 4.13.6
|
|
||||||
typescript: 5.9.3
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- magicast
|
|
||||||
|
|
||||||
'@hey-api/shared@0.2.6':
|
|
||||||
dependencies:
|
|
||||||
'@hey-api/codegen-core': 0.7.4
|
|
||||||
'@hey-api/json-schema-ref-parser': 1.3.1
|
|
||||||
'@hey-api/spec-types': 0.1.0
|
|
||||||
'@hey-api/types': 0.1.4
|
|
||||||
ansi-colors: 4.1.3
|
|
||||||
cross-spawn: 7.0.6
|
|
||||||
open: 11.0.0
|
|
||||||
semver: 7.7.3
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- magicast
|
|
||||||
|
|
||||||
'@hey-api/spec-types@0.1.0':
|
|
||||||
dependencies:
|
|
||||||
'@hey-api/types': 0.1.4
|
|
||||||
|
|
||||||
'@hey-api/types@0.1.4': {}
|
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
'@humanfs/node@0.16.7':
|
'@humanfs/node@0.16.7':
|
||||||
@@ -2996,8 +2785,6 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
'@jsdevtools/ono@7.1.3': {}
|
|
||||||
|
|
||||||
'@panva/hkdf@1.2.1': {}
|
'@panva/hkdf@1.2.1': {}
|
||||||
|
|
||||||
'@polka/url@1.0.0-next.29': {}
|
'@polka/url@1.0.0-next.29': {}
|
||||||
@@ -3617,6 +3404,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/resolve@1.20.2': {}
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
|
'@types/sanitize-html@2.16.1':
|
||||||
|
dependencies:
|
||||||
|
htmlparser2: 10.1.0
|
||||||
|
|
||||||
'@types/unist@3.0.3': {}
|
'@types/unist@3.0.3': {}
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)':
|
'@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)':
|
||||||
@@ -3726,8 +3517,6 @@ snapshots:
|
|||||||
json-schema-traverse: 0.4.1
|
json-schema-traverse: 0.4.1
|
||||||
uri-js: 4.4.1
|
uri-js: 4.4.1
|
||||||
|
|
||||||
ansi-colors@4.1.3: {}
|
|
||||||
|
|
||||||
ansi-styles@4.3.0:
|
ansi-styles@4.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-convert: 2.0.1
|
color-convert: 2.0.1
|
||||||
@@ -3760,25 +3549,6 @@ snapshots:
|
|||||||
|
|
||||||
buffer-from@1.1.2: {}
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
bundle-name@4.1.0:
|
|
||||||
dependencies:
|
|
||||||
run-applescript: 7.1.0
|
|
||||||
|
|
||||||
c12@3.3.3:
|
|
||||||
dependencies:
|
|
||||||
chokidar: 5.0.0
|
|
||||||
confbox: 0.2.4
|
|
||||||
defu: 6.1.4
|
|
||||||
dotenv: 17.3.1
|
|
||||||
exsolve: 1.0.8
|
|
||||||
giget: 2.0.0
|
|
||||||
jiti: 2.6.1
|
|
||||||
ohash: 2.0.11
|
|
||||||
pathe: 2.0.3
|
|
||||||
perfect-debounce: 2.1.0
|
|
||||||
pkg-types: 2.3.0
|
|
||||||
rc9: 2.1.2
|
|
||||||
|
|
||||||
callsites@3.1.0: {}
|
callsites@3.1.0: {}
|
||||||
|
|
||||||
chalk@4.1.2:
|
chalk@4.1.2:
|
||||||
@@ -3790,16 +3560,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
readdirp: 4.1.2
|
readdirp: 4.1.2
|
||||||
|
|
||||||
chokidar@5.0.0:
|
|
||||||
dependencies:
|
|
||||||
readdirp: 5.0.0
|
|
||||||
|
|
||||||
citty@0.1.6:
|
|
||||||
dependencies:
|
|
||||||
consola: 3.4.2
|
|
||||||
|
|
||||||
citty@0.2.1: {}
|
|
||||||
|
|
||||||
clsx@2.1.1: {}
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
@@ -3808,20 +3568,12 @@ snapshots:
|
|||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
color-support@1.1.3: {}
|
|
||||||
|
|
||||||
commander@14.0.3: {}
|
|
||||||
|
|
||||||
commander@8.3.0: {}
|
commander@8.3.0: {}
|
||||||
|
|
||||||
commondir@1.0.1: {}
|
commondir@1.0.1: {}
|
||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
|
||||||
confbox@0.2.4: {}
|
|
||||||
|
|
||||||
consola@3.4.2: {}
|
|
||||||
|
|
||||||
cookie@0.6.0: {}
|
cookie@0.6.0: {}
|
||||||
|
|
||||||
crelt@1.0.6: {}
|
crelt@1.0.6: {}
|
||||||
@@ -3844,21 +3596,8 @@ snapshots:
|
|||||||
|
|
||||||
deepmerge@4.3.1: {}
|
deepmerge@4.3.1: {}
|
||||||
|
|
||||||
default-browser-id@5.0.1: {}
|
|
||||||
|
|
||||||
default-browser@5.5.0:
|
|
||||||
dependencies:
|
|
||||||
bundle-name: 4.1.0
|
|
||||||
default-browser-id: 5.0.1
|
|
||||||
|
|
||||||
define-lazy-prop@3.0.0: {}
|
|
||||||
|
|
||||||
defu@6.1.4: {}
|
|
||||||
|
|
||||||
dequal@2.0.3: {}
|
dequal@2.0.3: {}
|
||||||
|
|
||||||
destr@2.0.5: {}
|
|
||||||
|
|
||||||
detect-libc@2.1.2: {}
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
devalue@5.5.0: {}
|
devalue@5.5.0: {}
|
||||||
@@ -3885,8 +3624,6 @@ snapshots:
|
|||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
domhandler: 5.0.3
|
domhandler: 5.0.3
|
||||||
|
|
||||||
dotenv@17.3.1: {}
|
|
||||||
|
|
||||||
drizzle-kit@0.31.7:
|
drizzle-kit@0.31.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@drizzle-team/brocli': 0.10.2
|
'@drizzle-team/brocli': 0.10.2
|
||||||
@@ -3915,6 +3652,8 @@ snapshots:
|
|||||||
|
|
||||||
entities@4.5.0: {}
|
entities@4.5.0: {}
|
||||||
|
|
||||||
|
entities@7.0.1: {}
|
||||||
|
|
||||||
esbuild-register@3.6.0(esbuild@0.25.12):
|
esbuild-register@3.6.0(esbuild@0.25.12):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
@@ -4072,8 +3811,6 @@ snapshots:
|
|||||||
|
|
||||||
esutils@2.0.3: {}
|
esutils@2.0.3: {}
|
||||||
|
|
||||||
exsolve@1.0.8: {}
|
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
fast-json-stable-stringify@2.1.0: {}
|
fast-json-stable-stringify@2.1.0: {}
|
||||||
@@ -4178,19 +3915,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
resolve-pkg-maps: 1.0.0
|
resolve-pkg-maps: 1.0.0
|
||||||
|
|
||||||
get-tsconfig@4.13.6:
|
|
||||||
dependencies:
|
|
||||||
resolve-pkg-maps: 1.0.0
|
|
||||||
|
|
||||||
giget@2.0.0:
|
|
||||||
dependencies:
|
|
||||||
citty: 0.1.6
|
|
||||||
consola: 3.4.2
|
|
||||||
defu: 6.1.4
|
|
||||||
node-fetch-native: 1.6.7
|
|
||||||
nypm: 0.6.5
|
|
||||||
pathe: 2.0.3
|
|
||||||
|
|
||||||
glob-parent@6.0.2:
|
glob-parent@6.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
@@ -4211,6 +3935,13 @@ snapshots:
|
|||||||
|
|
||||||
highlight.js@11.11.1: {}
|
highlight.js@11.11.1: {}
|
||||||
|
|
||||||
|
htmlparser2@10.1.0:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
domutils: 3.2.2
|
||||||
|
entities: 7.0.1
|
||||||
|
|
||||||
htmlparser2@8.0.2:
|
htmlparser2@8.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
@@ -4235,8 +3966,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
||||||
is-docker@3.0.0: {}
|
|
||||||
|
|
||||||
is-emoji-supported@0.0.5: {}
|
is-emoji-supported@0.0.5: {}
|
||||||
|
|
||||||
is-extglob@2.1.1: {}
|
is-extglob@2.1.1: {}
|
||||||
@@ -4245,12 +3974,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-extglob: 2.1.1
|
is-extglob: 2.1.1
|
||||||
|
|
||||||
is-in-ssh@1.0.0: {}
|
|
||||||
|
|
||||||
is-inside-container@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
is-docker: 3.0.0
|
|
||||||
|
|
||||||
is-module@1.0.0: {}
|
is-module@1.0.0: {}
|
||||||
|
|
||||||
is-plain-object@5.0.0: {}
|
is-plain-object@5.0.0: {}
|
||||||
@@ -4263,10 +3986,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.8
|
'@types/estree': 1.0.8
|
||||||
|
|
||||||
is-wsl@3.1.1:
|
|
||||||
dependencies:
|
|
||||||
is-inside-container: 1.0.0
|
|
||||||
|
|
||||||
isexe@2.0.0: {}
|
isexe@2.0.0: {}
|
||||||
|
|
||||||
isomorphic.js@0.2.5: {}
|
isomorphic.js@0.2.5: {}
|
||||||
@@ -4416,27 +4135,8 @@ snapshots:
|
|||||||
|
|
||||||
natural-compare@1.4.0: {}
|
natural-compare@1.4.0: {}
|
||||||
|
|
||||||
node-fetch-native@1.6.7: {}
|
|
||||||
|
|
||||||
nypm@0.6.5:
|
|
||||||
dependencies:
|
|
||||||
citty: 0.2.1
|
|
||||||
pathe: 2.0.3
|
|
||||||
tinyexec: 1.0.4
|
|
||||||
|
|
||||||
oauth4webapi@3.8.3: {}
|
oauth4webapi@3.8.3: {}
|
||||||
|
|
||||||
ohash@2.0.11: {}
|
|
||||||
|
|
||||||
open@11.0.0:
|
|
||||||
dependencies:
|
|
||||||
default-browser: 5.5.0
|
|
||||||
define-lazy-prop: 3.0.0
|
|
||||||
is-in-ssh: 1.0.0
|
|
||||||
is-inside-container: 1.0.0
|
|
||||||
powershell-utils: 0.1.0
|
|
||||||
wsl-utils: 0.3.1
|
|
||||||
|
|
||||||
optionator@0.9.4:
|
optionator@0.9.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-is: 0.1.4
|
deep-is: 0.1.4
|
||||||
@@ -4468,20 +4168,10 @@ snapshots:
|
|||||||
|
|
||||||
path-parse@1.0.7: {}
|
path-parse@1.0.7: {}
|
||||||
|
|
||||||
pathe@2.0.3: {}
|
|
||||||
|
|
||||||
perfect-debounce@2.1.0: {}
|
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
picomatch@4.0.3: {}
|
picomatch@4.0.3: {}
|
||||||
|
|
||||||
pkg-types@2.3.0:
|
|
||||||
dependencies:
|
|
||||||
confbox: 0.2.4
|
|
||||||
exsolve: 1.0.8
|
|
||||||
pathe: 2.0.3
|
|
||||||
|
|
||||||
postcss-load-config@3.1.4(postcss@8.5.6):
|
postcss-load-config@3.1.4(postcss@8.5.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 2.1.0
|
lilconfig: 2.1.0
|
||||||
@@ -4510,8 +4200,6 @@ snapshots:
|
|||||||
|
|
||||||
postgres@3.4.7: {}
|
postgres@3.4.7: {}
|
||||||
|
|
||||||
powershell-utils@0.1.0: {}
|
|
||||||
|
|
||||||
preact-render-to-string@6.5.11(preact@10.24.3):
|
preact-render-to-string@6.5.11(preact@10.24.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
preact: 10.24.3
|
preact: 10.24.3
|
||||||
@@ -4634,15 +4322,8 @@ snapshots:
|
|||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
rc9@2.1.2:
|
|
||||||
dependencies:
|
|
||||||
defu: 6.1.4
|
|
||||||
destr: 2.0.5
|
|
||||||
|
|
||||||
readdirp@4.1.2: {}
|
readdirp@4.1.2: {}
|
||||||
|
|
||||||
readdirp@5.0.0: {}
|
|
||||||
|
|
||||||
resolve-from@4.0.0: {}
|
resolve-from@4.0.0: {}
|
||||||
|
|
||||||
resolve-pkg-maps@1.0.0: {}
|
resolve-pkg-maps@1.0.0: {}
|
||||||
@@ -4683,8 +4364,6 @@ snapshots:
|
|||||||
|
|
||||||
rope-sequence@1.3.4: {}
|
rope-sequence@1.3.4: {}
|
||||||
|
|
||||||
run-applescript@7.1.0: {}
|
|
||||||
|
|
||||||
sade@1.8.1:
|
sade@1.8.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
mri: 1.2.0
|
mri: 1.2.0
|
||||||
@@ -4702,8 +4381,6 @@ snapshots:
|
|||||||
|
|
||||||
set-cookie-parser@2.7.2: {}
|
set-cookie-parser@2.7.2: {}
|
||||||
|
|
||||||
set-cookie-parser@3.1.0: {}
|
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
@@ -4785,8 +4462,6 @@ snapshots:
|
|||||||
|
|
||||||
tapable@2.3.0: {}
|
tapable@2.3.0: {}
|
||||||
|
|
||||||
tinyexec@1.0.4: {}
|
|
||||||
|
|
||||||
tinyglobby@0.2.15:
|
tinyglobby@0.2.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -4861,11 +4536,6 @@ snapshots:
|
|||||||
|
|
||||||
word-wrap@1.2.5: {}
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
wsl-utils@0.3.1:
|
|
||||||
dependencies:
|
|
||||||
is-wsl: 3.1.1
|
|
||||||
powershell-utils: 0.1.0
|
|
||||||
|
|
||||||
y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27):
|
y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27):
|
||||||
dependencies:
|
dependencies:
|
||||||
lib0: 0.2.114
|
lib0: 0.2.114
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import type { ContentNode } from '$lib/types/content-node';
|
|
||||||
import ContentNodeDisplay from '$lib/components/ecamp/ContentNodeDisplay.svelte';
|
|
||||||
|
|
||||||
let { node }: { node: ContentNode & { childNodes: any[] } } = $props();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="border p-5">
|
|
||||||
<h3>{node.contentTypeName}</h3>
|
|
||||||
|
|
||||||
<p>{JSON.stringify(node)}</p>
|
|
||||||
|
|
||||||
{#each node.childNodes as child}
|
|
||||||
<ContentNodeDisplay node={child} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { form } from '$app/server';
|
|
||||||
import { ecamp } from '$lib/server/ecamp';
|
|
||||||
import { error } from '@sveltejs/kit';
|
|
||||||
import * as v from 'valibot';
|
|
||||||
|
|
||||||
export const importCamp = form(
|
|
||||||
v.object({
|
|
||||||
url: v.pipe(v.string(), v.nonEmpty(), v.url())
|
|
||||||
}),
|
|
||||||
async ({ url }) => {
|
|
||||||
// example import link = https://app.ecamp3.ch/camps/a0613ea6c551/Testlager/program/activity/f11670330910/e587f21c5881/Blachevolleyball
|
|
||||||
//
|
|
||||||
//// Extract the path segments into an array
|
|
||||||
const segments = url.split('/');
|
|
||||||
|
|
||||||
if (segments.length < 7) error(400, 'please use an url generated by ecamp');
|
|
||||||
|
|
||||||
// Based on the URL structure:
|
|
||||||
const campId = segments[2];
|
|
||||||
const activityId = segments[6];
|
|
||||||
|
|
||||||
await ecamp.ready;
|
|
||||||
|
|
||||||
await ecamp.acceptAllInvitaions();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
async function ensureMembership(campId: string) {
|
|
||||||
if ((await ecamp.getCampIds()).find((id) => id === campId)) return true;
|
|
||||||
|
|
||||||
ecamp.acceptAllInvitaions();
|
|
||||||
}
|
|
||||||
@@ -12,8 +12,6 @@ export const aktis = pgTable('akti', {
|
|||||||
author: text('user_id')
|
author: text('user_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id),
|
.references(() => users.id),
|
||||||
originalLink: text(),
|
|
||||||
shareLink: text(),
|
|
||||||
version: integer('version').notNull().default(1)
|
version: integer('version').notNull().default(1)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import { type ClientOptions, type Config, createClient, createConfig } from './client';
|
|
||||||
import type { ClientOptions as ClientOptions2 } from './types.gen';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `createClientConfig()` function will be called on client initialization
|
|
||||||
* and the returned object will become the client's initial configuration.
|
|
||||||
*
|
|
||||||
* You may want to initialize your client this way instead of calling
|
|
||||||
* `setConfig()`. This is useful for example if you're using Next.js
|
|
||||||
* to ensure your client always has the correct values.
|
|
||||||
*/
|
|
||||||
export type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (
|
|
||||||
override?: Config<ClientOptions & T>
|
|
||||||
) => Config<Required<ClientOptions> & T>;
|
|
||||||
|
|
||||||
export const client = createClient(createConfig<ClientOptions2>());
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import { createSseClient } from '../core/serverSentEvents.gen';
|
|
||||||
import type { HttpMethod } from '../core/types.gen';
|
|
||||||
import { getValidRequestBody } from '../core/utils.gen';
|
|
||||||
import type { Client, Config, RequestOptions, ResolvedRequestOptions } from './types.gen';
|
|
||||||
import {
|
|
||||||
buildUrl,
|
|
||||||
createConfig,
|
|
||||||
createInterceptors,
|
|
||||||
getParseAs,
|
|
||||||
mergeConfigs,
|
|
||||||
mergeHeaders,
|
|
||||||
setAuthParams
|
|
||||||
} from './utils.gen';
|
|
||||||
|
|
||||||
type ReqInit = Omit<RequestInit, 'body' | 'headers'> & {
|
|
||||||
body?: any;
|
|
||||||
headers: ReturnType<typeof mergeHeaders>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createClient = (config: Config = {}): Client => {
|
|
||||||
let _config = mergeConfigs(createConfig(), config);
|
|
||||||
|
|
||||||
const getConfig = (): Config => ({ ..._config });
|
|
||||||
|
|
||||||
const setConfig = (config: Config): Config => {
|
|
||||||
_config = mergeConfigs(_config, config);
|
|
||||||
return getConfig();
|
|
||||||
};
|
|
||||||
|
|
||||||
const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>();
|
|
||||||
|
|
||||||
const beforeRequest = async (options: RequestOptions) => {
|
|
||||||
const opts = {
|
|
||||||
..._config,
|
|
||||||
...options,
|
|
||||||
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
|
|
||||||
headers: mergeHeaders(_config.headers, options.headers),
|
|
||||||
serializedBody: undefined as string | undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
if (opts.security) {
|
|
||||||
await setAuthParams({
|
|
||||||
...opts,
|
|
||||||
security: opts.security
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.requestValidator) {
|
|
||||||
await opts.requestValidator(opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.body !== undefined && opts.bodySerializer) {
|
|
||||||
opts.serializedBody = opts.bodySerializer(opts.body) as string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove Content-Type header if body is empty to avoid sending invalid requests
|
|
||||||
if (opts.body === undefined || opts.serializedBody === '') {
|
|
||||||
opts.headers.delete('Content-Type');
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = buildUrl(opts);
|
|
||||||
|
|
||||||
return { opts, url };
|
|
||||||
};
|
|
||||||
|
|
||||||
const request: Client['request'] = async (options) => {
|
|
||||||
// @ts-expect-error
|
|
||||||
const { opts, url } = await beforeRequest(options);
|
|
||||||
const requestInit: ReqInit = {
|
|
||||||
redirect: 'follow',
|
|
||||||
...opts,
|
|
||||||
body: getValidRequestBody(opts)
|
|
||||||
};
|
|
||||||
|
|
||||||
let request = new Request(url, requestInit);
|
|
||||||
|
|
||||||
for (const fn of interceptors.request.fns) {
|
|
||||||
if (fn) {
|
|
||||||
request = await fn(request, opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch must be assigned here, otherwise it would throw the error:
|
|
||||||
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
||||||
const _fetch = opts.fetch!;
|
|
||||||
let response: Response;
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = await _fetch(request);
|
|
||||||
} catch (error) {
|
|
||||||
// Handle fetch exceptions (AbortError, network errors, etc.)
|
|
||||||
let finalError = error;
|
|
||||||
|
|
||||||
for (const fn of interceptors.error.fns) {
|
|
||||||
if (fn) {
|
|
||||||
finalError = (await fn(error, undefined as any, request, opts)) as unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finalError = finalError || ({} as unknown);
|
|
||||||
|
|
||||||
if (opts.throwOnError) {
|
|
||||||
throw finalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return error response
|
|
||||||
return opts.responseStyle === 'data'
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
error: finalError,
|
|
||||||
request,
|
|
||||||
response: undefined as any
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const fn of interceptors.response.fns) {
|
|
||||||
if (fn) {
|
|
||||||
response = await fn(response, request, opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = {
|
|
||||||
request,
|
|
||||||
response
|
|
||||||
};
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const parseAs =
|
|
||||||
(opts.parseAs === 'auto'
|
|
||||||
? getParseAs(response.headers.get('Content-Type'))
|
|
||||||
: opts.parseAs) ?? 'json';
|
|
||||||
|
|
||||||
if (response.status === 204 || response.headers.get('Content-Length') === '0') {
|
|
||||||
let emptyData: any;
|
|
||||||
switch (parseAs) {
|
|
||||||
case 'arrayBuffer':
|
|
||||||
case 'blob':
|
|
||||||
case 'text':
|
|
||||||
emptyData = await response[parseAs]();
|
|
||||||
break;
|
|
||||||
case 'formData':
|
|
||||||
emptyData = new FormData();
|
|
||||||
break;
|
|
||||||
case 'stream':
|
|
||||||
emptyData = response.body;
|
|
||||||
break;
|
|
||||||
case 'json':
|
|
||||||
default:
|
|
||||||
emptyData = {};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return opts.responseStyle === 'data'
|
|
||||||
? emptyData
|
|
||||||
: {
|
|
||||||
data: emptyData,
|
|
||||||
...result
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let data: any;
|
|
||||||
switch (parseAs) {
|
|
||||||
case 'arrayBuffer':
|
|
||||||
case 'blob':
|
|
||||||
case 'formData':
|
|
||||||
case 'text':
|
|
||||||
data = await response[parseAs]();
|
|
||||||
break;
|
|
||||||
case 'json': {
|
|
||||||
// Some servers return 200 with no Content-Length and empty body.
|
|
||||||
// response.json() would throw; read as text and parse if non-empty.
|
|
||||||
const text = await response.text();
|
|
||||||
data = text ? JSON.parse(text) : {};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'stream':
|
|
||||||
return opts.responseStyle === 'data'
|
|
||||||
? response.body
|
|
||||||
: {
|
|
||||||
data: response.body,
|
|
||||||
...result
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parseAs === 'json') {
|
|
||||||
if (opts.responseValidator) {
|
|
||||||
await opts.responseValidator(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.responseTransformer) {
|
|
||||||
data = await opts.responseTransformer(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts.responseStyle === 'data'
|
|
||||||
? data
|
|
||||||
: {
|
|
||||||
data,
|
|
||||||
...result
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const textError = await response.text();
|
|
||||||
let jsonError: unknown;
|
|
||||||
|
|
||||||
try {
|
|
||||||
jsonError = JSON.parse(textError);
|
|
||||||
} catch {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
const error = jsonError ?? textError;
|
|
||||||
let finalError = error;
|
|
||||||
|
|
||||||
for (const fn of interceptors.error.fns) {
|
|
||||||
if (fn) {
|
|
||||||
finalError = (await fn(error, response, request, opts)) as string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finalError = finalError || ({} as string);
|
|
||||||
|
|
||||||
if (opts.throwOnError) {
|
|
||||||
throw finalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: we probably want to return error and improve types
|
|
||||||
return opts.responseStyle === 'data'
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
error: finalError,
|
|
||||||
...result
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) =>
|
|
||||||
request({ ...options, method });
|
|
||||||
|
|
||||||
const makeSseFn = (method: Uppercase<HttpMethod>) => async (options: RequestOptions) => {
|
|
||||||
const { opts, url } = await beforeRequest(options);
|
|
||||||
return createSseClient({
|
|
||||||
...opts,
|
|
||||||
body: opts.body as BodyInit | null | undefined,
|
|
||||||
headers: opts.headers as unknown as Record<string, string>,
|
|
||||||
method,
|
|
||||||
onRequest: async (url, init) => {
|
|
||||||
let request = new Request(url, init);
|
|
||||||
for (const fn of interceptors.request.fns) {
|
|
||||||
if (fn) {
|
|
||||||
request = await fn(request, opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return request;
|
|
||||||
},
|
|
||||||
serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined,
|
|
||||||
url
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const _buildUrl: Client['buildUrl'] = (options) => buildUrl({ ..._config, ...options });
|
|
||||||
|
|
||||||
return {
|
|
||||||
buildUrl: _buildUrl,
|
|
||||||
connect: makeMethodFn('CONNECT'),
|
|
||||||
delete: makeMethodFn('DELETE'),
|
|
||||||
get: makeMethodFn('GET'),
|
|
||||||
getConfig,
|
|
||||||
head: makeMethodFn('HEAD'),
|
|
||||||
interceptors,
|
|
||||||
options: makeMethodFn('OPTIONS'),
|
|
||||||
patch: makeMethodFn('PATCH'),
|
|
||||||
post: makeMethodFn('POST'),
|
|
||||||
put: makeMethodFn('PUT'),
|
|
||||||
request,
|
|
||||||
setConfig,
|
|
||||||
sse: {
|
|
||||||
connect: makeSseFn('CONNECT'),
|
|
||||||
delete: makeSseFn('DELETE'),
|
|
||||||
get: makeSseFn('GET'),
|
|
||||||
head: makeSseFn('HEAD'),
|
|
||||||
options: makeSseFn('OPTIONS'),
|
|
||||||
patch: makeSseFn('PATCH'),
|
|
||||||
post: makeSseFn('POST'),
|
|
||||||
put: makeSseFn('PUT'),
|
|
||||||
trace: makeSseFn('TRACE')
|
|
||||||
},
|
|
||||||
trace: makeMethodFn('TRACE')
|
|
||||||
} as Client;
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
export type { Auth } from '../core/auth.gen';
|
|
||||||
export type { QuerySerializerOptions } from '../core/bodySerializer.gen';
|
|
||||||
export {
|
|
||||||
formDataBodySerializer,
|
|
||||||
jsonBodySerializer,
|
|
||||||
urlSearchParamsBodySerializer
|
|
||||||
} from '../core/bodySerializer.gen';
|
|
||||||
export { buildClientParams } from '../core/params.gen';
|
|
||||||
export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen';
|
|
||||||
export { createClient } from './client.gen';
|
|
||||||
export type {
|
|
||||||
Client,
|
|
||||||
ClientOptions,
|
|
||||||
Config,
|
|
||||||
CreateClientConfig,
|
|
||||||
Options,
|
|
||||||
RequestOptions,
|
|
||||||
RequestResult,
|
|
||||||
ResolvedRequestOptions,
|
|
||||||
ResponseStyle,
|
|
||||||
TDataShape
|
|
||||||
} from './types.gen';
|
|
||||||
export { createConfig, mergeHeaders } from './utils.gen';
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import type { Auth } from '../core/auth.gen';
|
|
||||||
import type { ServerSentEventsOptions, ServerSentEventsResult } from '../core/serverSentEvents.gen';
|
|
||||||
import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen';
|
|
||||||
import type { Middleware } from './utils.gen';
|
|
||||||
|
|
||||||
export type ResponseStyle = 'data' | 'fields';
|
|
||||||
|
|
||||||
export interface Config<T extends ClientOptions = ClientOptions>
|
|
||||||
extends Omit<RequestInit, 'body' | 'headers' | 'method'>,
|
|
||||||
CoreConfig {
|
|
||||||
/**
|
|
||||||
* Base URL for all requests made by this client.
|
|
||||||
*/
|
|
||||||
baseUrl?: T['baseUrl'];
|
|
||||||
/**
|
|
||||||
* Fetch API implementation. You can use this option to provide a custom
|
|
||||||
* fetch instance.
|
|
||||||
*
|
|
||||||
* @default globalThis.fetch
|
|
||||||
*/
|
|
||||||
fetch?: typeof fetch;
|
|
||||||
/**
|
|
||||||
* Please don't use the Fetch client for Next.js applications. The `next`
|
|
||||||
* options won't have any effect.
|
|
||||||
*
|
|
||||||
* Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead.
|
|
||||||
*/
|
|
||||||
next?: never;
|
|
||||||
/**
|
|
||||||
* Return the response data parsed in a specified format. By default, `auto`
|
|
||||||
* will infer the appropriate method from the `Content-Type` response header.
|
|
||||||
* You can override this behavior with any of the {@link Body} methods.
|
|
||||||
* Select `stream` if you don't want to parse response data at all.
|
|
||||||
*
|
|
||||||
* @default 'auto'
|
|
||||||
*/
|
|
||||||
parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text';
|
|
||||||
/**
|
|
||||||
* Should we return only data or multiple fields (data, error, response, etc.)?
|
|
||||||
*
|
|
||||||
* @default 'fields'
|
|
||||||
*/
|
|
||||||
responseStyle?: ResponseStyle;
|
|
||||||
/**
|
|
||||||
* Throw an error instead of returning it in the response?
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
throwOnError?: T['throwOnError'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RequestOptions<
|
|
||||||
TData = unknown,
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields',
|
|
||||||
ThrowOnError extends boolean = boolean,
|
|
||||||
Url extends string = string
|
|
||||||
> extends Config<{
|
|
||||||
responseStyle: TResponseStyle;
|
|
||||||
throwOnError: ThrowOnError;
|
|
||||||
}>,
|
|
||||||
Pick<
|
|
||||||
ServerSentEventsOptions<TData>,
|
|
||||||
| 'onRequest'
|
|
||||||
| 'onSseError'
|
|
||||||
| 'onSseEvent'
|
|
||||||
| 'sseDefaultRetryDelay'
|
|
||||||
| 'sseMaxRetryAttempts'
|
|
||||||
| 'sseMaxRetryDelay'
|
|
||||||
> {
|
|
||||||
/**
|
|
||||||
* Any body that you want to add to your request.
|
|
||||||
*
|
|
||||||
* {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
|
|
||||||
*/
|
|
||||||
body?: unknown;
|
|
||||||
path?: Record<string, unknown>;
|
|
||||||
query?: Record<string, unknown>;
|
|
||||||
/**
|
|
||||||
* Security mechanism(s) to use for the request.
|
|
||||||
*/
|
|
||||||
security?: ReadonlyArray<Auth>;
|
|
||||||
url: Url;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResolvedRequestOptions<
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields',
|
|
||||||
ThrowOnError extends boolean = boolean,
|
|
||||||
Url extends string = string
|
|
||||||
> extends RequestOptions<unknown, TResponseStyle, ThrowOnError, Url> {
|
|
||||||
serializedBody?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RequestResult<
|
|
||||||
TData = unknown,
|
|
||||||
TError = unknown,
|
|
||||||
ThrowOnError extends boolean = boolean,
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields'
|
|
||||||
> = ThrowOnError extends true
|
|
||||||
? Promise<
|
|
||||||
TResponseStyle extends 'data'
|
|
||||||
? TData extends Record<string, unknown>
|
|
||||||
? TData[keyof TData]
|
|
||||||
: TData
|
|
||||||
: {
|
|
||||||
data: TData extends Record<string, unknown> ? TData[keyof TData] : TData;
|
|
||||||
request: Request;
|
|
||||||
response: Response;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
: Promise<
|
|
||||||
TResponseStyle extends 'data'
|
|
||||||
? (TData extends Record<string, unknown> ? TData[keyof TData] : TData) | undefined
|
|
||||||
: (
|
|
||||||
| {
|
|
||||||
data: TData extends Record<string, unknown> ? TData[keyof TData] : TData;
|
|
||||||
error: undefined;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
data: undefined;
|
|
||||||
error: TError extends Record<string, unknown> ? TError[keyof TError] : TError;
|
|
||||||
}
|
|
||||||
) & {
|
|
||||||
request: Request;
|
|
||||||
response: Response;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
export interface ClientOptions {
|
|
||||||
baseUrl?: string;
|
|
||||||
responseStyle?: ResponseStyle;
|
|
||||||
throwOnError?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
type MethodFn = <
|
|
||||||
TData = unknown,
|
|
||||||
TError = unknown,
|
|
||||||
ThrowOnError extends boolean = false,
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields'
|
|
||||||
>(
|
|
||||||
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'>
|
|
||||||
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
|
|
||||||
|
|
||||||
type SseFn = <
|
|
||||||
TData = unknown,
|
|
||||||
TError = unknown,
|
|
||||||
ThrowOnError extends boolean = false,
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields'
|
|
||||||
>(
|
|
||||||
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'>
|
|
||||||
) => Promise<ServerSentEventsResult<TData, TError>>;
|
|
||||||
|
|
||||||
type RequestFn = <
|
|
||||||
TData = unknown,
|
|
||||||
TError = unknown,
|
|
||||||
ThrowOnError extends boolean = false,
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields'
|
|
||||||
>(
|
|
||||||
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'> &
|
|
||||||
Pick<Required<RequestOptions<TData, TResponseStyle, ThrowOnError>>, 'method'>
|
|
||||||
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
|
|
||||||
|
|
||||||
type BuildUrlFn = <
|
|
||||||
TData extends {
|
|
||||||
body?: unknown;
|
|
||||||
path?: Record<string, unknown>;
|
|
||||||
query?: Record<string, unknown>;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
>(
|
|
||||||
options: TData & Options<TData>
|
|
||||||
) => string;
|
|
||||||
|
|
||||||
export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn, SseFn> & {
|
|
||||||
interceptors: Middleware<Request, Response, unknown, ResolvedRequestOptions>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `createClientConfig()` function will be called on client initialization
|
|
||||||
* and the returned object will become the client's initial configuration.
|
|
||||||
*
|
|
||||||
* You may want to initialize your client this way instead of calling
|
|
||||||
* `setConfig()`. This is useful for example if you're using Next.js
|
|
||||||
* to ensure your client always has the correct values.
|
|
||||||
*/
|
|
||||||
export type CreateClientConfig<T extends ClientOptions = ClientOptions> = (
|
|
||||||
override?: Config<ClientOptions & T>
|
|
||||||
) => Config<Required<ClientOptions> & T>;
|
|
||||||
|
|
||||||
export interface TDataShape {
|
|
||||||
body?: unknown;
|
|
||||||
headers?: unknown;
|
|
||||||
path?: unknown;
|
|
||||||
query?: unknown;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
|
|
||||||
|
|
||||||
export type Options<
|
|
||||||
TData extends TDataShape = TDataShape,
|
|
||||||
ThrowOnError extends boolean = boolean,
|
|
||||||
TResponse = unknown,
|
|
||||||
TResponseStyle extends ResponseStyle = 'fields'
|
|
||||||
> = OmitKeys<
|
|
||||||
RequestOptions<TResponse, TResponseStyle, ThrowOnError>,
|
|
||||||
'body' | 'path' | 'query' | 'url'
|
|
||||||
> &
|
|
||||||
([TData] extends [never] ? unknown : Omit<TData, 'url'>);
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import { getAuthToken } from '../core/auth.gen';
|
|
||||||
import type { QuerySerializerOptions } from '../core/bodySerializer.gen';
|
|
||||||
import { jsonBodySerializer } from '../core/bodySerializer.gen';
|
|
||||||
import {
|
|
||||||
serializeArrayParam,
|
|
||||||
serializeObjectParam,
|
|
||||||
serializePrimitiveParam
|
|
||||||
} from '../core/pathSerializer.gen';
|
|
||||||
import { getUrl } from '../core/utils.gen';
|
|
||||||
import type { Client, ClientOptions, Config, RequestOptions } from './types.gen';
|
|
||||||
|
|
||||||
export const createQuerySerializer = <T = unknown>({
|
|
||||||
parameters = {},
|
|
||||||
...args
|
|
||||||
}: QuerySerializerOptions = {}) => {
|
|
||||||
const querySerializer = (queryParams: T) => {
|
|
||||||
const search: string[] = [];
|
|
||||||
if (queryParams && typeof queryParams === 'object') {
|
|
||||||
for (const name in queryParams) {
|
|
||||||
const value = queryParams[name];
|
|
||||||
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = parameters[name] || args;
|
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
const serializedArray = serializeArrayParam({
|
|
||||||
allowReserved: options.allowReserved,
|
|
||||||
explode: true,
|
|
||||||
name,
|
|
||||||
style: 'form',
|
|
||||||
value,
|
|
||||||
...options.array
|
|
||||||
});
|
|
||||||
if (serializedArray) search.push(serializedArray);
|
|
||||||
} else if (typeof value === 'object') {
|
|
||||||
const serializedObject = serializeObjectParam({
|
|
||||||
allowReserved: options.allowReserved,
|
|
||||||
explode: true,
|
|
||||||
name,
|
|
||||||
style: 'deepObject',
|
|
||||||
value: value as Record<string, unknown>,
|
|
||||||
...options.object
|
|
||||||
});
|
|
||||||
if (serializedObject) search.push(serializedObject);
|
|
||||||
} else {
|
|
||||||
const serializedPrimitive = serializePrimitiveParam({
|
|
||||||
allowReserved: options.allowReserved,
|
|
||||||
name,
|
|
||||||
value: value as string
|
|
||||||
});
|
|
||||||
if (serializedPrimitive) search.push(serializedPrimitive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return search.join('&');
|
|
||||||
};
|
|
||||||
return querySerializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Infers parseAs value from provided Content-Type header.
|
|
||||||
*/
|
|
||||||
export const getParseAs = (contentType: string | null): Exclude<Config['parseAs'], 'auto'> => {
|
|
||||||
if (!contentType) {
|
|
||||||
// If no Content-Type header is provided, the best we can do is return the raw response body,
|
|
||||||
// which is effectively the same as the 'stream' option.
|
|
||||||
return 'stream';
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleanContent = contentType.split(';')[0]?.trim();
|
|
||||||
|
|
||||||
if (!cleanContent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) {
|
|
||||||
return 'json';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cleanContent === 'multipart/form-data') {
|
|
||||||
return 'formData';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type))
|
|
||||||
) {
|
|
||||||
return 'blob';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cleanContent.startsWith('text/')) {
|
|
||||||
return 'text';
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkForExistence = (
|
|
||||||
options: Pick<RequestOptions, 'auth' | 'query'> & {
|
|
||||||
headers: Headers;
|
|
||||||
},
|
|
||||||
name?: string
|
|
||||||
): boolean => {
|
|
||||||
if (!name) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
options.headers.has(name) ||
|
|
||||||
options.query?.[name] ||
|
|
||||||
options.headers.get('Cookie')?.includes(`${name}=`)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setAuthParams = async ({
|
|
||||||
security,
|
|
||||||
...options
|
|
||||||
}: Pick<Required<RequestOptions>, 'security'> &
|
|
||||||
Pick<RequestOptions, 'auth' | 'query'> & {
|
|
||||||
headers: Headers;
|
|
||||||
}) => {
|
|
||||||
for (const auth of security) {
|
|
||||||
if (checkForExistence(options, auth.name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = await getAuthToken(auth, options.auth);
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = auth.name ?? 'Authorization';
|
|
||||||
|
|
||||||
switch (auth.in) {
|
|
||||||
case 'query':
|
|
||||||
if (!options.query) {
|
|
||||||
options.query = {};
|
|
||||||
}
|
|
||||||
options.query[name] = token;
|
|
||||||
break;
|
|
||||||
case 'cookie':
|
|
||||||
options.headers.append('Cookie', `${name}=${token}`);
|
|
||||||
break;
|
|
||||||
case 'header':
|
|
||||||
default:
|
|
||||||
options.headers.set(name, token);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const buildUrl: Client['buildUrl'] = (options) =>
|
|
||||||
getUrl({
|
|
||||||
baseUrl: options.baseUrl as string,
|
|
||||||
path: options.path,
|
|
||||||
query: options.query,
|
|
||||||
querySerializer:
|
|
||||||
typeof options.querySerializer === 'function'
|
|
||||||
? options.querySerializer
|
|
||||||
: createQuerySerializer(options.querySerializer),
|
|
||||||
url: options.url
|
|
||||||
});
|
|
||||||
|
|
||||||
export const mergeConfigs = (a: Config, b: Config): Config => {
|
|
||||||
const config = { ...a, ...b };
|
|
||||||
if (config.baseUrl?.endsWith('/')) {
|
|
||||||
config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
|
|
||||||
}
|
|
||||||
config.headers = mergeHeaders(a.headers, b.headers);
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
|
|
||||||
const headersEntries = (headers: Headers): Array<[string, string]> => {
|
|
||||||
const entries: Array<[string, string]> = [];
|
|
||||||
headers.forEach((value, key) => {
|
|
||||||
entries.push([key, value]);
|
|
||||||
});
|
|
||||||
return entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mergeHeaders = (
|
|
||||||
...headers: Array<Required<Config>['headers'] | undefined>
|
|
||||||
): Headers => {
|
|
||||||
const mergedHeaders = new Headers();
|
|
||||||
for (const header of headers) {
|
|
||||||
if (!header) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
|
|
||||||
|
|
||||||
for (const [key, value] of iterator) {
|
|
||||||
if (value === null) {
|
|
||||||
mergedHeaders.delete(key);
|
|
||||||
} else if (Array.isArray(value)) {
|
|
||||||
for (const v of value) {
|
|
||||||
mergedHeaders.append(key, v as string);
|
|
||||||
}
|
|
||||||
} else if (value !== undefined) {
|
|
||||||
// assume object headers are meant to be JSON stringified, i.e., their
|
|
||||||
// content value in OpenAPI specification is 'application/json'
|
|
||||||
mergedHeaders.set(
|
|
||||||
key,
|
|
||||||
typeof value === 'object' ? JSON.stringify(value) : (value as string)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mergedHeaders;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ErrInterceptor<Err, Res, Req, Options> = (
|
|
||||||
error: Err,
|
|
||||||
response: Res,
|
|
||||||
request: Req,
|
|
||||||
options: Options
|
|
||||||
) => Err | Promise<Err>;
|
|
||||||
|
|
||||||
type ReqInterceptor<Req, Options> = (request: Req, options: Options) => Req | Promise<Req>;
|
|
||||||
|
|
||||||
type ResInterceptor<Res, Req, Options> = (
|
|
||||||
response: Res,
|
|
||||||
request: Req,
|
|
||||||
options: Options
|
|
||||||
) => Res | Promise<Res>;
|
|
||||||
|
|
||||||
class Interceptors<Interceptor> {
|
|
||||||
fns: Array<Interceptor | null> = [];
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this.fns = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
eject(id: number | Interceptor): void {
|
|
||||||
const index = this.getInterceptorIndex(id);
|
|
||||||
if (this.fns[index]) {
|
|
||||||
this.fns[index] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exists(id: number | Interceptor): boolean {
|
|
||||||
const index = this.getInterceptorIndex(id);
|
|
||||||
return Boolean(this.fns[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getInterceptorIndex(id: number | Interceptor): number {
|
|
||||||
if (typeof id === 'number') {
|
|
||||||
return this.fns[id] ? id : -1;
|
|
||||||
}
|
|
||||||
return this.fns.indexOf(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false {
|
|
||||||
const index = this.getInterceptorIndex(id);
|
|
||||||
if (this.fns[index]) {
|
|
||||||
this.fns[index] = fn;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
use(fn: Interceptor): number {
|
|
||||||
this.fns.push(fn);
|
|
||||||
return this.fns.length - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Middleware<Req, Res, Err, Options> {
|
|
||||||
error: Interceptors<ErrInterceptor<Err, Res, Req, Options>>;
|
|
||||||
request: Interceptors<ReqInterceptor<Req, Options>>;
|
|
||||||
response: Interceptors<ResInterceptor<Res, Req, Options>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createInterceptors = <Req, Res, Err, Options>(): Middleware<
|
|
||||||
Req,
|
|
||||||
Res,
|
|
||||||
Err,
|
|
||||||
Options
|
|
||||||
> => ({
|
|
||||||
error: new Interceptors<ErrInterceptor<Err, Res, Req, Options>>(),
|
|
||||||
request: new Interceptors<ReqInterceptor<Req, Options>>(),
|
|
||||||
response: new Interceptors<ResInterceptor<Res, Req, Options>>()
|
|
||||||
});
|
|
||||||
|
|
||||||
const defaultQuerySerializer = createQuerySerializer({
|
|
||||||
allowReserved: false,
|
|
||||||
array: {
|
|
||||||
explode: true,
|
|
||||||
style: 'form'
|
|
||||||
},
|
|
||||||
object: {
|
|
||||||
explode: true,
|
|
||||||
style: 'deepObject'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const defaultHeaders = {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createConfig = <T extends ClientOptions = ClientOptions>(
|
|
||||||
override: Config<Omit<ClientOptions, keyof T> & T> = {}
|
|
||||||
): Config<Omit<ClientOptions, keyof T> & T> => ({
|
|
||||||
...jsonBodySerializer,
|
|
||||||
headers: defaultHeaders,
|
|
||||||
parseAs: 'auto',
|
|
||||||
querySerializer: defaultQuerySerializer,
|
|
||||||
...override
|
|
||||||
});
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
export type AuthToken = string | undefined;
|
|
||||||
|
|
||||||
export interface Auth {
|
|
||||||
/**
|
|
||||||
* Which part of the request do we use to send the auth?
|
|
||||||
*
|
|
||||||
* @default 'header'
|
|
||||||
*/
|
|
||||||
in?: 'header' | 'query' | 'cookie';
|
|
||||||
/**
|
|
||||||
* Header or query parameter name.
|
|
||||||
*
|
|
||||||
* @default 'Authorization'
|
|
||||||
*/
|
|
||||||
name?: string;
|
|
||||||
scheme?: 'basic' | 'bearer';
|
|
||||||
type: 'apiKey' | 'http';
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAuthToken = async (
|
|
||||||
auth: Auth,
|
|
||||||
callback: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken
|
|
||||||
): Promise<string | undefined> => {
|
|
||||||
const token = typeof callback === 'function' ? await callback(auth) : callback;
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auth.scheme === 'bearer') {
|
|
||||||
return `Bearer ${token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auth.scheme === 'basic') {
|
|
||||||
return `Basic ${btoa(token)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
};
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen';
|
|
||||||
|
|
||||||
export type QuerySerializer = (query: Record<string, unknown>) => string;
|
|
||||||
|
|
||||||
export type BodySerializer = (body: unknown) => unknown;
|
|
||||||
|
|
||||||
type QuerySerializerOptionsObject = {
|
|
||||||
allowReserved?: boolean;
|
|
||||||
array?: Partial<SerializerOptions<ArrayStyle>>;
|
|
||||||
object?: Partial<SerializerOptions<ObjectStyle>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type QuerySerializerOptions = QuerySerializerOptionsObject & {
|
|
||||||
/**
|
|
||||||
* Per-parameter serialization overrides. When provided, these settings
|
|
||||||
* override the global array/object settings for specific parameter names.
|
|
||||||
*/
|
|
||||||
parameters?: Record<string, QuerySerializerOptionsObject>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => {
|
|
||||||
if (typeof value === 'string' || value instanceof Blob) {
|
|
||||||
data.append(key, value);
|
|
||||||
} else if (value instanceof Date) {
|
|
||||||
data.append(key, value.toISOString());
|
|
||||||
} else {
|
|
||||||
data.append(key, JSON.stringify(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
data.append(key, value);
|
|
||||||
} else {
|
|
||||||
data.append(key, JSON.stringify(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const formDataBodySerializer = {
|
|
||||||
bodySerializer: (body: unknown): FormData => {
|
|
||||||
const data = new FormData();
|
|
||||||
|
|
||||||
Object.entries(body as Record<string, unknown>).forEach(([key, value]) => {
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
value.forEach((v) => serializeFormDataPair(data, key, v));
|
|
||||||
} else {
|
|
||||||
serializeFormDataPair(data, key, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const jsonBodySerializer = {
|
|
||||||
bodySerializer: (body: unknown): string =>
|
|
||||||
JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value))
|
|
||||||
};
|
|
||||||
|
|
||||||
export const urlSearchParamsBodySerializer = {
|
|
||||||
bodySerializer: (body: unknown): string => {
|
|
||||||
const data = new URLSearchParams();
|
|
||||||
|
|
||||||
Object.entries(body as Record<string, unknown>).forEach(([key, value]) => {
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
value.forEach((v) => serializeUrlSearchParamsPair(data, key, v));
|
|
||||||
} else {
|
|
||||||
serializeUrlSearchParamsPair(data, key, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return data.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
type Slot = 'body' | 'headers' | 'path' | 'query';
|
|
||||||
|
|
||||||
export type Field =
|
|
||||||
| {
|
|
||||||
in: Exclude<Slot, 'body'>;
|
|
||||||
/**
|
|
||||||
* Field name. This is the name we want the user to see and use.
|
|
||||||
*/
|
|
||||||
key: string;
|
|
||||||
/**
|
|
||||||
* Field mapped name. This is the name we want to use in the request.
|
|
||||||
* If omitted, we use the same value as `key`.
|
|
||||||
*/
|
|
||||||
map?: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
in: Extract<Slot, 'body'>;
|
|
||||||
/**
|
|
||||||
* Key isn't required for bodies.
|
|
||||||
*/
|
|
||||||
key?: string;
|
|
||||||
map?: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
/**
|
|
||||||
* Field name. This is the name we want the user to see and use.
|
|
||||||
*/
|
|
||||||
key: string;
|
|
||||||
/**
|
|
||||||
* Field mapped name. This is the name we want to use in the request.
|
|
||||||
* If `in` is omitted, `map` aliases `key` to the transport layer.
|
|
||||||
*/
|
|
||||||
map: Slot;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Fields {
|
|
||||||
allowExtra?: Partial<Record<Slot, boolean>>;
|
|
||||||
args?: ReadonlyArray<Field>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type FieldsConfig = ReadonlyArray<Field | Fields>;
|
|
||||||
|
|
||||||
const extraPrefixesMap: Record<string, Slot> = {
|
|
||||||
$body_: 'body',
|
|
||||||
$headers_: 'headers',
|
|
||||||
$path_: 'path',
|
|
||||||
$query_: 'query'
|
|
||||||
};
|
|
||||||
const extraPrefixes = Object.entries(extraPrefixesMap);
|
|
||||||
|
|
||||||
type KeyMap = Map<
|
|
||||||
string,
|
|
||||||
| {
|
|
||||||
in: Slot;
|
|
||||||
map?: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
in?: never;
|
|
||||||
map: Slot;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
|
|
||||||
if (!map) {
|
|
||||||
map = new Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const config of fields) {
|
|
||||||
if ('in' in config) {
|
|
||||||
if (config.key) {
|
|
||||||
map.set(config.key, {
|
|
||||||
in: config.in,
|
|
||||||
map: config.map
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if ('key' in config) {
|
|
||||||
map.set(config.key, {
|
|
||||||
map: config.map
|
|
||||||
});
|
|
||||||
} else if (config.args) {
|
|
||||||
buildKeyMap(config.args, map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Params {
|
|
||||||
body: unknown;
|
|
||||||
headers: Record<string, unknown>;
|
|
||||||
path: Record<string, unknown>;
|
|
||||||
query: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stripEmptySlots = (params: Params) => {
|
|
||||||
for (const [slot, value] of Object.entries(params)) {
|
|
||||||
if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) {
|
|
||||||
delete params[slot as Slot];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsConfig) => {
|
|
||||||
const params: Params = {
|
|
||||||
body: {},
|
|
||||||
headers: {},
|
|
||||||
path: {},
|
|
||||||
query: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const map = buildKeyMap(fields);
|
|
||||||
|
|
||||||
let config: FieldsConfig[number] | undefined;
|
|
||||||
|
|
||||||
for (const [index, arg] of args.entries()) {
|
|
||||||
if (fields[index]) {
|
|
||||||
config = fields[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('in' in config) {
|
|
||||||
if (config.key) {
|
|
||||||
const field = map.get(config.key)!;
|
|
||||||
const name = field.map || config.key;
|
|
||||||
if (field.in) {
|
|
||||||
(params[field.in] as Record<string, unknown>)[name] = arg;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
params.body = arg;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const [key, value] of Object.entries(arg ?? {})) {
|
|
||||||
const field = map.get(key);
|
|
||||||
|
|
||||||
if (field) {
|
|
||||||
if (field.in) {
|
|
||||||
const name = field.map || key;
|
|
||||||
(params[field.in] as Record<string, unknown>)[name] = value;
|
|
||||||
} else {
|
|
||||||
params[field.map] = value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix));
|
|
||||||
|
|
||||||
if (extra) {
|
|
||||||
const [prefix, slot] = extra;
|
|
||||||
(params[slot] as Record<string, unknown>)[key.slice(prefix.length)] = value;
|
|
||||||
} else if ('allowExtra' in config && config.allowExtra) {
|
|
||||||
for (const [slot, allowed] of Object.entries(config.allowExtra)) {
|
|
||||||
if (allowed) {
|
|
||||||
(params[slot as Slot] as Record<string, unknown>)[key] = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stripEmptySlots(params);
|
|
||||||
|
|
||||||
return params;
|
|
||||||
};
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
interface SerializeOptions<T> extends SerializePrimitiveOptions, SerializerOptions<T> {}
|
|
||||||
|
|
||||||
interface SerializePrimitiveOptions {
|
|
||||||
allowReserved?: boolean;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SerializerOptions<T> {
|
|
||||||
/**
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
explode: boolean;
|
|
||||||
style: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
|
|
||||||
export type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
|
|
||||||
type MatrixStyle = 'label' | 'matrix' | 'simple';
|
|
||||||
export type ObjectStyle = 'form' | 'deepObject';
|
|
||||||
type ObjectSeparatorStyle = ObjectStyle | MatrixStyle;
|
|
||||||
|
|
||||||
interface SerializePrimitiveParam extends SerializePrimitiveOptions {
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
|
|
||||||
switch (style) {
|
|
||||||
case 'label':
|
|
||||||
return '.';
|
|
||||||
case 'matrix':
|
|
||||||
return ';';
|
|
||||||
case 'simple':
|
|
||||||
return ',';
|
|
||||||
default:
|
|
||||||
return '&';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
|
|
||||||
switch (style) {
|
|
||||||
case 'form':
|
|
||||||
return ',';
|
|
||||||
case 'pipeDelimited':
|
|
||||||
return '|';
|
|
||||||
case 'spaceDelimited':
|
|
||||||
return '%20';
|
|
||||||
default:
|
|
||||||
return ',';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
|
|
||||||
switch (style) {
|
|
||||||
case 'label':
|
|
||||||
return '.';
|
|
||||||
case 'matrix':
|
|
||||||
return ';';
|
|
||||||
case 'simple':
|
|
||||||
return ',';
|
|
||||||
default:
|
|
||||||
return '&';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const serializeArrayParam = ({
|
|
||||||
allowReserved,
|
|
||||||
explode,
|
|
||||||
name,
|
|
||||||
style,
|
|
||||||
value
|
|
||||||
}: SerializeOptions<ArraySeparatorStyle> & {
|
|
||||||
value: unknown[];
|
|
||||||
}) => {
|
|
||||||
if (!explode) {
|
|
||||||
const joinedValues = (
|
|
||||||
allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
|
|
||||||
).join(separatorArrayNoExplode(style));
|
|
||||||
switch (style) {
|
|
||||||
case 'label':
|
|
||||||
return `.${joinedValues}`;
|
|
||||||
case 'matrix':
|
|
||||||
return `;${name}=${joinedValues}`;
|
|
||||||
case 'simple':
|
|
||||||
return joinedValues;
|
|
||||||
default:
|
|
||||||
return `${name}=${joinedValues}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const separator = separatorArrayExplode(style);
|
|
||||||
const joinedValues = value
|
|
||||||
.map((v) => {
|
|
||||||
if (style === 'label' || style === 'simple') {
|
|
||||||
return allowReserved ? v : encodeURIComponent(v as string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return serializePrimitiveParam({
|
|
||||||
allowReserved,
|
|
||||||
name,
|
|
||||||
value: v as string
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.join(separator);
|
|
||||||
return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const serializePrimitiveParam = ({
|
|
||||||
allowReserved,
|
|
||||||
name,
|
|
||||||
value
|
|
||||||
}: SerializePrimitiveParam) => {
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'object') {
|
|
||||||
throw new Error(
|
|
||||||
'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const serializeObjectParam = ({
|
|
||||||
allowReserved,
|
|
||||||
explode,
|
|
||||||
name,
|
|
||||||
style,
|
|
||||||
value,
|
|
||||||
valueOnly
|
|
||||||
}: SerializeOptions<ObjectSeparatorStyle> & {
|
|
||||||
value: Record<string, unknown> | Date;
|
|
||||||
valueOnly?: boolean;
|
|
||||||
}) => {
|
|
||||||
if (value instanceof Date) {
|
|
||||||
return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style !== 'deepObject' && !explode) {
|
|
||||||
let values: string[] = [];
|
|
||||||
Object.entries(value).forEach(([key, v]) => {
|
|
||||||
values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)];
|
|
||||||
});
|
|
||||||
const joinedValues = values.join(',');
|
|
||||||
switch (style) {
|
|
||||||
case 'form':
|
|
||||||
return `${name}=${joinedValues}`;
|
|
||||||
case 'label':
|
|
||||||
return `.${joinedValues}`;
|
|
||||||
case 'matrix':
|
|
||||||
return `;${name}=${joinedValues}`;
|
|
||||||
default:
|
|
||||||
return joinedValues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const separator = separatorObjectExplode(style);
|
|
||||||
const joinedValues = Object.entries(value)
|
|
||||||
.map(([key, v]) =>
|
|
||||||
serializePrimitiveParam({
|
|
||||||
allowReserved,
|
|
||||||
name: style === 'deepObject' ? `${name}[${key}]` : key,
|
|
||||||
value: v as string
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.join(separator);
|
|
||||||
return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues;
|
|
||||||
};
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON-friendly union that mirrors what Pinia Colada can hash.
|
|
||||||
*/
|
|
||||||
export type JsonValue =
|
|
||||||
| null
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| JsonValue[]
|
|
||||||
| { [key: string]: JsonValue };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes.
|
|
||||||
*/
|
|
||||||
export const queryKeyJsonReplacer = (_key: string, value: unknown) => {
|
|
||||||
if (value === undefined || typeof value === 'function' || typeof value === 'symbol') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (typeof value === 'bigint') {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
if (value instanceof Date) {
|
|
||||||
return value.toISOString();
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Safely stringifies a value and parses it back into a JsonValue.
|
|
||||||
*/
|
|
||||||
export const stringifyToJsonValue = (input: unknown): JsonValue | undefined => {
|
|
||||||
try {
|
|
||||||
const json = JSON.stringify(input, queryKeyJsonReplacer);
|
|
||||||
if (json === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return JSON.parse(json) as JsonValue;
|
|
||||||
} catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detects plain objects (including objects with a null prototype).
|
|
||||||
*/
|
|
||||||
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
|
||||||
if (value === null || typeof value !== 'object') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const prototype = Object.getPrototypeOf(value as object);
|
|
||||||
return prototype === Object.prototype || prototype === null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns URLSearchParams into a sorted JSON object for deterministic keys.
|
|
||||||
*/
|
|
||||||
const serializeSearchParams = (params: URLSearchParams): JsonValue => {
|
|
||||||
const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
||||||
const result: Record<string, JsonValue> = {};
|
|
||||||
|
|
||||||
for (const [key, value] of entries) {
|
|
||||||
const existing = result[key];
|
|
||||||
if (existing === undefined) {
|
|
||||||
result[key] = value;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(existing)) {
|
|
||||||
(existing as string[]).push(value);
|
|
||||||
} else {
|
|
||||||
result[key] = [existing, value];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalizes any accepted value into a JSON-friendly shape for query keys.
|
|
||||||
*/
|
|
||||||
export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => {
|
|
||||||
if (value === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === undefined || typeof value === 'function' || typeof value === 'symbol') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'bigint') {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof Date) {
|
|
||||||
return value.toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return stringifyToJsonValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) {
|
|
||||||
return serializeSearchParams(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPlainObject(value)) {
|
|
||||||
return stringifyToJsonValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import type { Config } from './types.gen';
|
|
||||||
|
|
||||||
export type ServerSentEventsOptions<TData = unknown> = Omit<RequestInit, 'method'> &
|
|
||||||
Pick<Config, 'method' | 'responseTransformer' | 'responseValidator'> & {
|
|
||||||
/**
|
|
||||||
* Fetch API implementation. You can use this option to provide a custom
|
|
||||||
* fetch instance.
|
|
||||||
*
|
|
||||||
* @default globalThis.fetch
|
|
||||||
*/
|
|
||||||
fetch?: typeof fetch;
|
|
||||||
/**
|
|
||||||
* Implementing clients can call request interceptors inside this hook.
|
|
||||||
*/
|
|
||||||
onRequest?: (url: string, init: RequestInit) => Promise<Request>;
|
|
||||||
/**
|
|
||||||
* Callback invoked when a network or parsing error occurs during streaming.
|
|
||||||
*
|
|
||||||
* This option applies only if the endpoint returns a stream of events.
|
|
||||||
*
|
|
||||||
* @param error The error that occurred.
|
|
||||||
*/
|
|
||||||
onSseError?: (error: unknown) => void;
|
|
||||||
/**
|
|
||||||
* Callback invoked when an event is streamed from the server.
|
|
||||||
*
|
|
||||||
* This option applies only if the endpoint returns a stream of events.
|
|
||||||
*
|
|
||||||
* @param event Event streamed from the server.
|
|
||||||
* @returns Nothing (void).
|
|
||||||
*/
|
|
||||||
onSseEvent?: (event: StreamEvent<TData>) => void;
|
|
||||||
serializedBody?: RequestInit['body'];
|
|
||||||
/**
|
|
||||||
* Default retry delay in milliseconds.
|
|
||||||
*
|
|
||||||
* This option applies only if the endpoint returns a stream of events.
|
|
||||||
*
|
|
||||||
* @default 3000
|
|
||||||
*/
|
|
||||||
sseDefaultRetryDelay?: number;
|
|
||||||
/**
|
|
||||||
* Maximum number of retry attempts before giving up.
|
|
||||||
*/
|
|
||||||
sseMaxRetryAttempts?: number;
|
|
||||||
/**
|
|
||||||
* Maximum retry delay in milliseconds.
|
|
||||||
*
|
|
||||||
* Applies only when exponential backoff is used.
|
|
||||||
*
|
|
||||||
* This option applies only if the endpoint returns a stream of events.
|
|
||||||
*
|
|
||||||
* @default 30000
|
|
||||||
*/
|
|
||||||
sseMaxRetryDelay?: number;
|
|
||||||
/**
|
|
||||||
* Optional sleep function for retry backoff.
|
|
||||||
*
|
|
||||||
* Defaults to using `setTimeout`.
|
|
||||||
*/
|
|
||||||
sseSleepFn?: (ms: number) => Promise<void>;
|
|
||||||
url: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface StreamEvent<TData = unknown> {
|
|
||||||
data: TData;
|
|
||||||
event?: string;
|
|
||||||
id?: string;
|
|
||||||
retry?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ServerSentEventsResult<TData = unknown, TReturn = void, TNext = unknown> = {
|
|
||||||
stream: AsyncGenerator<
|
|
||||||
TData extends Record<string, unknown> ? TData[keyof TData] : TData,
|
|
||||||
TReturn,
|
|
||||||
TNext
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createSseClient = <TData = unknown>({
|
|
||||||
onRequest,
|
|
||||||
onSseError,
|
|
||||||
onSseEvent,
|
|
||||||
responseTransformer,
|
|
||||||
responseValidator,
|
|
||||||
sseDefaultRetryDelay,
|
|
||||||
sseMaxRetryAttempts,
|
|
||||||
sseMaxRetryDelay,
|
|
||||||
sseSleepFn,
|
|
||||||
url,
|
|
||||||
...options
|
|
||||||
}: ServerSentEventsOptions): ServerSentEventsResult<TData> => {
|
|
||||||
let lastEventId: string | undefined;
|
|
||||||
|
|
||||||
const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
||||||
|
|
||||||
const createStream = async function* () {
|
|
||||||
let retryDelay: number = sseDefaultRetryDelay ?? 3000;
|
|
||||||
let attempt = 0;
|
|
||||||
const signal = options.signal ?? new AbortController().signal;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (signal.aborted) break;
|
|
||||||
|
|
||||||
attempt++;
|
|
||||||
|
|
||||||
const headers =
|
|
||||||
options.headers instanceof Headers
|
|
||||||
? options.headers
|
|
||||||
: new Headers(options.headers as Record<string, string> | undefined);
|
|
||||||
|
|
||||||
if (lastEventId !== undefined) {
|
|
||||||
headers.set('Last-Event-ID', lastEventId);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const requestInit: RequestInit = {
|
|
||||||
redirect: 'follow',
|
|
||||||
...options,
|
|
||||||
body: options.serializedBody,
|
|
||||||
headers,
|
|
||||||
signal
|
|
||||||
};
|
|
||||||
let request = new Request(url, requestInit);
|
|
||||||
if (onRequest) {
|
|
||||||
request = await onRequest(url, requestInit);
|
|
||||||
}
|
|
||||||
// fetch must be assigned here, otherwise it would throw the error:
|
|
||||||
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
||||||
const _fetch = options.fetch ?? globalThis.fetch;
|
|
||||||
const response = await _fetch(request);
|
|
||||||
|
|
||||||
if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
|
|
||||||
|
|
||||||
if (!response.body) throw new Error('No body in SSE response');
|
|
||||||
|
|
||||||
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
||||||
|
|
||||||
let buffer = '';
|
|
||||||
|
|
||||||
const abortHandler = () => {
|
|
||||||
try {
|
|
||||||
reader.cancel();
|
|
||||||
} catch {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
signal.addEventListener('abort', abortHandler);
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
const { done, value } = await reader.read();
|
|
||||||
if (done) break;
|
|
||||||
buffer += value;
|
|
||||||
// Normalize line endings: CRLF -> LF, then CR -> LF
|
|
||||||
buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
||||||
|
|
||||||
const chunks = buffer.split('\n\n');
|
|
||||||
buffer = chunks.pop() ?? '';
|
|
||||||
|
|
||||||
for (const chunk of chunks) {
|
|
||||||
const lines = chunk.split('\n');
|
|
||||||
const dataLines: Array<string> = [];
|
|
||||||
let eventName: string | undefined;
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
if (line.startsWith('data:')) {
|
|
||||||
dataLines.push(line.replace(/^data:\s*/, ''));
|
|
||||||
} else if (line.startsWith('event:')) {
|
|
||||||
eventName = line.replace(/^event:\s*/, '');
|
|
||||||
} else if (line.startsWith('id:')) {
|
|
||||||
lastEventId = line.replace(/^id:\s*/, '');
|
|
||||||
} else if (line.startsWith('retry:')) {
|
|
||||||
const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10);
|
|
||||||
if (!Number.isNaN(parsed)) {
|
|
||||||
retryDelay = parsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let data: unknown;
|
|
||||||
let parsedJson = false;
|
|
||||||
|
|
||||||
if (dataLines.length) {
|
|
||||||
const rawData = dataLines.join('\n');
|
|
||||||
try {
|
|
||||||
data = JSON.parse(rawData);
|
|
||||||
parsedJson = true;
|
|
||||||
} catch {
|
|
||||||
data = rawData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedJson) {
|
|
||||||
if (responseValidator) {
|
|
||||||
await responseValidator(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responseTransformer) {
|
|
||||||
data = await responseTransformer(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSseEvent?.({
|
|
||||||
data,
|
|
||||||
event: eventName,
|
|
||||||
id: lastEventId,
|
|
||||||
retry: retryDelay
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dataLines.length) {
|
|
||||||
yield data as any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
signal.removeEventListener('abort', abortHandler);
|
|
||||||
reader.releaseLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
break; // exit loop on normal completion
|
|
||||||
} catch (error) {
|
|
||||||
// connection failed or aborted; retry after delay
|
|
||||||
onSseError?.(error);
|
|
||||||
|
|
||||||
if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) {
|
|
||||||
break; // stop after firing error
|
|
||||||
}
|
|
||||||
|
|
||||||
// exponential backoff: double retry each attempt, cap at 30s
|
|
||||||
const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000);
|
|
||||||
await sleep(backoff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const stream = createStream();
|
|
||||||
|
|
||||||
return { stream };
|
|
||||||
};
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import type { Auth, AuthToken } from './auth.gen';
|
|
||||||
import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen';
|
|
||||||
|
|
||||||
export type HttpMethod =
|
|
||||||
| 'connect'
|
|
||||||
| 'delete'
|
|
||||||
| 'get'
|
|
||||||
| 'head'
|
|
||||||
| 'options'
|
|
||||||
| 'patch'
|
|
||||||
| 'post'
|
|
||||||
| 'put'
|
|
||||||
| 'trace';
|
|
||||||
|
|
||||||
export type Client<
|
|
||||||
RequestFn = never,
|
|
||||||
Config = unknown,
|
|
||||||
MethodFn = never,
|
|
||||||
BuildUrlFn = never,
|
|
||||||
SseFn = never
|
|
||||||
> = {
|
|
||||||
/**
|
|
||||||
* Returns the final request URL.
|
|
||||||
*/
|
|
||||||
buildUrl: BuildUrlFn;
|
|
||||||
getConfig: () => Config;
|
|
||||||
request: RequestFn;
|
|
||||||
setConfig: (config: Config) => Config;
|
|
||||||
} & {
|
|
||||||
[K in HttpMethod]: MethodFn;
|
|
||||||
} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } });
|
|
||||||
|
|
||||||
export interface Config {
|
|
||||||
/**
|
|
||||||
* Auth token or a function returning auth token. The resolved value will be
|
|
||||||
* added to the request payload as defined by its `security` array.
|
|
||||||
*/
|
|
||||||
auth?: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken;
|
|
||||||
/**
|
|
||||||
* A function for serializing request body parameter. By default,
|
|
||||||
* {@link JSON.stringify()} will be used.
|
|
||||||
*/
|
|
||||||
bodySerializer?: BodySerializer | null;
|
|
||||||
/**
|
|
||||||
* An object containing any HTTP headers that you want to pre-populate your
|
|
||||||
* `Headers` object with.
|
|
||||||
*
|
|
||||||
* {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
|
|
||||||
*/
|
|
||||||
headers?:
|
|
||||||
| RequestInit['headers']
|
|
||||||
| Record<
|
|
||||||
string,
|
|
||||||
string | number | boolean | (string | number | boolean)[] | null | undefined | unknown
|
|
||||||
>;
|
|
||||||
/**
|
|
||||||
* The request method.
|
|
||||||
*
|
|
||||||
* {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more}
|
|
||||||
*/
|
|
||||||
method?: Uppercase<HttpMethod>;
|
|
||||||
/**
|
|
||||||
* A function for serializing request query parameters. By default, arrays
|
|
||||||
* will be exploded in form style, objects will be exploded in deepObject
|
|
||||||
* style, and reserved characters are percent-encoded.
|
|
||||||
*
|
|
||||||
* This method will have no effect if the native `paramsSerializer()` Axios
|
|
||||||
* API function is used.
|
|
||||||
*
|
|
||||||
* {@link https://swagger.io/docs/specification/serialization/#query View examples}
|
|
||||||
*/
|
|
||||||
querySerializer?: QuerySerializer | QuerySerializerOptions;
|
|
||||||
/**
|
|
||||||
* A function validating request data. This is useful if you want to ensure
|
|
||||||
* the request conforms to the desired shape, so it can be safely sent to
|
|
||||||
* the server.
|
|
||||||
*/
|
|
||||||
requestValidator?: (data: unknown) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* A function transforming response data before it's returned. This is useful
|
|
||||||
* for post-processing data, e.g., converting ISO strings into Date objects.
|
|
||||||
*/
|
|
||||||
responseTransformer?: (data: unknown) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* A function validating response data. This is useful if you want to ensure
|
|
||||||
* the response conforms to the desired shape, so it can be safely passed to
|
|
||||||
* the transformers and returned to the user.
|
|
||||||
*/
|
|
||||||
responseValidator?: (data: unknown) => Promise<unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
|
|
||||||
? true
|
|
||||||
: [T] extends [never | undefined]
|
|
||||||
? [undefined] extends [T]
|
|
||||||
? false
|
|
||||||
: true
|
|
||||||
: false;
|
|
||||||
|
|
||||||
export type OmitNever<T extends Record<string, unknown>> = {
|
|
||||||
[K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true ? never : K]: T[K];
|
|
||||||
};
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
|
||||||
|
|
||||||
import type { BodySerializer, QuerySerializer } from './bodySerializer.gen';
|
|
||||||
import {
|
|
||||||
type ArraySeparatorStyle,
|
|
||||||
serializeArrayParam,
|
|
||||||
serializeObjectParam,
|
|
||||||
serializePrimitiveParam
|
|
||||||
} from './pathSerializer.gen';
|
|
||||||
|
|
||||||
export interface PathSerializer {
|
|
||||||
path: Record<string, unknown>;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
||||||
|
|
||||||
export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
|
|
||||||
let url = _url;
|
|
||||||
const matches = _url.match(PATH_PARAM_RE);
|
|
||||||
if (matches) {
|
|
||||||
for (const match of matches) {
|
|
||||||
let explode = false;
|
|
||||||
let name = match.substring(1, match.length - 1);
|
|
||||||
let style: ArraySeparatorStyle = 'simple';
|
|
||||||
|
|
||||||
if (name.endsWith('*')) {
|
|
||||||
explode = true;
|
|
||||||
name = name.substring(0, name.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.startsWith('.')) {
|
|
||||||
name = name.substring(1);
|
|
||||||
style = 'label';
|
|
||||||
} else if (name.startsWith(';')) {
|
|
||||||
name = name.substring(1);
|
|
||||||
style = 'matrix';
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = path[name];
|
|
||||||
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'object') {
|
|
||||||
url = url.replace(
|
|
||||||
match,
|
|
||||||
serializeObjectParam({
|
|
||||||
explode,
|
|
||||||
name,
|
|
||||||
style,
|
|
||||||
value: value as Record<string, unknown>,
|
|
||||||
valueOnly: true
|
|
||||||
})
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style === 'matrix') {
|
|
||||||
url = url.replace(
|
|
||||||
match,
|
|
||||||
`;${serializePrimitiveParam({
|
|
||||||
name,
|
|
||||||
value: value as string
|
|
||||||
})}`
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const replaceValue = encodeURIComponent(
|
|
||||||
style === 'label' ? `.${value as string}` : (value as string)
|
|
||||||
);
|
|
||||||
url = url.replace(match, replaceValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUrl = ({
|
|
||||||
baseUrl,
|
|
||||||
path,
|
|
||||||
query,
|
|
||||||
querySerializer,
|
|
||||||
url: _url
|
|
||||||
}: {
|
|
||||||
baseUrl?: string;
|
|
||||||
path?: Record<string, unknown>;
|
|
||||||
query?: Record<string, unknown>;
|
|
||||||
querySerializer: QuerySerializer;
|
|
||||||
url: string;
|
|
||||||
}) => {
|
|
||||||
const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
|
|
||||||
let url = (baseUrl ?? '') + pathUrl;
|
|
||||||
if (path) {
|
|
||||||
url = defaultPathSerializer({ path, url });
|
|
||||||
}
|
|
||||||
let search = query ? querySerializer(query) : '';
|
|
||||||
if (search.startsWith('?')) {
|
|
||||||
search = search.substring(1);
|
|
||||||
}
|
|
||||||
if (search) {
|
|
||||||
url += `?${search}`;
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getValidRequestBody(options: {
|
|
||||||
body?: unknown;
|
|
||||||
bodySerializer?: BodySerializer | null;
|
|
||||||
serializedBody?: unknown;
|
|
||||||
}) {
|
|
||||||
const hasBody = options.body !== undefined;
|
|
||||||
const isSerializedBody = hasBody && options.bodySerializer;
|
|
||||||
|
|
||||||
if (isSerializedBody) {
|
|
||||||
if ('serializedBody' in options) {
|
|
||||||
const hasSerializedBody =
|
|
||||||
options.serializedBody !== undefined && options.serializedBody !== '';
|
|
||||||
|
|
||||||
return hasSerializedBody ? options.serializedBody : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not all clients implement a serializedBody property (i.e., client-axios)
|
|
||||||
return options.body !== '' ? options.body : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// plain/text body
|
|
||||||
if (hasBody) {
|
|
||||||
return options.body;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no body was provided
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,288 +0,0 @@
|
|||||||
import { type ContentNode } from '$lib/types/content-node.d';
|
|
||||||
import { parseSetCookie } from 'set-cookie-parser';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* eCamp3 API Client
|
|
||||||
*
|
|
||||||
* Supports authentication and retrieval of activities with their content nodes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface AuthResponse {
|
|
||||||
token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Activity {
|
|
||||||
'@id': string;
|
|
||||||
'@type': string;
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
location: string;
|
|
||||||
camp: string; // IRI
|
|
||||||
category: Category | string; // Embedded or IRI
|
|
||||||
progressLabel: ActivityProgressLabel | string | null; // Embedded or IRI
|
|
||||||
scheduleEntries: ScheduleEntry[];
|
|
||||||
contentNodes?: ContentNode[]; // Populated when using specific normalization groups
|
|
||||||
rootContentNode: string; // IRI to the root ColumnLayout
|
|
||||||
createTime: string;
|
|
||||||
updateTime: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Category {
|
|
||||||
'@id': string;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
color: string;
|
|
||||||
numbering: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActivityProgressLabel {
|
|
||||||
'@id': string;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
color: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ScheduleEntry {
|
|
||||||
'@id': string;
|
|
||||||
id: string;
|
|
||||||
period: string; // IRI
|
|
||||||
start: string; // ISO Date
|
|
||||||
end: string; // ISO Date
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaginatedResponse<T> {
|
|
||||||
'hydra:member': T[];
|
|
||||||
'hydra:totalItems': number;
|
|
||||||
'hydra:view'?: {
|
|
||||||
'@id': string;
|
|
||||||
'@type': string;
|
|
||||||
'hydra:first': string;
|
|
||||||
'hydra:last': string;
|
|
||||||
'hydra:next'?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Invitation {
|
|
||||||
id: string;
|
|
||||||
campId: string;
|
|
||||||
campTitle: string;
|
|
||||||
}
|
|
||||||
export interface Options {
|
|
||||||
auth?: AuthOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthOptions {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Auth {
|
|
||||||
content?: string;
|
|
||||||
signature?: string;
|
|
||||||
refresh?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Link {
|
|
||||||
href: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GetCampsResponse {
|
|
||||||
_links: {
|
|
||||||
items: Link[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ECampClient {
|
|
||||||
private auth: Auth | null = null;
|
|
||||||
private baseUrl: string;
|
|
||||||
private _ready: Promise<void>;
|
|
||||||
public get ready() {
|
|
||||||
return this._ready;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(baseUrl: string = 'http://localhost:3000/api', options?: Options) {
|
|
||||||
// Remove trailing slash if present
|
|
||||||
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
||||||
if (options?.auth) {
|
|
||||||
this._ready = this.login(options.auth.username, options.auth.password).catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._ready = new Promise<void>((r) => r());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticate with the API using email and password.
|
|
||||||
*/
|
|
||||||
async login(email: string, password: string): Promise<void> {
|
|
||||||
console.debug('start login');
|
|
||||||
const response = await fetch(`${this.baseUrl}/authentication_token`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ identifier: email, password })
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`Login failed: ${response.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const cookies = parseSetCookie(response.headers.getSetCookie(), { decodeValues: true });
|
|
||||||
cookies.forEach((c) => {
|
|
||||||
if (c.name.endsWith('jwt_hp')) {
|
|
||||||
this.auth = {
|
|
||||||
...this.auth,
|
|
||||||
content: c.value
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.name.endsWith('jwt_s')) {
|
|
||||||
this.auth = {
|
|
||||||
...this.auth,
|
|
||||||
signature: c.value
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.name.endsWith('refresh_token')) {
|
|
||||||
this.auth = {
|
|
||||||
...this.auth,
|
|
||||||
refresh: c.value
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.debug('loggin succeded');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a pre-existing JWT token.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of activities.
|
|
||||||
* If campId is provided, filters by that camp.
|
|
||||||
*/
|
|
||||||
async getActivities(campId?: string): Promise<Activity[]> {
|
|
||||||
let url = `${this.baseUrl}/activities`;
|
|
||||||
if (campId) {
|
|
||||||
// Handle both raw ID and IRI
|
|
||||||
const id = campId.includes('/') ? campId.split('/').pop() : campId;
|
|
||||||
url += `?camp=${encodeURIComponent(`/camps/${id}`)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.fetchJson<PaginatedResponse<Activity>>(url);
|
|
||||||
return data['hydra:member'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a single activity by its ID or IRI.
|
|
||||||
* This includes the embedded content nodes.
|
|
||||||
*/
|
|
||||||
async getActivity(activityId: string): Promise<Activity> {
|
|
||||||
const id = activityId.includes('/') ? activityId.split('/').pop() : activityId;
|
|
||||||
const url = `${this.baseUrl}/activities/${id}`;
|
|
||||||
|
|
||||||
return this.fetchJson<Activity>(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getInvitations() {
|
|
||||||
const url = `${this.baseUrl}/personal_invitations`;
|
|
||||||
return this.fetchJson<Invitation[]>(url);
|
|
||||||
}
|
|
||||||
private async acceptInvitation(invitation: Invitation) {
|
|
||||||
const url = `${this.baseUrl}/personal_invitations/${invitation.id}/accept`;
|
|
||||||
return this.fetchJson<Invitation>(url, {
|
|
||||||
method: 'PATCH',
|
|
||||||
body: '{}',
|
|
||||||
headers: { 'Content-Type': 'application/merge-patch+json' }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async getCampIds(): Promise<string[]> {
|
|
||||||
const url = `${this.baseUrl}/camps`;
|
|
||||||
|
|
||||||
const res = await this.fetchJson<GetCampsResponse>(url);
|
|
||||||
|
|
||||||
return res._links.items.map((l) => l.href.split('/').pop()).filter((e) => e !== undefined);
|
|
||||||
}
|
|
||||||
async acceptAllInvitaions() {
|
|
||||||
const invitations = await this.getInvitations();
|
|
||||||
if (invitations.length <= 0) return;
|
|
||||||
await Promise.all(
|
|
||||||
invitations.map((i) =>
|
|
||||||
this.acceptInvitation(i).catch((e) => console.error('could not accept invitation', i, e))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getActivityContent(activityId: string) {
|
|
||||||
const activity = await this.getActivity(activityId);
|
|
||||||
const contents = await this.getContentNodes(activity.rootContentNode);
|
|
||||||
return this.reconstructTree(contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all content nodes belonging to a specific root node (tree).
|
|
||||||
*/
|
|
||||||
async getContentNodes(rootIri: string): Promise<ContentNode[]> {
|
|
||||||
// The API allows filtering content nodes by their root node
|
|
||||||
const url = `${this.baseUrl}/content_nodes?root=${encodeURIComponent(rootIri)}`;
|
|
||||||
return this.fetchJson<ContentNode[]>(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reconstructs a tree structure from a flat list of ContentNodes.
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
reconstructTree(nodes: ContentNode[]): (ContentNode & { childNodes: any[] })[] {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const nodeMap = new Map<string, ContentNode & { childNodes: any[] }>();
|
|
||||||
|
|
||||||
// First pass: Create the map and initialize children arrays
|
|
||||||
nodes.forEach((node) => {
|
|
||||||
nodeMap.set(node.id!, { ...node, childNodes: [] });
|
|
||||||
});
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const rootNodes: (ContentNode & { childNodes: any[] })[] = [];
|
|
||||||
|
|
||||||
// Second pass: Build the tree
|
|
||||||
nodes.forEach((node) => {
|
|
||||||
const wrappedNode = nodeMap.get(node.id!)!;
|
|
||||||
if (node.parent && nodeMap.has(node.parent)) {
|
|
||||||
const parent = nodeMap.get(node.parent)!;
|
|
||||||
parent.childNodes.push(wrappedNode);
|
|
||||||
// Sort by position
|
|
||||||
parent.childNodes.sort((a, b) => a.position - b.position);
|
|
||||||
} else {
|
|
||||||
rootNodes.push(wrappedNode);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return rootNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async fetchJson<T>(url: string, options: RequestInit = {}): Promise<T> {
|
|
||||||
const headers: Record<string, string> = {
|
|
||||||
Accept: 'application/json',
|
|
||||||
...(options.headers as Record<string, string>)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.auth?.content && this.auth.refresh) {
|
|
||||||
headers['Authorization'] = `Bearer ${this.auth.content}.${this.auth.signature}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(url, { ...options, headers });
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
if (response.status === 401) {
|
|
||||||
throw new Error('Unauthorized: Please check your credentials or token.');
|
|
||||||
}
|
|
||||||
throw new Error(`API Request failed: ${response.status} ${response.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import { env } from '$env/dynamic/private';
|
|
||||||
import { ECampClient } from './client';
|
|
||||||
|
|
||||||
export const ecamp: ECampClient = new ECampClient(env.ECAMP_BASE_URL, {
|
|
||||||
auth: { username: env.ECAMP_USER, password: env.ECAMP_PASSWORD }
|
|
||||||
});
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
import type { Session, User } from '@auth/sveltekit';
|
import type { Session, User } from '@auth/sveltekit';
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import { db } from './server/db';
|
import { db } from './db';
|
||||||
import { users } from './server/db/schema';
|
import { users } from './db/schema';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
interface Event {
|
interface Event {
|
||||||
locals: {
|
locals: {
|
||||||
Vendored
-150
@@ -1,150 +0,0 @@
|
|||||||
/**
|
|
||||||
* eCamp3 Content Node Types
|
|
||||||
* Generated based on PHP Entity definitions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Base properties shared by all ContentNodes */
|
|
||||||
export interface ContentNode {
|
|
||||||
/** JSON-LD context */
|
|
||||||
'@id'?: string;
|
|
||||||
/** JSON-LD type */
|
|
||||||
'@type'?: string;
|
|
||||||
|
|
||||||
/** Internal unique identifier (12-character hex string) */
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
/** IRI of the root content node in the tree (usually a ColumnLayout) */
|
|
||||||
root: string;
|
|
||||||
|
|
||||||
/** IRI of the parent node. Null if this is the root. */
|
|
||||||
parent: string | null;
|
|
||||||
|
|
||||||
/** Array of IRIs pointing to direct child content nodes */
|
|
||||||
children: string[];
|
|
||||||
|
|
||||||
/** Name of the slot in the parent container where this node resides */
|
|
||||||
slot: string | null;
|
|
||||||
|
|
||||||
/** Ordering position within the current slot */
|
|
||||||
position: number;
|
|
||||||
|
|
||||||
/** Optional display name (e.g., "Bad Weather Program") */
|
|
||||||
instanceName: string | null;
|
|
||||||
|
|
||||||
/** IRI of the associated ContentType */
|
|
||||||
contentType: string;
|
|
||||||
|
|
||||||
/** Convenience field for the name of the content type */
|
|
||||||
contentTypeName: string;
|
|
||||||
|
|
||||||
/** ISO DateTime string representing creation time */
|
|
||||||
createTime?: string;
|
|
||||||
/** ISO DateTime string representing last update time */
|
|
||||||
updateTime?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 1. Single Text (Standard free-text field) */
|
|
||||||
export interface SingleTextNode extends ContentNode {
|
|
||||||
contentTypeName: 'SingleText';
|
|
||||||
data: {
|
|
||||||
/** HTML content of the text field */
|
|
||||||
html: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 2. Storyboard (Three-column activity planning grid) */
|
|
||||||
export interface StoryboardNode extends ContentNode {
|
|
||||||
contentTypeName: 'Storyboard';
|
|
||||||
data: {
|
|
||||||
/** Keyed by UUID v4 */
|
|
||||||
sections: {
|
|
||||||
[uuid: string]: {
|
|
||||||
column1: string;
|
|
||||||
column2Html: string;
|
|
||||||
column3: string;
|
|
||||||
position: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 3. MultiSelect (Checkbox options, e.g., for safety or environment topics) */
|
|
||||||
export interface MultiSelectNode extends ContentNode {
|
|
||||||
contentTypeName: 'MultiSelect';
|
|
||||||
data: {
|
|
||||||
options: {
|
|
||||||
[key: string]: {
|
|
||||||
checked: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 4. Column Layout (Container used to split content into columns) */
|
|
||||||
export interface ColumnLayoutNode extends ContentNode {
|
|
||||||
contentTypeName: 'ColumnLayout';
|
|
||||||
data: {
|
|
||||||
columns: Array<{
|
|
||||||
/** Slot identifier (numeric string) */
|
|
||||||
slot: string;
|
|
||||||
/** Column width in a 12-column grid */
|
|
||||||
width: number;
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 5. Responsive Layout (Specialized container for Main/Sidebar layouts) */
|
|
||||||
export interface ResponsiveLayoutNode extends ContentNode {
|
|
||||||
contentTypeName: 'ResponsiveLayout';
|
|
||||||
data: {
|
|
||||||
items: Array<{
|
|
||||||
slot: 'main' | 'aside-top' | 'aside-bottom';
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 6. Material Node (Container for physical equipment items) */
|
|
||||||
export interface MaterialNode extends ContentNode {
|
|
||||||
contentTypeName: 'MaterialNode';
|
|
||||||
/** Material nodes typically have null data as they use a OneToMany relation */
|
|
||||||
data: null;
|
|
||||||
/** Embedded MaterialItems for this node type */
|
|
||||||
materialItems: MaterialItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A physical item required for a programme */
|
|
||||||
export interface MaterialItem {
|
|
||||||
'@id'?: string;
|
|
||||||
id: string;
|
|
||||||
/** Name/description of the item */
|
|
||||||
article: string;
|
|
||||||
/** Quantity required */
|
|
||||||
quantity: number | null;
|
|
||||||
/** Unit of measurement (e.g., 'kg', 'pieces') */
|
|
||||||
unit: string | null;
|
|
||||||
/** Preparation status */
|
|
||||||
done: boolean;
|
|
||||||
/** IRI of the MaterialList this belongs to */
|
|
||||||
materialList: string;
|
|
||||||
/** IRI of the Camp this belongs to */
|
|
||||||
camp: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 7. Checklist Node (Selection of tasks/checklist items) */
|
|
||||||
export interface ChecklistNode extends ContentNode {
|
|
||||||
contentTypeName: 'ChecklistNode';
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
data: null | Record<string, any>;
|
|
||||||
/** IRIs to ChecklistItem entities */
|
|
||||||
checklistItems: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Discriminated Union for safe handling of ContentNodes in TypeScript */
|
|
||||||
export type ContentNode =
|
|
||||||
| SingleTextNode
|
|
||||||
| StoryboardNode
|
|
||||||
| MultiSelectNode
|
|
||||||
| ColumnLayoutNode
|
|
||||||
| ResponsiveLayoutNode
|
|
||||||
| MaterialNode
|
|
||||||
| ChecklistNode;
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getSession as getSession } from '$lib/auth';
|
import { getSession as getSession } from '$lib/server/session';
|
||||||
import type { LayoutServerLoad } from './$types';
|
import type { LayoutServerLoad } from './$types';
|
||||||
|
|
||||||
export const load: LayoutServerLoad = async (event) => {
|
export const load: LayoutServerLoad = async (event) => {
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import { extractFormData } from '$lib/extractFormData';
|
|||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
|
|
||||||
import * as v from 'valibot';
|
import * as v from 'valibot';
|
||||||
import { ensureAuth } from '$lib/auth';
|
import { ensureAuth } from '$lib/server/session';
|
||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { aktis } from '$lib/server/db/schema';
|
import { aktis } from '$lib/server/db/schema';
|
||||||
|
import sanitizeHtml from 'sanitize-html';
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
await ensureAuth(event);
|
await ensureAuth(event);
|
||||||
return {};
|
return {};
|
||||||
@@ -28,6 +29,8 @@ export const actions = {
|
|||||||
|
|
||||||
if (!akti) return {};
|
if (!akti) return {};
|
||||||
|
|
||||||
|
akti.body = sanitizeHtml(akti.body);
|
||||||
|
|
||||||
const res = await db
|
const res = await db
|
||||||
.insert(aktis)
|
.insert(aktis)
|
||||||
.values({ ...akti, author: user.id! })
|
.values({ ...akti, author: user.id! })
|
||||||
|
|||||||
@@ -3,21 +3,23 @@ import { aktis, ratings } from '$lib/server/db/schema';
|
|||||||
import { error, redirect, type Actions } from '@sveltejs/kit';
|
import { error, redirect, type Actions } from '@sveltejs/kit';
|
||||||
import { and, eq } from 'drizzle-orm';
|
import { and, eq } from 'drizzle-orm';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { ensureAuth } from '$lib/auth';
|
import { ensureAuth } from '$lib/server/session';
|
||||||
import { extractFormData } from '$lib/extractFormData';
|
import { extractFormData } from '$lib/extractFormData';
|
||||||
import * as v from 'valibot';
|
import * as v from 'valibot';
|
||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
|
import sanitizeHtml from 'sanitize-html';
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const akti = await db.query.aktis.findFirst({
|
const [akti, r] = await Promise.all([
|
||||||
|
db.query.aktis.findFirst({
|
||||||
where: eq(aktis.id, event.params.aktiId),
|
where: eq(aktis.id, event.params.aktiId),
|
||||||
with: { author: true }
|
with: { author: true }
|
||||||
});
|
}),
|
||||||
|
db.query.ratings.findMany({
|
||||||
const r = await db.query.ratings.findMany({
|
|
||||||
with: { user: true },
|
with: { user: true },
|
||||||
where: eq(ratings.aktiId, event.params.aktiId)
|
where: eq(ratings.aktiId, event.params.aktiId)
|
||||||
});
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
if (!akti) {
|
if (!akti) {
|
||||||
error(404, { message: 'Die Akti gits garnid, sorry...' });
|
error(404, { message: 'Die Akti gits garnid, sorry...' });
|
||||||
@@ -56,6 +58,8 @@ export const actions = {
|
|||||||
|
|
||||||
if (!changeRequest) return error(400);
|
if (!changeRequest) return error(400);
|
||||||
|
|
||||||
|
changeRequest.body = sanitizeHtml(changeRequest.body);
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.update(aktis)
|
.update(aktis)
|
||||||
.set({ ...changeRequest, version: akti[0].version + 1 })
|
.set({ ...changeRequest, version: akti[0].version + 1 })
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { ensureAuth } from '$lib/auth';
|
import { ensureAuth } from '$lib/server/session';
|
||||||
import { error, redirect, type Actions } from '@sveltejs/kit';
|
import { error, redirect, type Actions } from '@sveltejs/kit';
|
||||||
import { extractFormData } from '$lib/extractFormData';
|
import { extractFormData } from '$lib/extractFormData';
|
||||||
import { aktis, ratings } from '$lib/server/db/schema';
|
import { aktis, ratings } from '$lib/server/db/schema';
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { Button } from 'flowbite-svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
onclick={() => {
|
|
||||||
navigator.clipboard.read().then((i) => console.log(i));
|
|
||||||
}}>Import</Button
|
|
||||||
>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import type { PageServerLoad } from './$types';
|
|
||||||
|
|
||||||
import { ensureAuth } from '$lib/auth';
|
|
||||||
import { ecamp } from '$lib/server/ecamp';
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
|
||||||
await ensureAuth(event);
|
|
||||||
await ecamp.ready;
|
|
||||||
await ecamp.acceptAllInvitaions();
|
|
||||||
const activity = await ecamp.getActivityContent(event.params.activityId);
|
|
||||||
|
|
||||||
return { activity };
|
|
||||||
};
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import ContentNodeDisplay from '$lib/components/ecamp/ContentNodeDisplay.svelte';
|
|
||||||
import type { MaterialNode, SingleTextNode, StoryboardNode } from '$lib/types/content-node';
|
|
||||||
import type { PageProps } from './$types';
|
|
||||||
|
|
||||||
let { data }: PageProps = $props();
|
|
||||||
|
|
||||||
let storyboard = $derived.by(() => {
|
|
||||||
const storyboard = data.activity.find((n) => n.contentTypeName === 'Storyboard');
|
|
||||||
if (!storyboard) return [];
|
|
||||||
|
|
||||||
const sections = (storyboard as object as StoryboardNode).data.sections;
|
|
||||||
|
|
||||||
return Object.values(sections).sort((a, b) => a.position - b.position);
|
|
||||||
});
|
|
||||||
let safety = $derived.by(() => {
|
|
||||||
const safety = data.activity.find((n) => n.contentTypeName === 'SafetyConsiderations');
|
|
||||||
if (!safety) return null;
|
|
||||||
|
|
||||||
return (safety as object as SingleTextNode).data.html;
|
|
||||||
});
|
|
||||||
let materials = $derived.by(() => {
|
|
||||||
const materials = data.activity.find((n) => n.contentTypeName === 'Material');
|
|
||||||
if (!materials) return [];
|
|
||||||
|
|
||||||
const items = (materials as object as MaterialNode).materialItems;
|
|
||||||
return items;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if storyboard.length > 0}
|
|
||||||
<h3>storyboard</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Zyt</th>
|
|
||||||
<th>Programm</th>
|
|
||||||
<th>Zueständig</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each storyboard as entry (entry.position)}
|
|
||||||
<tr>
|
|
||||||
<td>{entry.column1}</td>
|
|
||||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
||||||
<td>{@html entry.column2Html}</td>
|
|
||||||
<td>{entry.column3}</td>
|
|
||||||
</tr>{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if safety}
|
|
||||||
<section>
|
|
||||||
<h3>safety considerations</h3>
|
|
||||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
||||||
{@html safety}
|
|
||||||
</section>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if materials.length > 0}
|
|
||||||
<h3>materials</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Mängi</th>
|
|
||||||
<th>Iheit</th>
|
|
||||||
<th>Materiau</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each materials as item (item.id)}
|
|
||||||
<tr>
|
|
||||||
<td>{item.quantity}</td>
|
|
||||||
<td>{item.unit}</td>
|
|
||||||
<td>{item.article}</td>
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#each data.activity as node}
|
|
||||||
<ContentNodeDisplay {node} />
|
|
||||||
{/each}
|
|
||||||
+1
-10
@@ -11,16 +11,7 @@ const config = {
|
|||||||
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||||
adapter: adapter(),
|
adapter: adapter()
|
||||||
experimental: {
|
|
||||||
remoteFunctions: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
compilerOptions: {
|
|
||||||
experimental: {
|
|
||||||
async: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user