From b81edca0ff55062e082d8f42fc6d0336410adde7 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:11:05 +0200 Subject: [PATCH 01/65] Init deep sea stories example --- deep-sea-stories/.gitignore | 170 ++ deep-sea-stories/README.md | 1 + deep-sea-stories/biome.json | 35 + deep-sea-stories/package.json | 16 + .../packages/backend/package.json | 22 + deep-sea-stories/packages/backend/src/main.ts | 35 + .../packages/backend/tsconfig.json | 6 + deep-sea-stories/packages/web/package.json | 5 + deep-sea-stories/yarn.lock | 1820 +++++++++++++++++ 9 files changed, 2110 insertions(+) create mode 100644 deep-sea-stories/.gitignore create mode 100644 deep-sea-stories/README.md create mode 100644 deep-sea-stories/biome.json create mode 100644 deep-sea-stories/package.json create mode 100644 deep-sea-stories/packages/backend/package.json create mode 100644 deep-sea-stories/packages/backend/src/main.ts create mode 100644 deep-sea-stories/packages/backend/tsconfig.json create mode 100644 deep-sea-stories/packages/web/package.json create mode 100644 deep-sea-stories/yarn.lock diff --git a/deep-sea-stories/.gitignore b/deep-sea-stories/.gitignore new file mode 100644 index 0000000..fd2d95b --- /dev/null +++ b/deep-sea-stories/.gitignore @@ -0,0 +1,170 @@ +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### react ### +.DS_* +**/*.backup.* +**/*.back.* + +node_modules + +*.sublime* + +psd +thumb +sketch + +### yarn ### +# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored + +.yarn/* +!.yarn/releases +!.yarn/patches +!.yarn/plugins +!.yarn/sdks +!.yarn/versions + +# if you are NOT using Zero-installs, then: +# comment the following lines +!.yarn/cache + +# and uncomment the following lines +# .pnp.* + diff --git a/deep-sea-stories/README.md b/deep-sea-stories/README.md new file mode 100644 index 0000000..cf21f1a --- /dev/null +++ b/deep-sea-stories/README.md @@ -0,0 +1 @@ +# Deep Sea Stories Example App diff --git a/deep-sea-stories/biome.json b/deep-sea-stories/biome.json new file mode 100644 index 0000000..8f7d1f8 --- /dev/null +++ b/deep-sea-stories/biome.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "includes": ["**", "!**/dist"], + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json new file mode 100644 index 0000000..935b9a3 --- /dev/null +++ b/deep-sea-stories/package.json @@ -0,0 +1,16 @@ +{ + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4" + }, + "scripts": { + "format": "biome format --write", + "lint": "biome lint --write", + "check": "biome check --write" + } +} diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json new file mode 100644 index 0000000..997d86c --- /dev/null +++ b/deep-sea-stories/packages/backend/package.json @@ -0,0 +1,22 @@ +{ + "name": "backend", + "packageManager": "yarn@4.9.2", + "private": true, + "main": "./src/main.ts", + "type": "module", + "dependencies": { + "fastify": "^5.6.1", + "pino-pretty": "^13.1.1" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.1", + "@types/node": "^24.5.2", + "tsc": "^2.0.4", + "tsx": "^4.20.6", + "typescript": "^5.9.2" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "tsx watch src/main.ts" + } +} diff --git a/deep-sea-stories/packages/backend/src/main.ts b/deep-sea-stories/packages/backend/src/main.ts new file mode 100644 index 0000000..8a45034 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/main.ts @@ -0,0 +1,35 @@ +import Fastify, { + type FastifyInstance, + type RouteShorthandOptions, +} from 'fastify'; + +const server: FastifyInstance = Fastify({ + logger: { transport: { target: 'pino-pretty' } }, +}); +const port = 3000; + +const opts: RouteShorthandOptions = { + schema: { + response: { + 200: { + type: 'object', + properties: { + pong: { + type: 'string', + }, + }, + }, + }, + }, +}; + +server.get('/ping', opts, async (_request, _reply) => { + return { pong: 'it worked!' }; +}); + +try { + await server.listen({ port }); +} catch (err) { + server.log.error(err); + process.exit(1); +} diff --git a/deep-sea-stories/packages/backend/tsconfig.json b/deep-sea-stories/packages/backend/tsconfig.json new file mode 100644 index 0000000..5416a60 --- /dev/null +++ b/deep-sea-stories/packages/backend/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@tsconfig/node24/tsconfig.json", + "compilerOptions": { + "outDir": "dist" + } +} diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json new file mode 100644 index 0000000..9f8d766 --- /dev/null +++ b/deep-sea-stories/packages/web/package.json @@ -0,0 +1,5 @@ +{ + "name": "web", + "packageManager": "yarn@4.9.2", + "private": true +} diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock new file mode 100644 index 0000000..4f58036 --- /dev/null +++ b/deep-sea-stories/yarn.lock @@ -0,0 +1,1820 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@biomejs/biome@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/biome@npm:2.2.4" + dependencies: + "@biomejs/cli-darwin-arm64": "npm:2.2.4" + "@biomejs/cli-darwin-x64": "npm:2.2.4" + "@biomejs/cli-linux-arm64": "npm:2.2.4" + "@biomejs/cli-linux-arm64-musl": "npm:2.2.4" + "@biomejs/cli-linux-x64": "npm:2.2.4" + "@biomejs/cli-linux-x64-musl": "npm:2.2.4" + "@biomejs/cli-win32-arm64": "npm:2.2.4" + "@biomejs/cli-win32-x64": "npm:2.2.4" + dependenciesMeta: + "@biomejs/cli-darwin-arm64": + optional: true + "@biomejs/cli-darwin-x64": + optional: true + "@biomejs/cli-linux-arm64": + optional: true + "@biomejs/cli-linux-arm64-musl": + optional: true + "@biomejs/cli-linux-x64": + optional: true + "@biomejs/cli-linux-x64-musl": + optional: true + "@biomejs/cli-win32-arm64": + optional: true + "@biomejs/cli-win32-x64": + optional: true + bin: + biome: bin/biome + checksum: 10c0/7229fcc743db48f3cfd7417fb3f33d1cd9e7dfe42a12ed3c1046cd3110718237bb71ea3fe5c8b0de9bd3df2b918d0be58027602aa3720b64904b63d9cedf53e3 + languageName: node + linkType: hard + +"@biomejs/cli-darwin-arm64@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-darwin-arm64@npm:2.2.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@biomejs/cli-darwin-x64@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-darwin-x64@npm:2.2.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@biomejs/cli-linux-arm64-musl@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-linux-arm64-musl@npm:2.2.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@biomejs/cli-linux-arm64@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-linux-arm64@npm:2.2.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@biomejs/cli-linux-x64-musl@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-linux-x64-musl@npm:2.2.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@biomejs/cli-linux-x64@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-linux-x64@npm:2.2.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@biomejs/cli-win32-arm64@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-win32-arm64@npm:2.2.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@biomejs/cli-win32-x64@npm:2.2.4": + version: 2.2.4 + resolution: "@biomejs/cli-win32-x64@npm:2.2.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/aix-ppc64@npm:0.25.10" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/android-arm64@npm:0.25.10" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/android-arm@npm:0.25.10" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/android-x64@npm:0.25.10" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/darwin-arm64@npm:0.25.10" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/darwin-x64@npm:0.25.10" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/freebsd-arm64@npm:0.25.10" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/freebsd-x64@npm:0.25.10" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-arm64@npm:0.25.10" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-arm@npm:0.25.10" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-ia32@npm:0.25.10" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-loong64@npm:0.25.10" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-mips64el@npm:0.25.10" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-ppc64@npm:0.25.10" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-riscv64@npm:0.25.10" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-s390x@npm:0.25.10" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-x64@npm:0.25.10" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/netbsd-arm64@npm:0.25.10" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/netbsd-x64@npm:0.25.10" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/openbsd-arm64@npm:0.25.10" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/openbsd-x64@npm:0.25.10" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/openharmony-arm64@npm:0.25.10" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/sunos-x64@npm:0.25.10" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/win32-arm64@npm:0.25.10" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/win32-ia32@npm:0.25.10" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/win32-x64@npm:0.25.10" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@fastify/ajv-compiler@npm:^4.0.0": + version: 4.0.2 + resolution: "@fastify/ajv-compiler@npm:4.0.2" + dependencies: + ajv: "npm:^8.12.0" + ajv-formats: "npm:^3.0.1" + fast-uri: "npm:^3.0.0" + checksum: 10c0/ca048db219cc958fb1b962f5dfc141f29e067ecb28a8dbe782bbef80ae3c920021468009cad613f0ed68db410890bb09c773ba2f33cb13e055b48c9c338bd8fa + languageName: node + linkType: hard + +"@fastify/error@npm:^4.0.0": + version: 4.2.0 + resolution: "@fastify/error@npm:4.2.0" + checksum: 10c0/8bdafe95b368a71dfc5644ef22e0a2412dfbb2f300cf4658fdbd9035c96d7c034c53fd7d38e1150437d9cf7a2d75e6bd05e458cf9ba5f2e47e527df8a5e0bd4e + languageName: node + linkType: hard + +"@fastify/fast-json-stringify-compiler@npm:^5.0.0": + version: 5.0.3 + resolution: "@fastify/fast-json-stringify-compiler@npm:5.0.3" + dependencies: + fast-json-stringify: "npm:^6.0.0" + checksum: 10c0/1f0e33c973fc228de44d997a8a1a43e883a580a8c971773bb9cb2375b0114694f81b47c52ac7e788eb6372d1f3dfc10be3176bad354a80d502d8b26a93dbc6c9 + languageName: node + linkType: hard + +"@fastify/forwarded@npm:^3.0.0": + version: 3.0.1 + resolution: "@fastify/forwarded@npm:3.0.1" + checksum: 10c0/fad9f7fb7ff4bf2f8ba782f79d46de190469817ed1bd55dc789927c381a38e63b53ab8c127d9444d703a449c5393529533bea365a25f6eb85a5ecbc78460be2a + languageName: node + linkType: hard + +"@fastify/merge-json-schemas@npm:^0.2.0": + version: 0.2.1 + resolution: "@fastify/merge-json-schemas@npm:0.2.1" + dependencies: + dequal: "npm:^2.0.3" + checksum: 10c0/dfa884a8f62d53f71de273fdcd0e501b213367767a7d8c522ae87ba6fb571b3eea85175d6e019036d7c0c5419be60305abe54899b9459f76ed5333358699efcb + languageName: node + linkType: hard + +"@fastify/proxy-addr@npm:^5.0.0": + version: 5.1.0 + resolution: "@fastify/proxy-addr@npm:5.1.0" + dependencies: + "@fastify/forwarded": "npm:^3.0.0" + ipaddr.js: "npm:^2.1.0" + checksum: 10c0/d9167e848086cb66a0ae8b008eb6a79e9ae0e17c3e8697a3a22b23152376e22843bea6642a2c07eba5460faa786ebda6157dfa6537ac7b733f758428cd51988b + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/agent@npm:3.0.0" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^10.0.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10c0/efe37b982f30740ee77696a80c196912c274ecd2cb243bc6ae7053a50c733ce0f6c09fda085145f33ecf453be19654acca74b69e81eaad4c90f00ccffe2f9271 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/fs@npm:4.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/c90935d5ce670c87b6b14fab04a965a3b8137e585f8b2a6257263bd7f97756dd736cb165bb470e5156a9e718ecd99413dccc54b1138c1a46d6ec7cf325982fe5 + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd + languageName: node + linkType: hard + +"@tsconfig/node24@npm:^24.0.1": + version: 24.0.1 + resolution: "@tsconfig/node24@npm:24.0.1" + checksum: 10c0/18e2ad5946bc6ddc9fbe37c4537439245da16eb8a5888641a1cdbc412a465ee321b5fa7c0ffc489c929d65c8bd0698ece9e8f3c52ae2596433ad0e866857bc83 + languageName: node + linkType: hard + +"@types/node@npm:^24.5.2": + version: 24.5.2 + resolution: "@types/node@npm:24.5.2" + dependencies: + undici-types: "npm:~7.12.0" + checksum: 10c0/96baaca6564d39c6f7f6eddd73ce41e2a7594ef37225cd52df3be36fad31712af8ae178387a72d0b80f2e2799e7fd30c014bc0ae9eb9f962d9079b691be00c48 + languageName: node + linkType: hard + +"abbrev@npm:^3.0.0": + version: 3.0.1 + resolution: "abbrev@npm:3.0.1" + checksum: 10c0/21ba8f574ea57a3106d6d35623f2c4a9111d9ee3e9a5be47baed46ec2457d2eac46e07a5c4a60186f88cb98abbe3e24f2d4cca70bc2b12f1692523e2209a9ccf + languageName: node + linkType: hard + +"abstract-logging@npm:^2.0.1": + version: 2.0.1 + resolution: "abstract-logging@npm:2.0.1" + checksum: 10c0/304879d9babcf6772260e5ddde632e6428e1f42f7a7a116d4689e97ad813a20e0ec2dd1e0a122f3617557f40091b9ca85735de4b48c17a2041268cb47b3f8ef1 + languageName: node + linkType: hard + +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe + languageName: node + linkType: hard + +"ajv-formats@npm:^3.0.1": + version: 3.0.1 + resolution: "ajv-formats@npm:3.0.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10c0/168d6bca1ea9f163b41c8147bae537e67bd963357a5488a1eaf3abe8baa8eec806d4e45f15b10767e6020679315c7e1e5e6803088dfb84efa2b4e9353b83dd0a + languageName: node + linkType: hard + +"ajv@npm:^8.0.0, ajv@npm:^8.12.0": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.2.2 + resolution: "ansi-regex@npm:6.2.2" + checksum: 10c0/05d4acb1d2f59ab2cf4b794339c7b168890d44dda4bf0ce01152a8da0213aca207802f930442ce8cd22d7a92f44907664aac6508904e75e038fa944d2601b30f + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.3 + resolution: "ansi-styles@npm:6.2.3" + checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868 + languageName: node + linkType: hard + +"atomic-sleep@npm:^1.0.0": + version: 1.0.0 + resolution: "atomic-sleep@npm:1.0.0" + checksum: 10c0/e329a6665512736a9bbb073e1761b4ec102f7926cce35037753146a9db9c8104f5044c1662e4a863576ce544fb8be27cd2be6bc8c1a40147d03f31eb1cfb6e8a + languageName: node + linkType: hard + +"avvio@npm:^9.0.0": + version: 9.1.0 + resolution: "avvio@npm:9.1.0" + dependencies: + "@fastify/error": "npm:^4.0.0" + fastq: "npm:^1.17.1" + checksum: 10c0/bdc294a7e8f38e1e21f9d338d97d7240025db54f1005fc419cfe0499a35edf2276ab1fe91135739faa3a9437358ec6912d5a56f23361b061880333cb4f1c7884 + languageName: node + linkType: hard + +"backend@workspace:packages/backend": + version: 0.0.0-use.local + resolution: "backend@workspace:packages/backend" + dependencies: + "@tsconfig/node24": "npm:^24.0.1" + "@types/node": "npm:^24.5.2" + fastify: "npm:^5.6.1" + pino-pretty: "npm:^13.1.1" + tsc: "npm:^2.0.4" + tsx: "npm:^4.20.6" + typescript: "npm:^5.9.2" + languageName: unknown + linkType: soft + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf + languageName: node + linkType: hard + +"cacache@npm:^19.0.1": + version: 19.0.1 + resolution: "cacache@npm:19.0.1" + dependencies: + "@npmcli/fs": "npm:^4.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^10.0.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^12.0.0" + tar: "npm:^7.4.3" + unique-filename: "npm:^4.0.0" + checksum: 10c0/01f2134e1bd7d3ab68be851df96c8d63b492b1853b67f2eecb2c37bb682d37cb70bb858a16f2f0554d3c0071be6dfe21456a1ff6fa4b7eed996570d6a25ffe9c + languageName: node + linkType: hard + +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + languageName: node + linkType: hard + +"colorette@npm:^2.0.7": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 10c0/e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 + languageName: node + linkType: hard + +"cookie@npm:^1.0.1": + version: 1.0.2 + resolution: "cookie@npm:1.0.2" + checksum: 10c0/fd25fe79e8fbcfcaf6aa61cd081c55d144eeeba755206c058682257cb38c4bd6795c6620de3f064c740695bb65b7949ebb1db7a95e4636efb8357a335ad3f54b + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.6": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 + languageName: node + linkType: hard + +"dateformat@npm:^4.6.3": + version: 4.6.3 + resolution: "dateformat@npm:4.6.3" + checksum: 10c0/e2023b905e8cfe2eb8444fb558562b524807a51cdfe712570f360f873271600b5c94aebffaf11efb285e2c072264a7cf243eadb68f3eba0f8cc85fb86cd25df6 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.4": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 + languageName: node + linkType: hard + +"deep-sea-stories@workspace:.": + version: 0.0.0-use.local + resolution: "deep-sea-stories@workspace:." + dependencies: + "@biomejs/biome": "npm:2.2.4" + languageName: unknown + linkType: soft + +"dequal@npm:^2.0.3": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 + languageName: node + linkType: hard + +"end-of-stream@npm:^1.1.0": + version: 1.4.5 + resolution: "end-of-stream@npm:1.4.5" + dependencies: + once: "npm:^1.4.0" + checksum: 10c0/b0701c92a10b89afb1cb45bf54a5292c6f008d744eb4382fa559d54775ff31617d1d7bc3ef617575f552e24fad2c7c1a1835948c66b3f3a4be0a6c1f35c883d8 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 + languageName: node + linkType: hard + +"esbuild@npm:~0.25.0": + version: 0.25.10 + resolution: "esbuild@npm:0.25.10" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.10" + "@esbuild/android-arm": "npm:0.25.10" + "@esbuild/android-arm64": "npm:0.25.10" + "@esbuild/android-x64": "npm:0.25.10" + "@esbuild/darwin-arm64": "npm:0.25.10" + "@esbuild/darwin-x64": "npm:0.25.10" + "@esbuild/freebsd-arm64": "npm:0.25.10" + "@esbuild/freebsd-x64": "npm:0.25.10" + "@esbuild/linux-arm": "npm:0.25.10" + "@esbuild/linux-arm64": "npm:0.25.10" + "@esbuild/linux-ia32": "npm:0.25.10" + "@esbuild/linux-loong64": "npm:0.25.10" + "@esbuild/linux-mips64el": "npm:0.25.10" + "@esbuild/linux-ppc64": "npm:0.25.10" + "@esbuild/linux-riscv64": "npm:0.25.10" + "@esbuild/linux-s390x": "npm:0.25.10" + "@esbuild/linux-x64": "npm:0.25.10" + "@esbuild/netbsd-arm64": "npm:0.25.10" + "@esbuild/netbsd-x64": "npm:0.25.10" + "@esbuild/openbsd-arm64": "npm:0.25.10" + "@esbuild/openbsd-x64": "npm:0.25.10" + "@esbuild/openharmony-arm64": "npm:0.25.10" + "@esbuild/sunos-x64": "npm:0.25.10" + "@esbuild/win32-arm64": "npm:0.25.10" + "@esbuild/win32-ia32": "npm:0.25.10" + "@esbuild/win32-x64": "npm:0.25.10" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/8ee5fdd43ed0d4092ce7f41577c63147f54049d5617763f0549c638bbe939e8adaa8f1a2728adb63417eb11df51956b7b0d8eb88ee08c27ad1d42960256158fa + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.2 + resolution: "exponential-backoff@npm:3.1.2" + checksum: 10c0/d9d3e1eafa21b78464297df91f1776f7fbaa3d5e3f7f0995648ca5b89c069d17055033817348d9f4a43d1c20b0eab84f75af6991751e839df53e4dfd6f22e844 + languageName: node + linkType: hard + +"fast-copy@npm:^3.0.2": + version: 3.0.2 + resolution: "fast-copy@npm:3.0.2" + checksum: 10c0/02e8b9fd03c8c024d2987760ce126456a0e17470850b51e11a1c3254eed6832e4733ded2d93316c82bc0b36aeb991ad1ff48d1ba95effe7add7c3ab8d8eb554a + languageName: node + linkType: hard + +"fast-decode-uri-component@npm:^1.0.1": + version: 1.0.1 + resolution: "fast-decode-uri-component@npm:1.0.1" + checksum: 10c0/039d50c2e99d64f999c3f2126c23fbf75a04a4117e218a149ca0b1d2aeb8c834b7b19d643b9d35d4eabce357189a6a94085f78cf48869e6e26cc59b036284bc3 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 + languageName: node + linkType: hard + +"fast-json-stringify@npm:^6.0.0": + version: 6.1.1 + resolution: "fast-json-stringify@npm:6.1.1" + dependencies: + "@fastify/merge-json-schemas": "npm:^0.2.0" + ajv: "npm:^8.12.0" + ajv-formats: "npm:^3.0.1" + fast-uri: "npm:^3.0.0" + json-schema-ref-resolver: "npm:^3.0.0" + rfdc: "npm:^1.2.0" + checksum: 10c0/15bf8e1e183c1631687d40907e4330b1ae764f790fbdeedf1f2b5d75fece457a445a1a99c0ea8e8113612928e4dae32bfccd7a7a7da57555d6be893471478a7a + languageName: node + linkType: hard + +"fast-querystring@npm:^1.0.0": + version: 1.1.2 + resolution: "fast-querystring@npm:1.1.2" + dependencies: + fast-decode-uri-component: "npm:^1.0.1" + checksum: 10c0/e8223273a9b199722f760f5a047a77ad049a14bd444b821502cb8218f5925e3a5fffb56b64389bca73ab2ac6f1aa7aebbe4e203e5f6e53ff5978de97c0fde4e3 + languageName: node + linkType: hard + +"fast-safe-stringify@npm:^2.1.1": + version: 2.1.1 + resolution: "fast-safe-stringify@npm:2.1.1" + checksum: 10c0/d90ec1c963394919828872f21edaa3ad6f1dddd288d2bd4e977027afff09f5db40f94e39536d4646f7e01761d704d72d51dce5af1b93717f3489ef808f5f4e4d + languageName: node + linkType: hard + +"fast-uri@npm:^3.0.0, fast-uri@npm:^3.0.1": + version: 3.1.0 + resolution: "fast-uri@npm:3.1.0" + checksum: 10c0/44364adca566f70f40d1e9b772c923138d47efeac2ae9732a872baafd77061f26b097ba2f68f0892885ad177becd065520412b8ffeec34b16c99433c5b9e2de7 + languageName: node + linkType: hard + +"fastify@npm:^5.6.1": + version: 5.6.1 + resolution: "fastify@npm:5.6.1" + dependencies: + "@fastify/ajv-compiler": "npm:^4.0.0" + "@fastify/error": "npm:^4.0.0" + "@fastify/fast-json-stringify-compiler": "npm:^5.0.0" + "@fastify/proxy-addr": "npm:^5.0.0" + abstract-logging: "npm:^2.0.1" + avvio: "npm:^9.0.0" + fast-json-stringify: "npm:^6.0.0" + find-my-way: "npm:^9.0.0" + light-my-request: "npm:^6.0.0" + pino: "npm:^9.0.0" + process-warning: "npm:^5.0.0" + rfdc: "npm:^1.3.1" + secure-json-parse: "npm:^4.0.0" + semver: "npm:^7.6.0" + toad-cache: "npm:^3.7.0" + checksum: 10c0/ded119174c175d22f78ca524d9a466cf70bc50468b4efcb6f520bc027f33670aed7d95b3946ecc9de43cad810dceb6c9f7429e63534e0a8bfd80f5e23337a979 + languageName: node + linkType: hard + +"fastq@npm:^1.17.1": + version: 1.19.1 + resolution: "fastq@npm:1.19.1" + dependencies: + reusify: "npm:^1.0.4" + checksum: 10c0/ebc6e50ac7048daaeb8e64522a1ea7a26e92b3cee5cd1c7f2316cdca81ba543aa40a136b53891446ea5c3a67ec215fbaca87ad405f102dd97012f62916905630 + languageName: node + linkType: hard + +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + +"find-my-way@npm:^9.0.0": + version: 9.3.0 + resolution: "find-my-way@npm:9.3.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-querystring: "npm:^1.0.0" + safe-regex2: "npm:^5.0.0" + checksum: 10c0/f221bc0c70b2c2a6f9282fd3e0ac1911fcbb68ac718da043ddcefdec3b9d884a54d6ef1bf92e1b2ff83400e50f3c22141206a8ea3308bf0e9e37fd177843425d + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.3.1 + resolution: "foreground-child@npm:3.3.1" + dependencies: + cross-spawn: "npm:^7.0.6" + signal-exit: "npm:^4.0.1" + checksum: 10c0/8986e4af2430896e65bc2788d6679067294d6aee9545daefc84923a0a4b399ad9c7a3ea7bd8c0b2b80fdf4a92de4c69df3f628233ff3224260e9c1541a9e9ed3 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 + languageName: node + linkType: hard + +"fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"get-tsconfig@npm:^4.7.5": + version: 4.10.1 + resolution: "get-tsconfig@npm:4.10.1" + dependencies: + resolve-pkg-maps: "npm:^1.0.0" + checksum: 10c0/7f8e3dabc6a49b747920a800fb88e1952fef871cdf51b79e98db48275a5de6cdaf499c55ee67df5fa6fe7ce65f0063e26de0f2e53049b408c585aa74d39ffa21 + languageName: node + linkType: hard + +"glob@npm:^10.2.2": + version: 10.4.5 + resolution: "glob@npm:10.4.5" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"help-me@npm:^5.0.0": + version: 5.0.0 + resolution: "help-me@npm:5.0.0" + checksum: 10c0/054c0e2e9ae2231c85ab5e04f75109b9d068ffcc54e58fb22079822a5ace8ff3d02c66fd45379c902ad5ab825e5d2e1451fcc2f7eab1eb49e7d488133ba4cacb + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.2.0 + resolution: "http-cache-semantics@npm:4.2.0" + checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:4" + checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 + languageName: node + linkType: hard + +"ip-address@npm:^10.0.1": + version: 10.0.1 + resolution: "ip-address@npm:10.0.1" + checksum: 10c0/1634d79dae18394004775cb6d699dc46b7c23df6d2083164025a2b15240c1164fccde53d0e08bd5ee4fc53913d033ab6b5e395a809ad4b956a940c446e948843 + languageName: node + linkType: hard + +"ipaddr.js@npm:^2.1.0": + version: 2.2.0 + resolution: "ipaddr.js@npm:2.2.0" + checksum: 10c0/e4ee875dc1bd92ac9d27e06cfd87cdb63ca786ff9fd7718f1d4f7a8ef27db6e5d516128f52d2c560408cbb75796ac2f83ead669e73507c86282d45f84c5abbb6 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + languageName: node + linkType: hard + +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 + languageName: node + linkType: hard + +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 + languageName: node + linkType: hard + +"joycon@npm:^3.1.1": + version: 3.1.1 + resolution: "joycon@npm:3.1.1" + checksum: 10c0/131fb1e98c9065d067fd49b6e685487ac4ad4d254191d7aa2c9e3b90f4e9ca70430c43cad001602bdbdabcf58717d3b5c5b7461c1bd8e39478c8de706b3fe6ae + languageName: node + linkType: hard + +"json-schema-ref-resolver@npm:^3.0.0": + version: 3.0.0 + resolution: "json-schema-ref-resolver@npm:3.0.0" + dependencies: + dequal: "npm:^2.0.3" + checksum: 10c0/0b6f4b66951ac0f6864949c08317cf0b7f7ae94e8da0b94e40df3561dc1a0b77a69b669d60aa1511b06aa18469203886eb2e89fd6bb3dcf0be46c329d69b0115 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 + languageName: node + linkType: hard + +"light-my-request@npm:^6.0.0": + version: 6.6.0 + resolution: "light-my-request@npm:6.6.0" + dependencies: + cookie: "npm:^1.0.1" + process-warning: "npm:^4.0.0" + set-cookie-parser: "npm:^2.6.0" + checksum: 10c0/1440853cd3822ab83fbb1be4456099082dec8e9e3a4ea35c9d8d7d17a7ab98c83ad0a4c39a73a8c2b31b9ca70c57506e5b7a929495c149463ca0daca0d90dc6f + languageName: node + linkType: hard + +"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb + languageName: node + linkType: hard + +"make-fetch-happen@npm:^14.0.3": + version: 14.0.3 + resolution: "make-fetch-happen@npm:14.0.3" + dependencies: + "@npmcli/agent": "npm:^3.0.0" + cacache: "npm:^19.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^4.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^5.0.0" + promise-retry: "npm:^2.0.1" + ssri: "npm:^12.0.0" + checksum: 10c0/c40efb5e5296e7feb8e37155bde8eb70bc57d731b1f7d90e35a092fde403d7697c56fb49334d92d330d6f1ca29a98142036d6480a12681133a0a1453164cb2f0 + languageName: node + linkType: hard + +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + languageName: node + linkType: hard + +"minimist@npm:^1.2.6": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e + languageName: node + linkType: hard + +"minipass-fetch@npm:^4.0.0": + version: 4.0.1 + resolution: "minipass-fetch@npm:4.0.1" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^3.0.1" + dependenciesMeta: + encoding: + optional: true + checksum: 10c0/a3147b2efe8e078c9bf9d024a0059339c5a09c5b1dded6900a219c218cc8b1b78510b62dae556b507304af226b18c3f1aeb1d48660283602d5b6586c399eed5c + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 + languageName: node + linkType: hard + +"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec + languageName: node + linkType: hard + +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 11.4.2 + resolution: "node-gyp@npm:11.4.2" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^14.0.3" + nopt: "npm:^8.0.0" + proc-log: "npm:^5.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.4.3" + tinyglobby: "npm:^0.2.12" + which: "npm:^5.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/0bfd3e96770ed70f07798d881dd37b4267708966d868a0e585986baac487d9cf5831285579fd629a83dc4e434f53e6416ce301097f2ee464cb74d377e4d8bdbe + languageName: node + linkType: hard + +"nopt@npm:^8.0.0": + version: 8.1.0 + resolution: "nopt@npm:8.1.0" + dependencies: + abbrev: "npm:^3.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/62e9ea70c7a3eb91d162d2c706b6606c041e4e7b547cbbb48f8b3695af457dd6479904d7ace600856bf923dd8d1ed0696f06195c8c20f02ac87c1da0e1d315ef + languageName: node + linkType: hard + +"on-exit-leak-free@npm:^2.1.0": + version: 2.1.2 + resolution: "on-exit-leak-free@npm:2.1.2" + checksum: 10c0/faea2e1c9d696ecee919026c32be8d6a633a7ac1240b3b87e944a380e8a11dc9c95c4a1f8fb0568de7ab8db3823e790f12bda45296b1d111e341aad3922a0570 + languageName: node + linkType: hard + +"once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 + languageName: node + linkType: hard + +"p-map@npm:^7.0.2": + version: 7.0.3 + resolution: "p-map@npm:7.0.3" + checksum: 10c0/46091610da2b38ce47bcd1d8b4835a6fa4e832848a6682cf1652bc93915770f4617afc844c10a77d1b3e56d2472bb2d5622353fa3ead01a7f42b04fc8e744a5c + languageName: node + linkType: hard + +"package-json-from-dist@npm:^1.0.0": + version: 1.0.1 + resolution: "package-json-from-dist@npm:1.0.1" + checksum: 10c0/62ba2785eb655fec084a257af34dbe24292ab74516d6aecef97ef72d4897310bc6898f6c85b5cd22770eaa1ce60d55a0230e150fb6a966e3ecd6c511e23d164b + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d + languageName: node + linkType: hard + +"picomatch@npm:^4.0.3": + version: 4.0.3 + resolution: "picomatch@npm:4.0.3" + checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2 + languageName: node + linkType: hard + +"pino-abstract-transport@npm:^2.0.0": + version: 2.0.0 + resolution: "pino-abstract-transport@npm:2.0.0" + dependencies: + split2: "npm:^4.0.0" + checksum: 10c0/02c05b8f2ffce0d7c774c8e588f61e8b77de8ccb5f8125afd4a7325c9ea0e6af7fb78168999657712ae843e4462bb70ac550dfd6284f930ee57f17f486f25a9f + languageName: node + linkType: hard + +"pino-pretty@npm:^13.1.1": + version: 13.1.1 + resolution: "pino-pretty@npm:13.1.1" + dependencies: + colorette: "npm:^2.0.7" + dateformat: "npm:^4.6.3" + fast-copy: "npm:^3.0.2" + fast-safe-stringify: "npm:^2.1.1" + help-me: "npm:^5.0.0" + joycon: "npm:^3.1.1" + minimist: "npm:^1.2.6" + on-exit-leak-free: "npm:^2.1.0" + pino-abstract-transport: "npm:^2.0.0" + pump: "npm:^3.0.0" + secure-json-parse: "npm:^4.0.0" + sonic-boom: "npm:^4.0.1" + strip-json-comments: "npm:^5.0.2" + bin: + pino-pretty: bin.js + checksum: 10c0/845c07afd3d73cb96ad2049cfa7fca12b8280a51e30d6db8b490857690637556bb8e7f05b2fa640b3e4a7edd9b1369110042d670fda743ef98fe3be29876c8c7 + languageName: node + linkType: hard + +"pino-std-serializers@npm:^7.0.0": + version: 7.0.0 + resolution: "pino-std-serializers@npm:7.0.0" + checksum: 10c0/73e694d542e8de94445a03a98396cf383306de41fd75ecc07085d57ed7a57896198508a0dec6eefad8d701044af21eb27253ccc352586a03cf0d4a0bd25b4133 + languageName: node + linkType: hard + +"pino@npm:^9.0.0": + version: 9.12.0 + resolution: "pino@npm:9.12.0" + dependencies: + atomic-sleep: "npm:^1.0.0" + on-exit-leak-free: "npm:^2.1.0" + pino-abstract-transport: "npm:^2.0.0" + pino-std-serializers: "npm:^7.0.0" + process-warning: "npm:^5.0.0" + quick-format-unescaped: "npm:^4.0.3" + real-require: "npm:^0.2.0" + safe-stable-stringify: "npm:^2.3.1" + slow-redact: "npm:^0.3.0" + sonic-boom: "npm:^4.0.1" + thread-stream: "npm:^3.0.0" + bin: + pino: bin.js + checksum: 10c0/5cfe093e972a8471a90f7f380c01379eed3fd937038acb97d1de9180f097c044855ca89a2e70baa699aec3e8dcaec037d03e2c90dde235102a3e17b40f54cc1f + languageName: node + linkType: hard + +"proc-log@npm:^5.0.0": + version: 5.0.0 + resolution: "proc-log@npm:5.0.0" + checksum: 10c0/bbe5edb944b0ad63387a1d5b1911ae93e05ce8d0f60de1035b218cdcceedfe39dbd2c697853355b70f1a090f8f58fe90da487c85216bf9671f9499d1a897e9e3 + languageName: node + linkType: hard + +"process-warning@npm:^4.0.0": + version: 4.0.1 + resolution: "process-warning@npm:4.0.1" + checksum: 10c0/577a268b9fd5c3d9f6dbb4348220099391d830905642845d591e7ee8b1e45043d98b7b9826a3c1379bdd1686cdfe0f6cf349cb812affc5853b662e6a9896579e + languageName: node + linkType: hard + +"process-warning@npm:^5.0.0": + version: 5.0.0 + resolution: "process-warning@npm:5.0.0" + checksum: 10c0/941f48863d368ec161e0b5890ba0c6af94170078f3d6b5e915c19b36fb59edb0dc2f8e834d25e0d375a8bf368a49d490f080508842168832b93489d17843ec29 + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 + languageName: node + linkType: hard + +"pump@npm:^3.0.0": + version: 3.0.3 + resolution: "pump@npm:3.0.3" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10c0/ada5cdf1d813065bbc99aa2c393b8f6beee73b5de2890a8754c9f488d7323ffd2ca5f5a0943b48934e3fcbd97637d0337369c3c631aeb9614915db629f1c75c9 + languageName: node + linkType: hard + +"quick-format-unescaped@npm:^4.0.3": + version: 4.0.4 + resolution: "quick-format-unescaped@npm:4.0.4" + checksum: 10c0/fe5acc6f775b172ca5b4373df26f7e4fd347975578199e7d74b2ae4077f0af05baa27d231de1e80e8f72d88275ccc6028568a7a8c9ee5e7368ace0e18eff93a4 + languageName: node + linkType: hard + +"real-require@npm:^0.2.0": + version: 0.2.0 + resolution: "real-require@npm:0.2.0" + checksum: 10c0/23eea5623642f0477412ef8b91acd3969015a1501ed34992ada0e3af521d3c865bb2fe4cdbfec5fe4b505f6d1ef6a03e5c3652520837a8c3b53decff7e74b6a0 + languageName: node + linkType: hard + +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 + languageName: node + linkType: hard + +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab + languageName: node + linkType: hard + +"ret@npm:~0.5.0": + version: 0.5.0 + resolution: "ret@npm:0.5.0" + checksum: 10c0/220868b194f87bf1998e32e409086eec6b39e860c052bf267f8ad4d0131706a9773d45fd3f91acfb1a7c928fce002b694ab86fdba90bc8d4b8df68fa8645c5cc + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.1.0 + resolution: "reusify@npm:1.1.0" + checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa + languageName: node + linkType: hard + +"rfdc@npm:^1.2.0, rfdc@npm:^1.3.1": + version: 1.4.1 + resolution: "rfdc@npm:1.4.1" + checksum: 10c0/4614e4292356cafade0b6031527eea9bc90f2372a22c012313be1dcc69a3b90c7338158b414539be863fa95bfcb2ddcd0587be696841af4e6679d85e62c060c7 + languageName: node + linkType: hard + +"safe-regex2@npm:^5.0.0": + version: 5.0.0 + resolution: "safe-regex2@npm:5.0.0" + dependencies: + ret: "npm:~0.5.0" + checksum: 10c0/83d5b1b60a5a97cb71a6e615518ec4a47761b3600aba389089be59a417498185250db2368080afc2f5e91237d68809c6c634b97a2e1cc8bd56a4c7eef2eeb6cf + languageName: node + linkType: hard + +"safe-stable-stringify@npm:^2.3.1": + version: 2.5.0 + resolution: "safe-stable-stringify@npm:2.5.0" + checksum: 10c0/baea14971858cadd65df23894a40588ed791769db21bafb7fd7608397dbdce9c5aac60748abae9995e0fc37e15f2061980501e012cd48859740796bea2987f49 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + languageName: node + linkType: hard + +"secure-json-parse@npm:^4.0.0": + version: 4.0.0 + resolution: "secure-json-parse@npm:4.0.0" + checksum: 10c0/1a298cf00e1de91e833cee5eb406d6e77fb2f7eca9bef3902047d49e7f5d3e6c21b5de61ff73466c831e716430bfe87d732a6e645a7dabb5f1e8a8e4d3e15eb4 + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.6.0": + version: 7.7.2 + resolution: "semver@npm:7.7.2" + bin: + semver: bin/semver.js + checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea + languageName: node + linkType: hard + +"set-cookie-parser@npm:^2.6.0": + version: 2.7.1 + resolution: "set-cookie-parser@npm:2.7.1" + checksum: 10c0/060c198c4c92547ac15988256f445eae523f57f2ceefeccf52d30d75dedf6bff22b9c26f756bd44e8e560d44ff4ab2130b178bd2e52ef5571bf7be3bd7632d9a + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 + languageName: node + linkType: hard + +"slow-redact@npm:^0.3.0": + version: 0.3.0 + resolution: "slow-redact@npm:0.3.0" + checksum: 10c0/bb2f77830f64fb01079849e0c6433c15e782b88cccb82d4b0d62ce216307cf514ea3f92e9b2c6ae1b1d613ac7743305d5f0324e94c9dc8e41908939456248f9a + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.7 + resolution: "socks@npm:2.8.7" + dependencies: + ip-address: "npm:^10.0.1" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 + languageName: node + linkType: hard + +"sonic-boom@npm:^4.0.1": + version: 4.2.0 + resolution: "sonic-boom@npm:4.2.0" + dependencies: + atomic-sleep: "npm:^1.0.0" + checksum: 10c0/ae897e6c2cd6d3cb7cdcf608bc182393b19c61c9413a85ce33ffd25891485589f39bece0db1de24381d0a38fc03d08c9862ded0c60f184f1b852f51f97af9684 + languageName: node + linkType: hard + +"split2@npm:^4.0.0": + version: 4.2.0 + resolution: "split2@npm:4.2.0" + checksum: 10c0/b292beb8ce9215f8c642bb68be6249c5a4c7f332fc8ecadae7be5cbdf1ea95addc95f0459ef2e7ad9d45fd1064698a097e4eb211c83e772b49bc0ee423e91534 + languageName: node + linkType: hard + +"ssri@npm:^12.0.0": + version: 12.0.0 + resolution: "ssri@npm:12.0.0" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/caddd5f544b2006e88fa6b0124d8d7b28208b83c72d7672d5ade44d794525d23b540f3396108c4eb9280dcb7c01f0bef50682f5b4b2c34291f7c5e211fd1417d + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b + languageName: node + linkType: hard + +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca + languageName: node + linkType: hard + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: "npm:^5.0.1" + checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.2 + resolution: "strip-ansi@npm:7.1.2" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 10c0/0d6d7a023de33368fd042aab0bf48f4f4077abdfd60e5393e73c7c411e85e1b3a83507c11af2e656188511475776215df9ca589b4da2295c9455cc399ce1858b + languageName: node + linkType: hard + +"strip-json-comments@npm:^5.0.2": + version: 5.0.3 + resolution: "strip-json-comments@npm:5.0.3" + checksum: 10c0/daaf20b29f69fb51112698f4a9a662490dbb78d5baf6127c75a0a83c2ac6c078a8c0f74b389ad5e0519d6fc359c4a57cb9971b1ae201aef62ce45a13247791e0 + languageName: node + linkType: hard + +"tar@npm:^7.4.3": + version: 7.5.1 + resolution: "tar@npm:7.5.1" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/0dad0596a61586180981133b20c32cfd93c5863c5b7140d646714e6ea8ec84583b879e5dc3928a4d683be6e6109ad7ea3de1cf71986d5194f81b3a016c8858c9 + languageName: node + linkType: hard + +"thread-stream@npm:^3.0.0": + version: 3.1.0 + resolution: "thread-stream@npm:3.1.0" + dependencies: + real-require: "npm:^0.2.0" + checksum: 10c0/c36118379940b77a6ef3e6f4d5dd31e97b8210c3f7b9a54eb8fe6358ab173f6d0acfaf69b9c3db024b948c0c5fd2a7df93e2e49151af02076b35ada3205ec9a6 + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 + languageName: node + linkType: hard + +"toad-cache@npm:^3.7.0": + version: 3.7.0 + resolution: "toad-cache@npm:3.7.0" + checksum: 10c0/7dae2782ee20b22c9798bb8b71dec7ec6a0091021d2ea9dd6e8afccab6b65b358fdba49a02209fac574499702e2c000660721516c87c2538d1b2c0ba03e8c0c3 + languageName: node + linkType: hard + +"tsc@npm:^2.0.4": + version: 2.0.4 + resolution: "tsc@npm:2.0.4" + bin: + tsc: bin/tsc + checksum: 10c0/4651d344891d995e62ab7ca64ce0a8597bbdc2d392886c9956d15caab4dc9bfe86e759d3385b3f97c49fb5294194a161d6812673e3f51e46357c82482f32c3ab + languageName: node + linkType: hard + +"tsx@npm:^4.20.6": + version: 4.20.6 + resolution: "tsx@npm:4.20.6" + dependencies: + esbuild: "npm:~0.25.0" + fsevents: "npm:~2.3.3" + get-tsconfig: "npm:^4.7.5" + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: 10c0/07757a9bf62c271e0a00869b2008c5f2d6e648766536e4faf27d9d8027b7cde1ac8e4871f4bb570c99388bcee0018e6869dad98c07df809b8052f9c549cd216f + languageName: node + linkType: hard + +"typescript@npm:^5.9.2": + version: 5.9.2 + resolution: "typescript@npm:5.9.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^5.9.2#optional!builtin": + version: 5.9.2 + resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e + languageName: node + linkType: hard + +"undici-types@npm:~7.12.0": + version: 7.12.0 + resolution: "undici-types@npm:7.12.0" + checksum: 10c0/326e455bbc0026db1d6b81c76a1cf10c63f7e2f9821db2e24fdc258f482814e5bfa8481f8910d07c68e305937c5c049610fdc441c5e8b7bb0daca7154fb8a306 + languageName: node + linkType: hard + +"unique-filename@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-filename@npm:4.0.0" + dependencies: + unique-slug: "npm:^5.0.0" + checksum: 10c0/38ae681cceb1408ea0587b6b01e29b00eee3c84baee1e41fd5c16b9ed443b80fba90c40e0ba69627e30855570a34ba8b06702d4a35035d4b5e198bf5a64c9ddc + languageName: node + linkType: hard + +"unique-slug@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-slug@npm:5.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10c0/d324c5a44887bd7e105ce800fcf7533d43f29c48757ac410afd42975de82cc38ea2035c0483f4de82d186691bf3208ef35c644f73aa2b1b20b8e651be5afd293 + languageName: node + linkType: hard + +"web@workspace:packages/web": + version: 0.0.0-use.local + resolution: "web@workspace:packages/web" + languageName: unknown + linkType: soft + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + languageName: node + linkType: hard + +"which@npm:^5.0.0": + version: 5.0.0 + resolution: "which@npm:5.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10c0/e556e4cd8b7dbf5df52408c9a9dd5ac6518c8c5267c8953f5b0564073c66ed5bf9503b14d876d0e9c7844d4db9725fb0dcf45d6e911e17e26ab363dc3965ae7b + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a + languageName: node + linkType: hard + +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard From d4744528ac41994071c008d0c2e5d5b0b74513dd Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:22:20 +0200 Subject: [PATCH 02/65] Add CI --- .github/workflows/CI.yaml | 35 +++++++++++++++++++++++++++++++++++ deep-sea-stories/package.json | 28 ++++++++++++++-------------- 2 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/CI.yaml diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml new file mode 100644 index 0000000..7def1d8 --- /dev/null +++ b/.github/workflows/CI.yaml @@ -0,0 +1,35 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +jobs: + deep-sea-stories: + runs-on: ubuntu-latest + defaults: + run: + working-directory: deep-sea-stories + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Enable corepack + run: corepack enable + + - name: Set up Node.js + uses: actions/setup-node@v5 + with: + node-version: 24 + cache: yarn + + - name: Install dependencies + run: yarn --immutable + + - name: Run format + run: yarn format + + - name: Run lint + run: yarn lint diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index 935b9a3..935abc9 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -1,16 +1,16 @@ { - "name": "deep-sea-stories", - "packageManager": "yarn@4.9.2", - "private": true, - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@biomejs/biome": "2.2.4" - }, - "scripts": { - "format": "biome format --write", - "lint": "biome lint --write", - "check": "biome check --write" - } + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4" + }, + "scripts": { + "format": "biome format", + "lint": "biome lint", + "check": "biome check --write" + } } From 0a39589f444e229f7763b320310641d9e0d7706f Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:48:58 +0200 Subject: [PATCH 03/65] Add yarnrc --- deep-sea-stories/.yarnrc.yml | 1 + .../packages/backend/package.json | 39 +++++++++---------- deep-sea-stories/packages/web/package.json | 5 +-- 3 files changed, 22 insertions(+), 23 deletions(-) create mode 100644 deep-sea-stories/.yarnrc.yml diff --git a/deep-sea-stories/.yarnrc.yml b/deep-sea-stories/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/deep-sea-stories/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 997d86c..c3a955f 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -1,22 +1,21 @@ { - "name": "backend", - "packageManager": "yarn@4.9.2", - "private": true, - "main": "./src/main.ts", - "type": "module", - "dependencies": { - "fastify": "^5.6.1", - "pino-pretty": "^13.1.1" - }, - "devDependencies": { - "@tsconfig/node24": "^24.0.1", - "@types/node": "^24.5.2", - "tsc": "^2.0.4", - "tsx": "^4.20.6", - "typescript": "^5.9.2" - }, - "scripts": { - "build": "tsc -p tsconfig.json", - "start": "tsx watch src/main.ts" - } + "name": "backend", + "private": true, + "main": "./src/main.ts", + "type": "module", + "dependencies": { + "fastify": "^5.6.1", + "pino-pretty": "^13.1.1" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.1", + "@types/node": "^24.5.2", + "tsc": "^2.0.4", + "tsx": "^4.20.6", + "typescript": "^5.9.2" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "tsx watch src/main.ts" + } } diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 9f8d766..41b70d4 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -1,5 +1,4 @@ { - "name": "web", - "packageManager": "yarn@4.9.2", - "private": true + "name": "web", + "private": true } From 4b1fb40e96fc1b8e67a468105e4511d00ded1bd2 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:52:49 +0200 Subject: [PATCH 04/65] Update CI --- .github/workflows/CI.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 7def1d8..1e7d85e 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -24,6 +24,7 @@ jobs: with: node-version: 24 cache: yarn + cache-dependency-path: ./deep-sea-stories/yarn.lock - name: Install dependencies run: yarn --immutable From 66b9d62ad31ebefed3985604a0946fa39623a0e5 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:54:10 +0200 Subject: [PATCH 05/65] Format --- deep-sea-stories/biome.json | 66 +++++++++---------- deep-sea-stories/package.json | 28 ++++---- .../packages/backend/package.json | 38 +++++------ deep-sea-stories/packages/web/package.json | 4 +- 4 files changed, 68 insertions(+), 68 deletions(-) diff --git a/deep-sea-stories/biome.json b/deep-sea-stories/biome.json index 8f7d1f8..c5c9476 100644 --- a/deep-sea-stories/biome.json +++ b/deep-sea-stories/biome.json @@ -1,35 +1,35 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", - "vcs": { - "enabled": false, - "clientKind": "git", - "useIgnoreFile": false - }, - "files": { - "includes": ["**", "!**/dist"], - "ignoreUnknown": false - }, - "formatter": { - "enabled": true, - "indentStyle": "tab" - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "single" - } - }, - "assist": { - "enabled": true, - "actions": { - "source": { - "organizeImports": "on" - } - } - } + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "includes": ["**", "!**/dist"], + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } } diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index 935abc9..33cea52 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -1,16 +1,16 @@ { - "name": "deep-sea-stories", - "packageManager": "yarn@4.9.2", - "private": true, - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@biomejs/biome": "2.2.4" - }, - "scripts": { - "format": "biome format", - "lint": "biome lint", - "check": "biome check --write" - } + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4" + }, + "scripts": { + "format": "biome format", + "lint": "biome lint", + "check": "biome check --write" + } } diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index c3a955f..54e6cde 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -1,21 +1,21 @@ { - "name": "backend", - "private": true, - "main": "./src/main.ts", - "type": "module", - "dependencies": { - "fastify": "^5.6.1", - "pino-pretty": "^13.1.1" - }, - "devDependencies": { - "@tsconfig/node24": "^24.0.1", - "@types/node": "^24.5.2", - "tsc": "^2.0.4", - "tsx": "^4.20.6", - "typescript": "^5.9.2" - }, - "scripts": { - "build": "tsc -p tsconfig.json", - "start": "tsx watch src/main.ts" - } + "name": "backend", + "private": true, + "main": "./src/main.ts", + "type": "module", + "dependencies": { + "fastify": "^5.6.1", + "pino-pretty": "^13.1.1" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.1", + "@types/node": "^24.5.2", + "tsc": "^2.0.4", + "tsx": "^4.20.6", + "typescript": "^5.9.2" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "tsx watch src/main.ts" + } } diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 41b70d4..1dfb7e3 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -1,4 +1,4 @@ { - "name": "web", - "private": true + "name": "web", + "private": true } From 79c6196a9579d9b638471cc4dda39dca8703ba61 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:02:40 +0200 Subject: [PATCH 06/65] Add engines to package.json --- deep-sea-stories/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index 33cea52..4bd516e 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -12,5 +12,8 @@ "format": "biome format", "lint": "biome lint", "check": "biome check --write" + }, + "engines": { + "node": ">= 24.0.0" } } From 0e4bca19e80b23e753060140c68ce59ac63c213c Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:03:42 +0200 Subject: [PATCH 07/65] Use node version file --- .github/workflows/CI.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 1e7d85e..19dec58 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -22,7 +22,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v5 with: - node-version: 24 + node-version-file: ./deep-sea-stories/package.json cache: yarn cache-dependency-path: ./deep-sea-stories/yarn.lock From 4fa231bf083d08af337c63e47fe8eef6c3e86b5c Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:40:19 +0200 Subject: [PATCH 08/65] Move typescript to root package.json --- .github/workflows/CI.yaml | 2 +- deep-sea-stories/package.json | 37 ++++++++++--------- .../packages/backend/package.json | 37 +++++++++---------- deep-sea-stories/yarn.lock | 12 +----- 4 files changed, 40 insertions(+), 48 deletions(-) diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 19dec58..d18c98e 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -30,7 +30,7 @@ jobs: run: yarn --immutable - name: Run format - run: yarn format + run: yarn format:check - name: Run lint run: yarn lint diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index 4bd516e..9c464ea 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -1,19 +1,22 @@ { - "name": "deep-sea-stories", - "packageManager": "yarn@4.9.2", - "private": true, - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@biomejs/biome": "2.2.4" - }, - "scripts": { - "format": "biome format", - "lint": "biome lint", - "check": "biome check --write" - }, - "engines": { - "node": ">= 24.0.0" - } + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4", + "typescript": "^5.9.2" + }, + "scripts": { + "format": "biome format --write", + "format:check": "biome format", + "lint": "biome lint", + "check": "biome check --write", + "typecheck": "yarn workspaces foreach -A -p run typecheck" + }, + "engines": { + "node": ">= 24.0.0" + } } diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 54e6cde..4cccc24 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -1,21 +1,20 @@ { - "name": "backend", - "private": true, - "main": "./src/main.ts", - "type": "module", - "dependencies": { - "fastify": "^5.6.1", - "pino-pretty": "^13.1.1" - }, - "devDependencies": { - "@tsconfig/node24": "^24.0.1", - "@types/node": "^24.5.2", - "tsc": "^2.0.4", - "tsx": "^4.20.6", - "typescript": "^5.9.2" - }, - "scripts": { - "build": "tsc -p tsconfig.json", - "start": "tsx watch src/main.ts" - } + "name": "backend", + "private": true, + "main": "./src/main.ts", + "type": "module", + "dependencies": { + "fastify": "^5.6.1", + "pino-pretty": "^13.1.1" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.1", + "@types/node": "^24.5.2", + "tsx": "^4.20.6" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "tsx watch src/main.ts", + "typecheck": "tsc --noEmit" + } } diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 4f58036..f16bfd7 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -501,9 +501,7 @@ __metadata: "@types/node": "npm:^24.5.2" fastify: "npm:^5.6.1" pino-pretty: "npm:^13.1.1" - tsc: "npm:^2.0.4" tsx: "npm:^4.20.6" - typescript: "npm:^5.9.2" languageName: unknown linkType: soft @@ -615,6 +613,7 @@ __metadata: resolution: "deep-sea-stories@workspace:." dependencies: "@biomejs/biome": "npm:2.2.4" + typescript: "npm:^5.9.2" languageName: unknown linkType: soft @@ -1678,15 +1677,6 @@ __metadata: languageName: node linkType: hard -"tsc@npm:^2.0.4": - version: 2.0.4 - resolution: "tsc@npm:2.0.4" - bin: - tsc: bin/tsc - checksum: 10c0/4651d344891d995e62ab7ca64ce0a8597bbdc2d392886c9956d15caab4dc9bfe86e759d3385b3f97c49fb5294194a161d6812673e3f51e46357c82482f32c3ab - languageName: node - linkType: hard - "tsx@npm:^4.20.6": version: 4.20.6 resolution: "tsx@npm:4.20.6" From a8a284a3ece1651bb965a9b227f814394ccf0520 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 30 Sep 2025 14:34:17 +0200 Subject: [PATCH 09/65] Some backend boilerplate --- deep-sea-stories/package.json | 40 +-- .../packages/backend/.env.example | 2 + .../packages/backend/package.json | 41 +-- .../packages/backend/src/config.ts | 25 ++ .../packages/backend/src/controllers/rooms.ts | 9 + deep-sea-stories/packages/backend/src/main.ts | 46 ++- .../packages/backend/src/plugins/fishjam.ts | 29 ++ .../packages/backend/src/routes/index.ts | 6 + .../packages/backend/src/routes/rooms.ts | 38 +++ .../packages/backend/src/schemas.ts | 10 + .../packages/backend/tsconfig.json | 3 +- deep-sea-stories/yarn.lock | 295 +++++++++++++++++- 12 files changed, 478 insertions(+), 66 deletions(-) create mode 100644 deep-sea-stories/packages/backend/.env.example create mode 100644 deep-sea-stories/packages/backend/src/config.ts create mode 100644 deep-sea-stories/packages/backend/src/controllers/rooms.ts create mode 100644 deep-sea-stories/packages/backend/src/plugins/fishjam.ts create mode 100644 deep-sea-stories/packages/backend/src/routes/index.ts create mode 100644 deep-sea-stories/packages/backend/src/routes/rooms.ts create mode 100644 deep-sea-stories/packages/backend/src/schemas.ts diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index 9c464ea..ba030be 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -1,22 +1,22 @@ { - "name": "deep-sea-stories", - "packageManager": "yarn@4.9.2", - "private": true, - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@biomejs/biome": "2.2.4", - "typescript": "^5.9.2" - }, - "scripts": { - "format": "biome format --write", - "format:check": "biome format", - "lint": "biome lint", - "check": "biome check --write", - "typecheck": "yarn workspaces foreach -A -p run typecheck" - }, - "engines": { - "node": ">= 24.0.0" - } + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4", + "typescript": "^5.9.2" + }, + "scripts": { + "format": "biome format --write", + "format:check": "biome format", + "lint": "biome lint", + "check": "biome check --write", + "typecheck": "yarn workspaces foreach -A -p run typecheck" + }, + "engines": { + "node": ">= 24.0.0" + } } diff --git a/deep-sea-stories/packages/backend/.env.example b/deep-sea-stories/packages/backend/.env.example new file mode 100644 index 0000000..3360907 --- /dev/null +++ b/deep-sea-stories/packages/backend/.env.example @@ -0,0 +1,2 @@ +FISHJAM_ID="your-fishjam-id" +FISHJAM_MANAGEMENT_TOKEN="your-management-token" diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 4cccc24..19c4ddb 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -1,20 +1,25 @@ { - "name": "backend", - "private": true, - "main": "./src/main.ts", - "type": "module", - "dependencies": { - "fastify": "^5.6.1", - "pino-pretty": "^13.1.1" - }, - "devDependencies": { - "@tsconfig/node24": "^24.0.1", - "@types/node": "^24.5.2", - "tsx": "^4.20.6" - }, - "scripts": { - "build": "tsc -p tsconfig.json", - "start": "tsx watch src/main.ts", - "typecheck": "tsc --noEmit" - } + "name": "backend", + "private": true, + "main": "./src/main.ts", + "type": "module", + "dependencies": { + "@fishjam-cloud/js-server-sdk": "^0.21.0", + "dotenv": "^17.2.3", + "fastify": "^5.6.1", + "fastify-plugin": "^5.1.0", + "fastify-type-provider-zod": "^6.0.0", + "pino-pretty": "^13.1.1", + "zod": "^4.1.11" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.1", + "@types/node": "^24.5.2", + "tsx": "^4.20.6" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "tsx watch src/main.ts", + "typecheck": "tsc --noEmit" + } } diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts new file mode 100644 index 0000000..0ce6b5c --- /dev/null +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -0,0 +1,25 @@ +import dotenv from 'dotenv'; +import type { FastifyInstance } from 'fastify'; +import fp from 'fastify-plugin'; +import z from 'zod'; + +dotenv.config(); + +declare module 'fastify' { + interface FastifyInstance { + config: ConfigSchema; + } +} + +export const configSchema = z.object({ + PORT: z.coerce.number().int().default(8000), + FISHJAM_ID: z.string(), + FISHJAM_URL: z.string().optional(), + FISHJAM_MANAGEMENT_TOKEN: z.string(), +}); + +type ConfigSchema = z.infer; + +export const fastifyConfig = fp((fastify: FastifyInstance) => { + fastify.decorate('config', configSchema.parse(process.env)); +}); diff --git a/deep-sea-stories/packages/backend/src/controllers/rooms.ts b/deep-sea-stories/packages/backend/src/controllers/rooms.ts new file mode 100644 index 0000000..f4def30 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/controllers/rooms.ts @@ -0,0 +1,9 @@ +import type { FishjamClient, RoomId } from '@fishjam-cloud/js-server-sdk'; + +export async function createRoom(fishjam: FishjamClient) { + return await fishjam.createRoom(); +} + +export async function getRoom(fishjam: FishjamClient, roomId: RoomId) { + return await fishjam.getRoom(roomId); +} diff --git a/deep-sea-stories/packages/backend/src/main.ts b/deep-sea-stories/packages/backend/src/main.ts index 8a45034..a2bc43c 100644 --- a/deep-sea-stories/packages/backend/src/main.ts +++ b/deep-sea-stories/packages/backend/src/main.ts @@ -1,35 +1,29 @@ -import Fastify, { - type FastifyInstance, - type RouteShorthandOptions, -} from 'fastify'; +import Fastify from 'fastify'; +import { + serializerCompiler, + validatorCompiler, + type ZodTypeProvider, +} from 'fastify-type-provider-zod'; +import { fastifyConfig } from './config.js'; +import { fishjamPlugin } from './plugins/fishjam.js'; +import routes from './routes/index.js'; -const server: FastifyInstance = Fastify({ +const fastify = Fastify({ logger: { transport: { target: 'pino-pretty' } }, -}); -const port = 3000; +}).withTypeProvider(); -const opts: RouteShorthandOptions = { - schema: { - response: { - 200: { - type: 'object', - properties: { - pong: { - type: 'string', - }, - }, - }, - }, - }, -}; +fastify.setValidatorCompiler(validatorCompiler); +fastify.setSerializerCompiler(serializerCompiler); -server.get('/ping', opts, async (_request, _reply) => { - return { pong: 'it worked!' }; -}); +fastify.register(fastifyConfig); +fastify.register(fishjamPlugin); + +fastify.register(routes, { prefix: '/api/v1' }); try { - await server.listen({ port }); + await fastify.ready(); + await fastify.listen({ port: fastify.config.PORT }); } catch (err) { - server.log.error(err); + fastify.log.error(err); process.exit(1); } diff --git a/deep-sea-stories/packages/backend/src/plugins/fishjam.ts b/deep-sea-stories/packages/backend/src/plugins/fishjam.ts new file mode 100644 index 0000000..3754811 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/plugins/fishjam.ts @@ -0,0 +1,29 @@ +import { + FishjamBaseException, + FishjamClient, +} from '@fishjam-cloud/js-server-sdk'; +import type { FastifyInstance } from 'fastify'; +import fp from 'fastify-plugin'; + +declare module 'fastify' { + interface FastifyInstance { + fishjam: FishjamClient; + } +} + +export const fishjamPlugin = fp(async (fastify: FastifyInstance) => { + const fishjamClient = new FishjamClient({ + fishjamId: fastify.config.FISHJAM_ID, + fishjamUrl: fastify.config.FISHJAM_URL, + managementToken: fastify.config.FISHJAM_MANAGEMENT_TOKEN, + }); + + try { + await fishjamClient.getAllRooms(); + } catch (e) { + if (e instanceof FishjamBaseException) + throw Error('Invalid Fishjam configuration provided.'); + } + + fastify.decorate('fishjam', fishjamClient); +}); diff --git a/deep-sea-stories/packages/backend/src/routes/index.ts b/deep-sea-stories/packages/backend/src/routes/index.ts new file mode 100644 index 0000000..5ecf82e --- /dev/null +++ b/deep-sea-stories/packages/backend/src/routes/index.ts @@ -0,0 +1,6 @@ +import type { FastifyInstance } from 'fastify'; +import rooms from './rooms.js'; + +export default function routes(fastify: FastifyInstance) { + fastify.register(rooms, { prefix: '/rooms' }); +} diff --git a/deep-sea-stories/packages/backend/src/routes/rooms.ts b/deep-sea-stories/packages/backend/src/routes/rooms.ts new file mode 100644 index 0000000..96e5612 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/routes/rooms.ts @@ -0,0 +1,38 @@ +import type { RoomId } from '@fishjam-cloud/js-server-sdk'; +import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod'; +import z from 'zod'; +import { createRoom, getRoom } from '../controllers/rooms.js'; +import { roomSchema } from '../schemas.js'; + +const routes: FastifyPluginAsyncZod = async (fastify) => { + fastify.post( + '/', + { + schema: { + response: { + 201: roomSchema, + }, + }, + }, + async () => { + return await createRoom(fastify.fishjam); + }, + ); + + fastify.get( + '/:roomId', + { + schema: { + params: z.object({ + roomId: z.string(), + }), + response: { + 200: roomSchema, + }, + }, + }, + async (req) => await getRoom(fastify.fishjam, req.params.roomId as RoomId), + ); +}; + +export default routes; diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts new file mode 100644 index 0000000..796d85e --- /dev/null +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -0,0 +1,10 @@ +import z from 'zod'; + +export const peerSchema = z.object({ + id: z.string(), +}); + +export const roomSchema = z.object({ + id: z.string(), + peers: peerSchema.array(), +}); diff --git a/deep-sea-stories/packages/backend/tsconfig.json b/deep-sea-stories/packages/backend/tsconfig.json index 5416a60..4e37b26 100644 --- a/deep-sea-stories/packages/backend/tsconfig.json +++ b/deep-sea-stories/packages/backend/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@tsconfig/node24/tsconfig.json", "compilerOptions": { - "outDir": "dist" + "outDir": "dist", + "declaration": true } } diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index f16bfd7..aba01b6 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -289,7 +289,7 @@ __metadata: languageName: node linkType: hard -"@fastify/error@npm:^4.0.0": +"@fastify/error@npm:^4.0.0, @fastify/error@npm:^4.2.0": version: 4.2.0 resolution: "@fastify/error@npm:4.2.0" checksum: 10c0/8bdafe95b368a71dfc5644ef22e0a2412dfbb2f300cf4658fdbd9035c96d7c034c53fd7d38e1150437d9cf7a2d75e6bd05e458cf9ba5f2e47e527df8a5e0bd4e @@ -331,6 +331,16 @@ __metadata: languageName: node linkType: hard +"@fishjam-cloud/js-server-sdk@npm:^0.21.0": + version: 0.21.0 + resolution: "@fishjam-cloud/js-server-sdk@npm:0.21.0" + dependencies: + axios: "npm:^1.7.9" + uuid: "npm:^11.1.0" + checksum: 10c0/6574e887a731b6a2e0db691ea4320fe726ce7bd51731fbe51d697c91842d18d4d70aa55bb43e487b472ef255e904fef721a4abef2170e9588f119ffe22ca234b + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -476,6 +486,27 @@ __metadata: languageName: node linkType: hard +"async-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-function@npm:1.0.0" + checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 + languageName: node + linkType: hard + +"async-generator-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-generator-function@npm:1.0.0" + checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186 + languageName: node + linkType: hard + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + languageName: node + linkType: hard + "atomic-sleep@npm:^1.0.0": version: 1.0.0 resolution: "atomic-sleep@npm:1.0.0" @@ -493,15 +524,31 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.7.9": + version: 1.12.2 + resolution: "axios@npm:1.12.2" + dependencies: + follow-redirects: "npm:^1.15.6" + form-data: "npm:^4.0.4" + proxy-from-env: "npm:^1.1.0" + checksum: 10c0/80b063e318cf05cd33a4d991cea0162f3573481946f9129efb7766f38fde4c061c34f41a93a9f9521f02b7c9565ccbc197c099b0186543ac84a24580017adfed + languageName: node + linkType: hard + "backend@workspace:packages/backend": version: 0.0.0-use.local resolution: "backend@workspace:packages/backend" dependencies: + "@fishjam-cloud/js-server-sdk": "npm:^0.21.0" "@tsconfig/node24": "npm:^24.0.1" "@types/node": "npm:^24.5.2" + dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" + fastify-plugin: "npm:^5.1.0" + fastify-type-provider-zod: "npm:^6.0.0" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" + zod: "npm:^4.1.11" languageName: unknown linkType: soft @@ -541,6 +588,16 @@ __metadata: languageName: node linkType: hard +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -571,6 +628,15 @@ __metadata: languageName: node linkType: hard +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + languageName: node + linkType: hard + "cookie@npm:^1.0.1": version: 1.0.2 resolution: "cookie@npm:1.0.2" @@ -617,6 +683,13 @@ __metadata: languageName: unknown linkType: soft +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + languageName: node + linkType: hard + "dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" @@ -624,6 +697,24 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^17.2.3": + version: 17.2.3 + resolution: "dotenv@npm:17.2.3" + checksum: 10c0/c884403209f713214a1b64d4d1defa4934c2aa5b0002f5a670ae298a51e3c3ad3ba79dfee2f8df49f01ae74290fcd9acdb1ab1d09c7bfb42b539036108bb2ba0 + languageName: node + linkType: hard + +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -677,6 +768,41 @@ __metadata: languageName: node linkType: hard +"es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 + languageName: node + linkType: hard + +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.1.0": + version: 2.1.0 + resolution: "es-set-tostringtag@npm:2.1.0" + dependencies: + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af + languageName: node + linkType: hard + "esbuild@npm:~0.25.0": version: 0.25.10 resolution: "esbuild@npm:0.25.10" @@ -831,6 +957,27 @@ __metadata: languageName: node linkType: hard +"fastify-plugin@npm:^5.1.0": + version: 5.1.0 + resolution: "fastify-plugin@npm:5.1.0" + checksum: 10c0/61b330b8cb03a3581b796d745137499a782934abcf65dbf9a41d07248520cfd220b3ae8b16afeaf81af712e68e1ac24352895132cfeb2b372c66662c0170f365 + languageName: node + linkType: hard + +"fastify-type-provider-zod@npm:^6.0.0": + version: 6.0.0 + resolution: "fastify-type-provider-zod@npm:6.0.0" + dependencies: + "@fastify/error": "npm:^4.2.0" + peerDependencies: + "@fastify/swagger": ">=9.5.1" + fastify: ^5.0.0 + openapi-types: ^12.1.3 + zod: ">=4.1.5" + checksum: 10c0/222a32de89ad5a3d15cdb3536c004d7b36b5f969fb34ffaeda35f06a03fc9ca31dd8045bdb3b61c6c72259fd7b4d3654e2ce886d0e193036fde47eab17f4f1b6 + languageName: node + linkType: hard + "fastify@npm:^5.6.1": version: 5.6.1 resolution: "fastify@npm:5.6.1" @@ -886,6 +1033,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.6": + version: 1.15.11 + resolution: "follow-redirects@npm:1.15.11" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343 + languageName: node + linkType: hard + "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -896,6 +1053,19 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.4": + version: 4.0.4 + resolution: "form-data@npm:4.0.4" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" + hasown: "npm:^2.0.2" + mime-types: "npm:^2.1.12" + checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695 + languageName: node + linkType: hard + "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -924,6 +1094,51 @@ __metadata: languageName: node linkType: hard +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 + languageName: node + linkType: hard + +"generator-function@npm:^2.0.0": + version: 2.0.0 + resolution: "generator-function@npm:2.0.0" + checksum: 10c0/27574ccb34deb4ff89155c4b417601522f770cc823c2806ffadc3c1d679b2c862dc22374ac22cfe0198034f6aca95dd8ee8d7d6a35d038a5e2db2dd8bf4e0b80 + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.6": + version: 1.3.1 + resolution: "get-intrinsic@npm:1.3.1" + dependencies: + async-function: "npm:^1.0.0" + async-generator-function: "npm:^1.0.0" + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + function-bind: "npm:^1.1.2" + generator-function: "npm:^2.0.0" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d + languageName: node + linkType: hard + +"get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c + languageName: node + linkType: hard + "get-tsconfig@npm:^4.7.5": version: 4.10.1 resolution: "get-tsconfig@npm:4.10.1" @@ -949,6 +1164,13 @@ __metadata: languageName: node linkType: hard +"gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead + languageName: node + linkType: hard + "graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -956,6 +1178,31 @@ __metadata: languageName: node linkType: hard +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e + languageName: node + linkType: hard + +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c + languageName: node + linkType: hard + +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 + languageName: node + linkType: hard + "help-me@npm:^5.0.0": version: 5.0.0 resolution: "help-me@npm:5.0.0" @@ -1114,6 +1361,29 @@ __metadata: languageName: node linkType: hard +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -1396,6 +1666,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.3 resolution: "pump@npm:3.0.3" @@ -1738,6 +2015,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^11.1.0": + version: 11.1.0 + resolution: "uuid@npm:11.1.0" + bin: + uuid: dist/esm/bin/uuid + checksum: 10c0/34aa51b9874ae398c2b799c88a127701408cd581ee89ec3baa53509dd8728cbb25826f2a038f9465f8b7be446f0fbf11558862965b18d21c993684297628d4d3 + languageName: node + linkType: hard + "web@workspace:packages/web": version: 0.0.0-use.local resolution: "web@workspace:packages/web" @@ -1808,3 +2094,10 @@ __metadata: checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 languageName: node linkType: hard + +"zod@npm:^4.1.11": + version: 4.1.11 + resolution: "zod@npm:4.1.11" + checksum: 10c0/ce6a4c4acfbf51d7dd0f2669c82f207d62a1f00264eef608994b94eb99d86a74c99f59b0dd3e61ef82909ee136631378b709e0908f0a02a2d5c21d0c497de5db + languageName: node + linkType: hard From 7208fa891173104a0acc18abefa2cd172b6883dc Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:49:32 +0200 Subject: [PATCH 10/65] Init vite --- deep-sea-stories/packages/web/.gitignore | 24 + deep-sea-stories/packages/web/README.md | 75 + .../packages/web/eslint.config.js | 23 + deep-sea-stories/packages/web/index.html | 13 + deep-sea-stories/packages/web/package.json | 30 +- deep-sea-stories/packages/web/public/vite.svg | 1 + deep-sea-stories/packages/web/src/App.css | 42 + deep-sea-stories/packages/web/src/App.tsx | 35 + .../packages/web/src/assets/react.svg | 1 + deep-sea-stories/packages/web/src/index.css | 68 + deep-sea-stories/packages/web/src/main.tsx | 10 + .../packages/web/tsconfig.app.json | 28 + deep-sea-stories/packages/web/tsconfig.json | 7 + .../packages/web/tsconfig.node.json | 26 + deep-sea-stories/packages/web/vite.config.ts | 13 + deep-sea-stories/yarn.lock | 1889 ++++++++++++++++- 16 files changed, 2253 insertions(+), 32 deletions(-) create mode 100644 deep-sea-stories/packages/web/.gitignore create mode 100644 deep-sea-stories/packages/web/README.md create mode 100644 deep-sea-stories/packages/web/eslint.config.js create mode 100644 deep-sea-stories/packages/web/index.html create mode 100644 deep-sea-stories/packages/web/public/vite.svg create mode 100644 deep-sea-stories/packages/web/src/App.css create mode 100644 deep-sea-stories/packages/web/src/App.tsx create mode 100644 deep-sea-stories/packages/web/src/assets/react.svg create mode 100644 deep-sea-stories/packages/web/src/index.css create mode 100644 deep-sea-stories/packages/web/src/main.tsx create mode 100644 deep-sea-stories/packages/web/tsconfig.app.json create mode 100644 deep-sea-stories/packages/web/tsconfig.json create mode 100644 deep-sea-stories/packages/web/tsconfig.node.json create mode 100644 deep-sea-stories/packages/web/vite.config.ts diff --git a/deep-sea-stories/packages/web/.gitignore b/deep-sea-stories/packages/web/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/deep-sea-stories/packages/web/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/deep-sea-stories/packages/web/README.md b/deep-sea-stories/packages/web/README.md new file mode 100644 index 0000000..b473640 --- /dev/null +++ b/deep-sea-stories/packages/web/README.md @@ -0,0 +1,75 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## React Compiler + +The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. + +Note: This will impact Vite dev & build performances. + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/deep-sea-stories/packages/web/eslint.config.js b/deep-sea-stories/packages/web/eslint.config.js new file mode 100644 index 0000000..b19330b --- /dev/null +++ b/deep-sea-stories/packages/web/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/deep-sea-stories/packages/web/index.html b/deep-sea-stories/packages/web/index.html new file mode 100644 index 0000000..af88f03 --- /dev/null +++ b/deep-sea-stories/packages/web/index.html @@ -0,0 +1,13 @@ + + + + + + + web + + +
+ + + diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 1dfb7e3..f38fb3c 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -1,4 +1,30 @@ { - "name": "web", - "private": true + "name": "web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "babel-plugin-react-compiler": "^19.1.0-rc.3", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.4.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.44.0", + "vite": "^7.1.7" + } } diff --git a/deep-sea-stories/packages/web/public/vite.svg b/deep-sea-stories/packages/web/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/deep-sea-stories/packages/web/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/deep-sea-stories/packages/web/src/App.css b/deep-sea-stories/packages/web/src/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/deep-sea-stories/packages/web/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/deep-sea-stories/packages/web/src/App.tsx b/deep-sea-stories/packages/web/src/App.tsx new file mode 100644 index 0000000..3d7ded3 --- /dev/null +++ b/deep-sea-stories/packages/web/src/App.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react' +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' +import './App.css' + +function App() { + const [count, setCount] = useState(0) + + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ) +} + +export default App diff --git a/deep-sea-stories/packages/web/src/assets/react.svg b/deep-sea-stories/packages/web/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/deep-sea-stories/packages/web/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css new file mode 100644 index 0000000..08a3ac9 --- /dev/null +++ b/deep-sea-stories/packages/web/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/deep-sea-stories/packages/web/tsconfig.app.json b/deep-sea-stories/packages/web/tsconfig.app.json new file mode 100644 index 0000000..a9b5a59 --- /dev/null +++ b/deep-sea-stories/packages/web/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/deep-sea-stories/packages/web/tsconfig.json b/deep-sea-stories/packages/web/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/deep-sea-stories/packages/web/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/deep-sea-stories/packages/web/tsconfig.node.json b/deep-sea-stories/packages/web/tsconfig.node.json new file mode 100644 index 0000000..7a77bab --- /dev/null +++ b/deep-sea-stories/packages/web/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": [], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/deep-sea-stories/packages/web/vite.config.ts b/deep-sea-stories/packages/web/vite.config.ts new file mode 100644 index 0000000..4efe189 --- /dev/null +++ b/deep-sea-stories/packages/web/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [['babel-plugin-react-compiler']], + }, + }), + ], +}) diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index aba01b6..42a149f 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -5,6 +5,210 @@ __metadata: version: 8 cacheKey: 10c0 +"@babel/code-frame@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/code-frame@npm:7.27.1" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.27.1" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/5dd9a18baa5fce4741ba729acc3a3272c49c25cb8736c4b18e113099520e7ef7b545a4096a26d600e4416157e63e87d66db46aa3fbf0a5f2286da2705c12da00 + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.27.2": + version: 7.28.4 + resolution: "@babel/compat-data@npm:7.28.4" + checksum: 10c0/9d346471e0a016641df9a325f42ad1e8324bbdc0243ce4af4dd2b10b974128590da9eb179eea2c36647b9bb987343119105e96773c1f6981732cd4f87e5a03b9 + languageName: node + linkType: hard + +"@babel/core@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/core@npm:7.28.4" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.3" + "@babel/helper-compilation-targets": "npm:^7.27.2" + "@babel/helper-module-transforms": "npm:^7.28.3" + "@babel/helpers": "npm:^7.28.4" + "@babel/parser": "npm:^7.28.4" + "@babel/template": "npm:^7.27.2" + "@babel/traverse": "npm:^7.28.4" + "@babel/types": "npm:^7.28.4" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/ef5a6c3c6bf40d3589b5593f8118cfe2602ce737412629fb6e26d595be2fcbaae0807b43027a5c42ec4fba5b895ff65891f2503b5918c8a3ea3542ab44d4c278 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.28.3": + version: 7.28.3 + resolution: "@babel/generator@npm:7.28.3" + dependencies: + "@babel/parser": "npm:^7.28.3" + "@babel/types": "npm:^7.28.2" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/0ff58bcf04f8803dcc29479b547b43b9b0b828ec1ee0668e92d79f9e90f388c28589056637c5ff2fd7bcf8d153c990d29c448d449d852bf9d1bc64753ca462bc + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/helper-compilation-targets@npm:7.27.2" + dependencies: + "@babel/compat-data": "npm:^7.27.2" + "@babel/helper-validator-option": "npm:^7.27.1" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/f338fa00dcfea931804a7c55d1a1c81b6f0a09787e528ec580d5c21b3ecb3913f6cb0f361368973ce953b824d910d3ac3e8a8ee15192710d3563826447193ad1 + languageName: node + linkType: hard + +"@babel/helper-globals@npm:^7.28.0": + version: 7.28.0 + resolution: "@babel/helper-globals@npm:7.28.0" + checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-module-imports@npm:7.27.1" + dependencies: + "@babel/traverse": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + checksum: 10c0/e00aace096e4e29290ff8648455c2bc4ed982f0d61dbf2db1b5e750b9b98f318bf5788d75a4f974c151bd318fd549e81dbcab595f46b14b81c12eda3023f51e8 + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.28.3": + version: 7.28.3 + resolution: "@babel/helper-module-transforms@npm:7.28.3" + dependencies: + "@babel/helper-module-imports": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.3" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/549be62515a6d50cd4cfefcab1b005c47f89bd9135a22d602ee6a5e3a01f27571868ada10b75b033569f24dc4a2bb8d04bfa05ee75c16da7ade2d0db1437fcdb + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-plugin-utils@npm:7.27.1" + checksum: 10c0/94cf22c81a0c11a09b197b41ab488d416ff62254ce13c57e62912c85700dc2e99e555225787a4099ff6bae7a1812d622c80fbaeda824b79baa10a6c5ac4cf69b + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-identifier@npm:7.27.1" + checksum: 10c0/c558f11c4871d526498e49d07a84752d1800bf72ac0d3dad100309a2eaba24efbf56ea59af5137ff15e3a00280ebe588560534b0e894a4750f8b1411d8f78b84 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-option@npm:7.27.1" + checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/helpers@npm:7.28.4" + dependencies: + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.4" + checksum: 10c0/aaa5fb8098926dfed5f223adf2c5e4c7fbba4b911b73dfec2d7d3083f8ba694d201a206db673da2d9b3ae8c01793e795767654558c450c8c14b4c2175b4fcb44 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.3, @babel/parser@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/parser@npm:7.28.4" + dependencies: + "@babel/types": "npm:^7.28.4" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/58b239a5b1477ac7ed7e29d86d675cc81075ca055424eba6485872626db2dc556ce63c45043e5a679cd925e999471dba8a3ed4864e7ab1dbf64306ab72c52707 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-self@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/00a4f917b70a608f9aca2fb39aabe04a60aa33165a7e0105fd44b3a8531630eb85bf5572e9f242f51e6ad2fa38c2e7e780902176c863556c58b5ba6f6e164031 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5e67b56c39c4d03e59e03ba80692b24c5a921472079b63af711b1d250fc37c1733a17069b63537f750f3e937ec44a42b1ee6a46cd23b1a0df5163b17f741f7f2 + languageName: node + linkType: hard + +"@babel/template@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/template@npm:7.27.2" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/parser": "npm:^7.27.2" + "@babel/types": "npm:^7.27.1" + checksum: 10c0/ed9e9022651e463cc5f2cc21942f0e74544f1754d231add6348ff1b472985a3b3502041c0be62dc99ed2d12cfae0c51394bf827452b98a2f8769c03b87aadc81 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/traverse@npm:7.28.4" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.3" + "@babel/helper-globals": "npm:^7.28.0" + "@babel/parser": "npm:^7.28.4" + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.4" + debug: "npm:^4.3.1" + checksum: 10c0/ee678fdd49c9f54a32e07e8455242390d43ce44887cea6567b233fe13907b89240c377e7633478a32c6cf1be0e17c2f7f3b0c59f0666e39c5074cc47b968489c + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.26.0, @babel/types@npm:^7.27.1, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/types@npm:7.28.4" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + checksum: 10c0/ac6f909d6191319e08c80efbfac7bd9a25f80cc83b43cd6d82e7233f7a6b9d6e7b90236f3af7400a3f83b576895bcab9188a22b584eb0f224e80e6d4e95f4517 + languageName: node + linkType: hard + "@biomejs/biome@npm:2.2.4": version: 2.2.4 resolution: "@biomejs/biome@npm:2.2.4" @@ -278,6 +482,92 @@ __metadata: languageName: node linkType: hard +"@eslint-community/eslint-utils@npm:^4.7.0, @eslint-community/eslint-utils@npm:^4.8.0": + version: 4.9.0 + resolution: "@eslint-community/eslint-utils@npm:4.9.0" + dependencies: + eslint-visitor-keys: "npm:^3.4.3" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.12.1": + version: 4.12.1 + resolution: "@eslint-community/regexpp@npm:4.12.1" + checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.21.0": + version: 0.21.0 + resolution: "@eslint/config-array@npm:0.21.0" + dependencies: + "@eslint/object-schema": "npm:^2.1.6" + debug: "npm:^4.3.1" + minimatch: "npm:^3.1.2" + checksum: 10c0/0ea801139166c4aa56465b309af512ef9b2d3c68f9198751bbc3e21894fe70f25fbf26e1b0e9fffff41857bc21bfddeee58649ae6d79aadcd747db0c5dca771f + languageName: node + linkType: hard + +"@eslint/config-helpers@npm:^0.3.1": + version: 0.3.1 + resolution: "@eslint/config-helpers@npm:0.3.1" + checksum: 10c0/f6c5b3a0b76a0d7d84cc93e310c259e6c3e0792ddd0a62c5fc0027796ffae44183432cb74b2c2b1162801ee1b1b34a6beb5d90a151632b4df7349f994146a856 + languageName: node + linkType: hard + +"@eslint/core@npm:^0.15.2": + version: 0.15.2 + resolution: "@eslint/core@npm:0.15.2" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 10c0/c17a6dc4f5a6006ecb60165cc38bcd21fefb4a10c7a2578a0cfe5813bbd442531a87ed741da5adab5eb678e8e693fda2e2b14555b035355537e32bcec367ea17 + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^3.3.1": + version: 3.3.1 + resolution: "@eslint/eslintrc@npm:3.3.1" + dependencies: + ajv: "npm:^6.12.4" + debug: "npm:^4.3.2" + espree: "npm:^10.0.1" + globals: "npm:^14.0.0" + ignore: "npm:^5.2.0" + import-fresh: "npm:^3.2.1" + js-yaml: "npm:^4.1.0" + minimatch: "npm:^3.1.2" + strip-json-comments: "npm:^3.1.1" + checksum: 10c0/b0e63f3bc5cce4555f791a4e487bf999173fcf27c65e1ab6e7d63634d8a43b33c3693e79f192cbff486d7df1be8ebb2bd2edc6e70ddd486cbfa84a359a3e3b41 + languageName: node + linkType: hard + +"@eslint/js@npm:9.36.0, @eslint/js@npm:^9.36.0": + version: 9.36.0 + resolution: "@eslint/js@npm:9.36.0" + checksum: 10c0/e3f6fb7d6f117d79615574f7bef4f238bcfed6ece0465d28226c3a75d2b6fac9cc189121e8673562796ca8ccea2bf9861715ee5cf4a3dbef87d17811c0dac22c + languageName: node + linkType: hard + +"@eslint/object-schema@npm:^2.1.6": + version: 2.1.6 + resolution: "@eslint/object-schema@npm:2.1.6" + checksum: 10c0/b8cdb7edea5bc5f6a96173f8d768d3554a628327af536da2fc6967a93b040f2557114d98dbcdbf389d5a7b290985ad6a9ce5babc547f36fc1fde42e674d11a56 + languageName: node + linkType: hard + +"@eslint/plugin-kit@npm:^0.3.5": + version: 0.3.5 + resolution: "@eslint/plugin-kit@npm:0.3.5" + dependencies: + "@eslint/core": "npm:^0.15.2" + levn: "npm:^0.4.1" + checksum: 10c0/c178c1b58c574200c0fd125af3e4bc775daba7ce434ba6d1eeaf9bcb64b2e9fea75efabffb3ed3ab28858e55a016a5efa95f509994ee4341b341199ca630b89e + languageName: node + linkType: hard + "@fastify/ajv-compiler@npm:^4.0.0": version: 4.0.2 resolution: "@fastify/ajv-compiler@npm:4.0.2" @@ -341,6 +631,37 @@ __metadata: languageName: node linkType: hard +"@humanfs/core@npm:^0.19.1": + version: 0.19.1 + resolution: "@humanfs/core@npm:0.19.1" + checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 + languageName: node + linkType: hard + +"@humanfs/node@npm:^0.16.6": + version: 0.16.7 + resolution: "@humanfs/node@npm:0.16.7" + dependencies: + "@humanfs/core": "npm:^0.19.1" + "@humanwhocodes/retry": "npm:^0.4.0" + checksum: 10c0/9f83d3cf2cfa37383e01e3cdaead11cd426208e04c44adcdd291aa983aaf72d7d3598844d2fe9ce54896bb1bf8bd4b56883376611c8905a19c44684642823f30 + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 + languageName: node + linkType: hard + +"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -364,6 +685,77 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.13 + resolution: "@jridgewell/gen-mapping@npm:0.3.13" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b + languageName: node + linkType: hard + +"@jridgewell/remapping@npm:^2.3.5": + version: 2.3.5 + resolution: "@jridgewell/remapping@npm:2.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.5 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" + checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": "npm:2.0.5" + run-parallel: "npm:^1.1.9" + checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": "npm:2.1.5" + fastq: "npm:^1.6.0" + checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 + languageName: node + linkType: hard + "@npmcli/agent@npm:^3.0.0": version: 3.0.0 resolution: "@npmcli/agent@npm:3.0.0" @@ -377,35 +769,422 @@ __metadata: languageName: node linkType: hard -"@npmcli/fs@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/fs@npm:4.0.0" +"@npmcli/fs@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/fs@npm:4.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/c90935d5ce670c87b6b14fab04a965a3b8137e585f8b2a6257263bd7f97756dd736cb165bb470e5156a9e718ecd99413dccc54b1138c1a46d6ec7cf325982fe5 + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd + languageName: node + linkType: hard + +"@rolldown/pluginutils@npm:1.0.0-beta.38": + version: 1.0.0-beta.38 + resolution: "@rolldown/pluginutils@npm:1.0.0-beta.38" + checksum: 10c0/8353ec2528349f79e27d1a3193806725b85830da334e935cbb606d88c1177c58ea6519c578e4e93e5f677f5b22aecb8738894dbed14603e14b6bffe3facf1002 + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.52.3" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-android-arm64@npm:4.52.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-darwin-arm64@npm:4.52.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-darwin-x64@npm:4.52.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.52.3" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-freebsd-x64@npm:4.52.3" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.52.3" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.52.3" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.52.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.52.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.52.3" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.52.3" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.52.3" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.52.3" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.52.3" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.52.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.52.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.52.3" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.52.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.52.3" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-gnu@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.52.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.52.3": + version: 4.52.3 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.52.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@tsconfig/node24@npm:^24.0.1": + version: 24.0.1 + resolution: "@tsconfig/node24@npm:24.0.1" + checksum: 10c0/18e2ad5946bc6ddc9fbe37c4537439245da16eb8a5888641a1cdbc412a465ee321b5fa7c0ffc489c929d65c8bd0698ece9e8f3c52ae2596433ad0e866857bc83 + languageName: node + linkType: hard + +"@types/babel__core@npm:^7.20.5": + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" + dependencies: + "@babel/parser": "npm:^7.20.7" + "@babel/types": "npm:^7.20.7" + "@types/babel__generator": "npm:*" + "@types/babel__template": "npm:*" + "@types/babel__traverse": "npm:*" + checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff + languageName: node + linkType: hard + +"@types/babel__generator@npm:*": + version: 7.27.0 + resolution: "@types/babel__generator@npm:7.27.0" + dependencies: + "@babel/types": "npm:^7.0.0" + checksum: 10c0/9f9e959a8792df208a9d048092fda7e1858bddc95c6314857a8211a99e20e6830bdeb572e3587ae8be5429e37f2a96fcf222a9f53ad232f5537764c9e13a2bbd + languageName: node + linkType: hard + +"@types/babel__template@npm:*": + version: 7.4.4 + resolution: "@types/babel__template@npm:7.4.4" + dependencies: + "@babel/parser": "npm:^7.1.0" + "@babel/types": "npm:^7.0.0" + checksum: 10c0/cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b + languageName: node + linkType: hard + +"@types/babel__traverse@npm:*": + version: 7.28.0 + resolution: "@types/babel__traverse@npm:7.28.0" + dependencies: + "@babel/types": "npm:^7.28.2" + checksum: 10c0/b52d7d4e8fc6a9018fe7361c4062c1c190f5778cf2466817cb9ed19d69fbbb54f9a85ffedeb748ed8062d2cf7d4cc088ee739848f47c57740de1c48cbf0d0994 + languageName: node + linkType: hard + +"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.6": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + languageName: node + linkType: hard + +"@types/json-schema@npm:^7.0.15": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + +"@types/node@npm:^24.5.2": + version: 24.5.2 + resolution: "@types/node@npm:24.5.2" + dependencies: + undici-types: "npm:~7.12.0" + checksum: 10c0/96baaca6564d39c6f7f6eddd73ce41e2a7594ef37225cd52df3be36fad31712af8ae178387a72d0b80f2e2799e7fd30c014bc0ae9eb9f962d9079b691be00c48 + languageName: node + linkType: hard + +"@types/react-dom@npm:^19.1.9": + version: 19.1.9 + resolution: "@types/react-dom@npm:19.1.9" + peerDependencies: + "@types/react": ^19.0.0 + checksum: 10c0/34c8dda86c1590b3ef0e7ecd38f9663a66ba2dd69113ba74fb0adc36b83bbfb8c94c1487a2505282a5f7e5e000d2ebf36f4c0fd41b3b672f5178fd1d4f1f8f58 + languageName: node + linkType: hard + +"@types/react@npm:^19.1.13": + version: 19.1.16 + resolution: "@types/react@npm:19.1.16" + dependencies: + csstype: "npm:^3.0.2" + checksum: 10c0/3d781f715f15f308b601d74142fae77c65679c318a3bb0a319df898f39095e738ba7ed7061cec971b19b6d33969ef9cd50fec92b034024ef3fcc25bb9a2eb3d0 + languageName: node + linkType: hard + +"@typescript-eslint/eslint-plugin@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.45.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:8.45.0" + "@typescript-eslint/type-utils": "npm:8.45.0" + "@typescript-eslint/utils": "npm:8.45.0" + "@typescript-eslint/visitor-keys": "npm:8.45.0" + graphemer: "npm:^1.4.0" + ignore: "npm:^7.0.0" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + "@typescript-eslint/parser": ^8.45.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/0c60a0e5d07fa8618348db38b5a81e66143d528e1b3cdb5678bbc6c60590cd559b27c98c36f5663230fc4cf6920dff2cd604de30b58df26a37fcfcc5dc1dbd45 + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/parser@npm:8.45.0" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.45.0" + "@typescript-eslint/types": "npm:8.45.0" + "@typescript-eslint/typescript-estree": "npm:8.45.0" + "@typescript-eslint/visitor-keys": "npm:8.45.0" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/8b419bcf795b112a39fcac05dcf147835059345b6399035ffa3f76a9d8e320f3fac79cae2fe4320dcda83fa059b017ca7626a7b4e3da08a614415c8867d169b8 + languageName: node + linkType: hard + +"@typescript-eslint/project-service@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/project-service@npm:8.45.0" + dependencies: + "@typescript-eslint/tsconfig-utils": "npm:^8.45.0" + "@typescript-eslint/types": "npm:^8.45.0" + debug: "npm:^4.3.4" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/98af065a1a3ed9d3d1eb265e09d3e9c2ae676d500a8c1d764f5609fe2c1b86749516b709804eb814fae688be7809d11748b9ae691d43c28da51dac390ca81fa9 + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/scope-manager@npm:8.45.0" + dependencies: + "@typescript-eslint/types": "npm:8.45.0" + "@typescript-eslint/visitor-keys": "npm:8.45.0" + checksum: 10c0/54cd36206f6b4fc8e1e48576ed01e0d6ab20c2a9c4c7d90d5cc3a2d317dd8a13abe148ffecf471b16f1224aba5749e0905472745626bef9ae5bed771776f4abe + languageName: node + linkType: hard + +"@typescript-eslint/tsconfig-utils@npm:8.45.0, @typescript-eslint/tsconfig-utils@npm:^8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.45.0" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/227a9b7a5baaf35466fd369992cb933192515df1156ddf22f438deb344c2523695208e1036f5590b20603f31724de75a47fe0ee84e2fd4c8e9f3606f23f68112 + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/type-utils@npm:8.45.0" + dependencies: + "@typescript-eslint/types": "npm:8.45.0" + "@typescript-eslint/typescript-estree": "npm:8.45.0" + "@typescript-eslint/utils": "npm:8.45.0" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/ce0f4c209c2418ebeb65e7de053499fb68bf6000bdd71068594fdb8c8ac3dbbd62935a3cea233989491f7da3ef5db87e7efd2910133c6abf6d0cbf57248f6442 + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:8.45.0, @typescript-eslint/types@npm:^8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/types@npm:8.45.0" + checksum: 10c0/0213a0573c671d13bc91961a2b2e814ec7f6381ff093bce6704017bd96b2fc7fee25906c815cedb32a0601cf5071ca6c7c5f940d087c3b0d3dd7d4bc03478278 + languageName: node + linkType: hard + +"@typescript-eslint/typescript-estree@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.45.0" dependencies: - semver: "npm:^7.3.5" - checksum: 10c0/c90935d5ce670c87b6b14fab04a965a3b8137e585f8b2a6257263bd7f97756dd736cb165bb470e5156a9e718ecd99413dccc54b1138c1a46d6ec7cf325982fe5 + "@typescript-eslint/project-service": "npm:8.45.0" + "@typescript-eslint/tsconfig-utils": "npm:8.45.0" + "@typescript-eslint/types": "npm:8.45.0" + "@typescript-eslint/visitor-keys": "npm:8.45.0" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/8c2f44a00fe859a6cd4b50157c484c5b6a1c7af5d48e89ae79c5f4924947964962fc8f478ad4c2ade788907fceee9b72d4e376508ea79b51392f91082a37d239 languageName: node linkType: hard -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd +"@typescript-eslint/utils@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/utils@npm:8.45.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.7.0" + "@typescript-eslint/scope-manager": "npm:8.45.0" + "@typescript-eslint/types": "npm:8.45.0" + "@typescript-eslint/typescript-estree": "npm:8.45.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/b3c83a23813b15e20e303d7153789508c01e06dec355b1a80547c59aa36998d498102f45fcd13f111031fac57270608abb04d20560248d4448fd00b1cf4dc4ab languageName: node linkType: hard -"@tsconfig/node24@npm:^24.0.1": - version: 24.0.1 - resolution: "@tsconfig/node24@npm:24.0.1" - checksum: 10c0/18e2ad5946bc6ddc9fbe37c4537439245da16eb8a5888641a1cdbc412a465ee321b5fa7c0ffc489c929d65c8bd0698ece9e8f3c52ae2596433ad0e866857bc83 +"@typescript-eslint/visitor-keys@npm:8.45.0": + version: 8.45.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.45.0" + dependencies: + "@typescript-eslint/types": "npm:8.45.0" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/119adcf50c902dad7f7757bcdd88fad0a23a171d309d9b7cefe78af12e451cf84c04ae611f4c31f7e23f16c2b47665ad92e6e5648fc77d542ef306f465bf1f29 languageName: node linkType: hard -"@types/node@npm:^24.5.2": - version: 24.5.2 - resolution: "@types/node@npm:24.5.2" +"@vitejs/plugin-react@npm:^5.0.3": + version: 5.0.4 + resolution: "@vitejs/plugin-react@npm:5.0.4" dependencies: - undici-types: "npm:~7.12.0" - checksum: 10c0/96baaca6564d39c6f7f6eddd73ce41e2a7594ef37225cd52df3be36fad31712af8ae178387a72d0b80f2e2799e7fd30c014bc0ae9eb9f962d9079b691be00c48 + "@babel/core": "npm:^7.28.4" + "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" + "@rolldown/pluginutils": "npm:1.0.0-beta.38" + "@types/babel__core": "npm:^7.20.5" + react-refresh: "npm:^0.17.0" + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + checksum: 10c0/bb9360a4b4c0abf064d22211756b999faf23889ac150de490590ca7bd029b0ef7f4cd8ba3a32b86682a62d46fb7bebd75b3fa9835c57c78123f4a646de2e0136 languageName: node linkType: hard @@ -423,6 +1202,24 @@ __metadata: languageName: node linkType: hard +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn@npm:^8.15.0": + version: 8.15.0 + resolution: "acorn@npm:8.15.0" + bin: + acorn: bin/acorn + checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec + languageName: node + linkType: hard + "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -444,6 +1241,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^6.12.4": + version: 6.12.6 + resolution: "ajv@npm:6.12.6" + dependencies: + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 + languageName: node + linkType: hard + "ajv@npm:^8.0.0, ajv@npm:^8.12.0": version: 8.17.1 resolution: "ajv@npm:8.17.1" @@ -470,7 +1279,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -486,6 +1295,13 @@ __metadata: languageName: node linkType: hard +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e + languageName: node + linkType: hard + "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -535,6 +1351,15 @@ __metadata: languageName: node linkType: hard +"babel-plugin-react-compiler@npm:^19.1.0-rc.3": + version: 19.1.0-rc.3 + resolution: "babel-plugin-react-compiler@npm:19.1.0-rc.3" + dependencies: + "@babel/types": "npm:^7.26.0" + checksum: 10c0/6811500cf81a309f104ec1de3fa9336932a1105e3c0e747b81a1d12e80c2cd4f531f7c42ec4441f96527ee20e19342af58d958241061d47a02b0d8bee66fbe35 + languageName: node + linkType: hard + "backend@workspace:packages/backend": version: 0.0.0-use.local resolution: "backend@workspace:packages/backend" @@ -559,6 +1384,25 @@ __metadata: languageName: node linkType: hard +"baseline-browser-mapping@npm:^2.8.3": + version: 2.8.9 + resolution: "baseline-browser-mapping@npm:2.8.9" + bin: + baseline-browser-mapping: dist/cli.js + checksum: 10c0/c54356eb90cf251f351708f151fa42d0331814c03baa7bdcc802767f721fd9fe069eea88ae42395984bfddcae0c2fba2e5ee25d7921ce7cdcefc2f47440673d4 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10c0/975fecac2bb7758c062c20d0b3b6288c7cc895219ee25f0a64a9de662dbac981ff0b6e89909c3897c1f84fa353113a721923afdec5f8b2350255b097f12b1f73 + languageName: node + linkType: hard + "brace-expansion@npm:^2.0.1": version: 2.0.2 resolution: "brace-expansion@npm:2.0.2" @@ -568,6 +1412,30 @@ __metadata: languageName: node linkType: hard +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 + languageName: node + linkType: hard + +"browserslist@npm:^4.24.0": + version: 4.26.2 + resolution: "browserslist@npm:4.26.2" + dependencies: + baseline-browser-mapping: "npm:^2.8.3" + caniuse-lite: "npm:^1.0.30001741" + electron-to-chromium: "npm:^1.5.218" + node-releases: "npm:^2.0.21" + update-browserslist-db: "npm:^1.1.3" + bin: + browserslist: cli.js + checksum: 10c0/1146339dad33fda77786b11ea07f1c40c48899edd897d73a9114ee0dbb1ee6475bb4abda263a678c104508bdca8e66760ff8e10be1947d3e20d34bae01d8b89b + languageName: node + linkType: hard + "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -598,6 +1466,30 @@ __metadata: languageName: node linkType: hard +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001741": + version: 1.0.30001746 + resolution: "caniuse-lite@npm:1.0.30001746" + checksum: 10c0/e656a9dc811be2316e3b6dbd3bf25d0e32dbce645b1284821b4ec93fb81dc3e3f73b9473e2f66c921b620ea8b25ebbae9ee70c3d13dad85f8dd69d6bb2c91d46 + languageName: node + linkType: hard + +"chalk@npm:^4.0.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -637,6 +1529,20 @@ __metadata: languageName: node linkType: hard +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f + languageName: node + linkType: hard + +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + "cookie@npm:^1.0.1": version: 1.0.2 resolution: "cookie@npm:1.0.2" @@ -655,6 +1561,13 @@ __metadata: languageName: node linkType: hard +"csstype@npm:^3.0.2": + version: 3.1.3 + resolution: "csstype@npm:3.1.3" + checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 + languageName: node + linkType: hard + "dateformat@npm:^4.6.3": version: 4.6.3 resolution: "dateformat@npm:4.6.3" @@ -662,7 +1575,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -674,6 +1587,13 @@ __metadata: languageName: node linkType: hard +"deep-is@npm:^0.1.3": + version: 0.1.4 + resolution: "deep-is@npm:0.1.4" + checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c + languageName: node + linkType: hard + "deep-sea-stories@workspace:.": version: 0.0.0-use.local resolution: "deep-sea-stories@workspace:." @@ -722,6 +1642,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.218": + version: 1.5.227 + resolution: "electron-to-chromium@npm:1.5.227" + checksum: 10c0/6b220ea024bcdd1560ffaca6b6b4c220d789b3e9c580c37509e8c176f369c93a4de8497a6e25cbfd9619ab9d129069368e4a4317dec0335d3a0cb61c2353e6f1 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -803,7 +1730,7 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:~0.25.0": +"esbuild@npm:^0.25.0, esbuild@npm:~0.25.0": version: 0.25.10 resolution: "esbuild@npm:0.25.10" dependencies: @@ -892,6 +1819,155 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 + languageName: node + linkType: hard + +"eslint-plugin-react-hooks@npm:^5.2.0": + version: 5.2.0 + resolution: "eslint-plugin-react-hooks@npm:5.2.0" + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + checksum: 10c0/1c8d50fa5984c6dea32470651807d2922cc3934cf3425e78f84a24c2dfd972e7f019bee84aefb27e0cf2c13fea0ac1d4473267727408feeb1c56333ca1489385 + languageName: node + linkType: hard + +"eslint-plugin-react-refresh@npm:^0.4.20": + version: 0.4.22 + resolution: "eslint-plugin-react-refresh@npm:0.4.22" + peerDependencies: + eslint: ">=8.40" + checksum: 10c0/029cf19dc001c6611c9d8d29421e0c19bbe607f401a739b4049747ce3e7abadb59dea213833886c4259702eb65a2ddbcb9f406b1ccc018acc5a01ec5a62b25f5 + languageName: node + linkType: hard + +"eslint-scope@npm:^8.4.0": + version: 8.4.0 + resolution: "eslint-scope@npm:8.4.0" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 + languageName: node + linkType: hard + +"eslint@npm:^9.36.0": + version: 9.36.0 + resolution: "eslint@npm:9.36.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.8.0" + "@eslint-community/regexpp": "npm:^4.12.1" + "@eslint/config-array": "npm:^0.21.0" + "@eslint/config-helpers": "npm:^0.3.1" + "@eslint/core": "npm:^0.15.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:9.36.0" + "@eslint/plugin-kit": "npm:^0.3.5" + "@humanfs/node": "npm:^0.16.6" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.4.2" + "@types/estree": "npm:^1.0.6" + "@types/json-schema": "npm:^7.0.15" + ajv: "npm:^6.12.4" + chalk: "npm:^4.0.0" + cross-spawn: "npm:^7.0.6" + debug: "npm:^4.3.2" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^8.4.0" + eslint-visitor-keys: "npm:^4.2.1" + espree: "npm:^10.4.0" + esquery: "npm:^1.5.0" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:^8.0.0" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + lodash.merge: "npm:^4.6.2" + minimatch: "npm:^3.1.2" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + bin: + eslint: bin/eslint.js + checksum: 10c0/0e2705a94847813b03f2f3c1367c0708319cbb66458250a09b2d056a088c56e079a1c1d76c44feebf51971d9ce64d010373b2a4f007cd1026fc24f95c89836df + languageName: node + linkType: hard + +"espree@npm:^10.0.1, espree@npm:^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" + dependencies: + acorn: "npm:^8.15.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b + languageName: node + linkType: hard + +"esquery@npm:^1.5.0": + version: 1.6.0 + resolution: "esquery@npm:1.6.0" + dependencies: + estraverse: "npm:^5.1.0" + checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + languageName: node + linkType: hard + +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -913,13 +1989,33 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.3": +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard +"fast-glob@npm:^3.3.2": + version: 3.3.3 + resolution: "fast-glob@npm:3.3.3" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.8" + checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe + languageName: node + linkType: hard + +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b + languageName: node + linkType: hard + "fast-json-stringify@npm:^6.0.0": version: 6.1.1 resolution: "fast-json-stringify@npm:6.1.1" @@ -934,6 +2030,13 @@ __metadata: languageName: node linkType: hard +"fast-levenshtein@npm:^2.0.6": + version: 2.0.6 + resolution: "fast-levenshtein@npm:2.0.6" + checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 + languageName: node + linkType: hard + "fast-querystring@npm:^1.0.0": version: 1.1.2 resolution: "fast-querystring@npm:1.1.2" @@ -1001,7 +2104,7 @@ __metadata: languageName: node linkType: hard -"fastq@npm:^1.17.1": +"fastq@npm:^1.17.1, fastq@npm:^1.6.0": version: 1.19.1 resolution: "fastq@npm:1.19.1" dependencies: @@ -1022,6 +2125,24 @@ __metadata: languageName: node linkType: hard +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" + dependencies: + flat-cache: "npm:^4.0.0" + checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 + languageName: node + linkType: hard + +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 + languageName: node + linkType: hard + "find-my-way@npm:^9.0.0": version: 9.3.0 resolution: "find-my-way@npm:9.3.0" @@ -1033,6 +2154,33 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: "npm:^6.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a + languageName: node + linkType: hard + +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" + dependencies: + flatted: "npm:^3.2.9" + keyv: "npm:^4.5.4" + checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc + languageName: node + linkType: hard + +"flatted@npm:^3.2.9": + version: 3.3.3 + resolution: "flatted@npm:3.3.3" + checksum: 10c0/e957a1c6b0254aa15b8cce8533e24165abd98fadc98575db082b786b5da1b7d72062b81bfdcd1da2f4d46b6ed93bec2434e62333e9b4261d79ef2e75a10dd538 + languageName: node + linkType: hard + "follow-redirects@npm:^1.15.6": version: 1.15.11 resolution: "follow-redirects@npm:1.15.11" @@ -1075,7 +2223,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:~2.3.3": +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -1085,7 +2233,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -1108,6 +2256,13 @@ __metadata: languageName: node linkType: hard +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + languageName: node + linkType: hard + "get-intrinsic@npm:^1.2.6": version: 1.3.1 resolution: "get-intrinsic@npm:1.3.1" @@ -1148,6 +2303,24 @@ __metadata: languageName: node linkType: hard +"glob-parent@npm:^5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: "npm:^4.0.1" + checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee + languageName: node + linkType: hard + +"glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 + languageName: node + linkType: hard + "glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -1164,6 +2337,20 @@ __metadata: languageName: node linkType: hard +"globals@npm:^14.0.0": + version: 14.0.0 + resolution: "globals@npm:14.0.0" + checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d + languageName: node + linkType: hard + +"globals@npm:^16.4.0": + version: 16.4.0 + resolution: "globals@npm:16.4.0" + checksum: 10c0/a14b447a78b664b42f6d324e8675fcae6fe5e57924fecc1f6328dce08af9b2ca3a3138501e1b1f244a49814a732dc60cfc1aa24e714e0b64ac8bd18910bfac90 + languageName: node + linkType: hard + "gopd@npm:^1.2.0": version: 1.2.0 resolution: "gopd@npm:1.2.0" @@ -1178,6 +2365,20 @@ __metadata: languageName: node linkType: hard +"graphemer@npm:^1.4.0": + version: 1.4.0 + resolution: "graphemer@npm:1.4.0" + checksum: 10c0/e951259d8cd2e0d196c72ec711add7115d42eb9a8146c8eeda5b8d3ac91e5dd816b9cd68920726d9fd4490368e7ed86e9c423f40db87e2d8dfafa00fa17c3a31 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 + languageName: node + linkType: hard + "has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" @@ -1246,6 +2447,30 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^5.2.0": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + +"ignore@npm:^7.0.0": + version: 7.0.5 + resolution: "ignore@npm:7.0.5" + checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d + languageName: node + linkType: hard + +"import-fresh@npm:^3.2.1": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" + dependencies: + parent-module: "npm:^1.0.0" + resolve-from: "npm:^4.0.0" + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -1267,6 +2492,13 @@ __metadata: languageName: node linkType: hard +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + languageName: node + linkType: hard + "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -1274,6 +2506,22 @@ __metadata: languageName: node linkType: hard +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -1301,10 +2549,44 @@ __metadata: languageName: node linkType: hard -"joycon@npm:^3.1.1": - version: 3.1.1 - resolution: "joycon@npm:3.1.1" - checksum: 10c0/131fb1e98c9065d067fd49b6e685487ac4ad4d254191d7aa2c9e3b90f4e9ca70430c43cad001602bdbdabcf58717d3b5c5b7461c1bd8e39478c8de706b3fe6ae +"joycon@npm:^3.1.1": + version: 3.1.1 + resolution: "joycon@npm:3.1.1" + checksum: 10c0/131fb1e98c9065d067fd49b6e685487ac4ad4d254191d7aa2c9e3b90f4e9ca70430c43cad001602bdbdabcf58717d3b5c5b7461c1bd8e39478c8de706b3fe6ae + languageName: node + linkType: hard + +"js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + +"js-yaml@npm:^4.1.0": + version: 4.1.0 + resolution: "js-yaml@npm:4.1.0" + dependencies: + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f + languageName: node + linkType: hard + +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 languageName: node linkType: hard @@ -1317,6 +2599,13 @@ __metadata: languageName: node linkType: hard +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce + languageName: node + linkType: hard + "json-schema-traverse@npm:^1.0.0": version: 1.0.0 resolution: "json-schema-traverse@npm:1.0.0" @@ -1324,6 +2613,41 @@ __metadata: languageName: node linkType: hard +"json-stable-stringify-without-jsonify@npm:^1.0.1": + version: 1.0.1 + resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" + checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 + languageName: node + linkType: hard + +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c + languageName: node + linkType: hard + +"keyv@npm:^4.5.4": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e + languageName: node + linkType: hard + +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: "npm:^1.2.1" + type-check: "npm:~0.4.0" + checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e + languageName: node + linkType: hard + "light-my-request@npm:^6.0.0": version: 6.6.0 resolution: "light-my-request@npm:6.6.0" @@ -1335,6 +2659,22 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: "npm:^5.0.0" + checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 + languageName: node + linkType: hard + +"lodash.merge@npm:^4.6.2": + version: 4.6.2 + resolution: "lodash.merge@npm:4.6.2" + checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -1342,6 +2682,15 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + languageName: node + linkType: hard + "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" @@ -1368,6 +2717,23 @@ __metadata: languageName: node linkType: hard +"merge2@npm:^1.3.0": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb + languageName: node + linkType: hard + +"micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -1384,6 +2750,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -1483,6 +2858,22 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.11": + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b + languageName: node + linkType: hard + +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 + languageName: node + linkType: hard + "negotiator@npm:^1.0.0": version: 1.0.0 resolution: "negotiator@npm:1.0.0" @@ -1510,6 +2901,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.21": + version: 2.0.21 + resolution: "node-releases@npm:2.0.21" + checksum: 10c0/0eb94916eeebbda9d51da6a9ea47428a12b2bb0dd94930c949632b0c859356abf53b2e5a2792021f96c5fda4f791a8e195f2375b78ae7dba8d8bc3141baa1469 + languageName: node + linkType: hard + "nopt@npm:^8.0.0": version: 8.1.0 resolution: "nopt@npm:8.1.0" @@ -1537,6 +2935,38 @@ __metadata: languageName: node linkType: hard +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" + dependencies: + deep-is: "npm:^0.1.3" + fast-levenshtein: "npm:^2.0.6" + levn: "npm:^0.4.1" + prelude-ls: "npm:^1.2.1" + type-check: "npm:^0.4.0" + word-wrap: "npm:^1.2.5" + checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 + languageName: node + linkType: hard + +"p-limit@npm:^3.0.2": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: "npm:^0.1.0" + checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a + languageName: node + linkType: hard + +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: "npm:^3.0.2" + checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -1551,6 +2981,22 @@ __metadata: languageName: node linkType: hard +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" + dependencies: + callsites: "npm:^3.0.0" + checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 + languageName: node + linkType: hard + +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b + languageName: node + linkType: hard + "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -1568,6 +3014,20 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be + languageName: node + linkType: hard + "picomatch@npm:^4.0.3": version: 4.0.3 resolution: "picomatch@npm:4.0.3" @@ -1635,6 +3095,24 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.5.6": + version: 8.5.6 + resolution: "postcss@npm:8.5.6" + dependencies: + nanoid: "npm:^3.3.11" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/5127cc7c91ed7a133a1b7318012d8bfa112da9ef092dddf369ae699a1f10ebbd89b1b9f25f3228795b84585c72aabd5ced5fc11f2ba467eedf7b081a66fad024 + languageName: node + linkType: hard + +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd + languageName: node + linkType: hard + "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -1683,6 +3161,20 @@ __metadata: languageName: node linkType: hard +"punycode@npm:^2.1.0": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 + languageName: node + linkType: hard + "quick-format-unescaped@npm:^4.0.3": version: 4.0.4 resolution: "quick-format-unescaped@npm:4.0.4" @@ -1690,6 +3182,31 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:^19.1.1": + version: 19.1.1 + resolution: "react-dom@npm:19.1.1" + dependencies: + scheduler: "npm:^0.26.0" + peerDependencies: + react: ^19.1.1 + checksum: 10c0/8c91198510521299c56e4e8d5e3a4508b2734fb5e52f29eeac33811de64e76fe586ad32c32182e2e84e070d98df67125da346c3360013357228172dbcd20bcdd + languageName: node + linkType: hard + +"react-refresh@npm:^0.17.0": + version: 0.17.0 + resolution: "react-refresh@npm:0.17.0" + checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c + languageName: node + linkType: hard + +"react@npm:^19.1.1": + version: 19.1.1 + resolution: "react@npm:19.1.1" + checksum: 10c0/8c9769a2dfd02e603af6445058325e6c8a24b47b185d0e461f66a6454765ddcaecb3f0a90184836c68bb509f3c38248359edbc42f0d07c23eb500a5c30c87b4e + languageName: node + linkType: hard + "real-require@npm:^0.2.0": version: 0.2.0 resolution: "real-require@npm:0.2.0" @@ -1704,6 +3221,13 @@ __metadata: languageName: node linkType: hard +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 + languageName: node + linkType: hard + "resolve-pkg-maps@npm:^1.0.0": version: 1.0.0 resolution: "resolve-pkg-maps@npm:1.0.0" @@ -1739,6 +3263,96 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.43.0": + version: 4.52.3 + resolution: "rollup@npm:4.52.3" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.52.3" + "@rollup/rollup-android-arm64": "npm:4.52.3" + "@rollup/rollup-darwin-arm64": "npm:4.52.3" + "@rollup/rollup-darwin-x64": "npm:4.52.3" + "@rollup/rollup-freebsd-arm64": "npm:4.52.3" + "@rollup/rollup-freebsd-x64": "npm:4.52.3" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.52.3" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.52.3" + "@rollup/rollup-linux-arm64-gnu": "npm:4.52.3" + "@rollup/rollup-linux-arm64-musl": "npm:4.52.3" + "@rollup/rollup-linux-loong64-gnu": "npm:4.52.3" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.52.3" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.52.3" + "@rollup/rollup-linux-riscv64-musl": "npm:4.52.3" + "@rollup/rollup-linux-s390x-gnu": "npm:4.52.3" + "@rollup/rollup-linux-x64-gnu": "npm:4.52.3" + "@rollup/rollup-linux-x64-musl": "npm:4.52.3" + "@rollup/rollup-openharmony-arm64": "npm:4.52.3" + "@rollup/rollup-win32-arm64-msvc": "npm:4.52.3" + "@rollup/rollup-win32-ia32-msvc": "npm:4.52.3" + "@rollup/rollup-win32-x64-gnu": "npm:4.52.3" + "@rollup/rollup-win32-x64-msvc": "npm:4.52.3" + "@types/estree": "npm:1.0.8" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/5a7a3a2e8c7558df5652ecc126e0d9133df4d58c5a001777377202b52517fa48b43be5e21a2cbab6d85975b765991af72666b5132813da6e86ea47ae963b4e71 + languageName: node + linkType: hard + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: "npm:^1.2.2" + checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 + languageName: node + linkType: hard + "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -1762,6 +3376,13 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.26.0": + version: 0.26.0 + resolution: "scheduler@npm:0.26.0" + checksum: 10c0/5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356 + languageName: node + linkType: hard + "secure-json-parse@npm:^4.0.0": version: 4.0.0 resolution: "secure-json-parse@npm:4.0.0" @@ -1769,6 +3390,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d + languageName: node + linkType: hard + "semver@npm:^7.3.5, semver@npm:^7.6.0": version: 7.7.2 resolution: "semver@npm:7.7.2" @@ -1852,6 +3482,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + "split2@npm:^4.0.0": version: 4.2.0 resolution: "split2@npm:4.2.0" @@ -1908,6 +3545,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd + languageName: node + linkType: hard + "strip-json-comments@npm:^5.0.2": version: 5.0.3 resolution: "strip-json-comments@npm:5.0.3" @@ -1915,6 +3559,15 @@ __metadata: languageName: node linkType: hard +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.5.1 resolution: "tar@npm:7.5.1" @@ -1937,7 +3590,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12": +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" dependencies: @@ -1947,6 +3600,15 @@ __metadata: languageName: node linkType: hard +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 + languageName: node + linkType: hard + "toad-cache@npm:^3.7.0": version: 3.7.0 resolution: "toad-cache@npm:3.7.0" @@ -1954,6 +3616,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^2.1.0": + version: 2.1.0 + resolution: "ts-api-utils@npm:2.1.0" + peerDependencies: + typescript: ">=4.8.4" + checksum: 10c0/9806a38adea2db0f6aa217ccc6bc9c391ddba338a9fe3080676d0d50ed806d305bb90e8cef0276e793d28c8a929f400abb184ddd7ff83a416959c0f4d2ce754f + languageName: node + linkType: hard + "tsx@npm:^4.20.6": version: 4.20.6 resolution: "tsx@npm:4.20.6" @@ -1970,6 +3641,30 @@ __metadata: languageName: node linkType: hard +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" + dependencies: + prelude-ls: "npm:^1.2.1" + checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 + languageName: node + linkType: hard + +"typescript-eslint@npm:^8.44.0": + version: 8.45.0 + resolution: "typescript-eslint@npm:8.45.0" + dependencies: + "@typescript-eslint/eslint-plugin": "npm:8.45.0" + "@typescript-eslint/parser": "npm:8.45.0" + "@typescript-eslint/typescript-estree": "npm:8.45.0" + "@typescript-eslint/utils": "npm:8.45.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/2342b0bffe6f719711adbb42116f90cb1fe1670e2e74dde2739482c9d61c2a975ee16e2d560684613050544b543342ec1b11b46e158a48ecc605f5882d2d5da7 + languageName: node + linkType: hard + "typescript@npm:^5.9.2": version: 5.9.2 resolution: "typescript@npm:5.9.2" @@ -1980,6 +3675,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:~5.8.3": + version: 5.8.3 + resolution: "typescript@npm:5.8.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48 + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A^5.9.2#optional!builtin": version: 5.9.2 resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" @@ -1990,6 +3695,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A~5.8.3#optional!builtin": + version: 5.8.3 + resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb + languageName: node + linkType: hard + "undici-types@npm:~7.12.0": version: 7.12.0 resolution: "undici-types@npm:7.12.0" @@ -2015,6 +3730,29 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.3": + version: 1.1.3 + resolution: "update-browserslist-db@npm:1.1.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/682e8ecbf9de474a626f6462aa85927936cdd256fe584c6df2508b0df9f7362c44c957e9970df55dfe44d3623807d26316ea2c7d26b80bb76a16c56c37233c32 + languageName: node + linkType: hard + +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + languageName: node + linkType: hard + "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -2024,9 +3762,79 @@ __metadata: languageName: node linkType: hard +"vite@npm:^7.1.7": + version: 7.1.7 + resolution: "vite@npm:7.1.7" + dependencies: + esbuild: "npm:^0.25.0" + fdir: "npm:^6.5.0" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.3" + postcss: "npm:^8.5.6" + rollup: "npm:^4.43.0" + tinyglobby: "npm:^0.2.15" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/3f6bd61a65aaa81368f4dda804f0e23b103664724218ccb5a0b1a0c7e284df498107b57ced951dc40ae4c5d472435bc8fb5c836414e729ee7e102809eaf6ff80 + languageName: node + linkType: hard + "web@workspace:packages/web": version: 0.0.0-use.local resolution: "web@workspace:packages/web" + dependencies: + "@eslint/js": "npm:^9.36.0" + "@types/react": "npm:^19.1.13" + "@types/react-dom": "npm:^19.1.9" + "@vitejs/plugin-react": "npm:^5.0.3" + babel-plugin-react-compiler: "npm:^19.1.0-rc.3" + eslint: "npm:^9.36.0" + eslint-plugin-react-hooks: "npm:^5.2.0" + eslint-plugin-react-refresh: "npm:^0.4.20" + globals: "npm:^16.4.0" + react: "npm:^19.1.1" + react-dom: "npm:^19.1.1" + typescript: "npm:~5.8.3" + typescript-eslint: "npm:^8.44.0" + vite: "npm:^7.1.7" languageName: unknown linkType: soft @@ -2052,6 +3860,13 @@ __metadata: languageName: node linkType: hard +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 + languageName: node + linkType: hard + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -2081,6 +3896,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + languageName: node + linkType: hard + "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -2095,6 +3917,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f + languageName: node + linkType: hard + "zod@npm:^4.1.11": version: 4.1.11 resolution: "zod@npm:4.1.11" From 461f466c7277fba08219bfa81f38138012c12401 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:03:18 +0200 Subject: [PATCH 11/65] Use biome --- deep-sea-stories/packages/web/biome.json | 9 ++++++++ .../packages/web/eslint.config.js | 23 ------------------- deep-sea-stories/packages/web/package.json | 9 +------- deep-sea-stories/packages/web/src/App.tsx | 6 ++--- deep-sea-stories/packages/web/src/main.tsx | 1 + .../packages/web/tsconfig.app.json | 3 --- .../packages/web/tsconfig.node.json | 3 --- 7 files changed, 14 insertions(+), 40 deletions(-) create mode 100644 deep-sea-stories/packages/web/biome.json delete mode 100644 deep-sea-stories/packages/web/eslint.config.js diff --git a/deep-sea-stories/packages/web/biome.json b/deep-sea-stories/packages/web/biome.json new file mode 100644 index 0000000..ed43b30 --- /dev/null +++ b/deep-sea-stories/packages/web/biome.json @@ -0,0 +1,9 @@ +{ + "root": false, + "extends": "//", + "linter": { + "domains": { + "react": "recommended" + } + } +} diff --git a/deep-sea-stories/packages/web/eslint.config.js b/deep-sea-stories/packages/web/eslint.config.js deleted file mode 100644 index b19330b..0000000 --- a/deep-sea-stories/packages/web/eslint.config.js +++ /dev/null @@ -1,23 +0,0 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' -import { defineConfig, globalIgnores } from 'eslint/config' - -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - js.configs.recommended, - tseslint.configs.recommended, - reactHooks.configs['recommended-latest'], - reactRefresh.configs.vite, - ], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - }, -]) diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index f38fb3c..20efc2e 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -4,9 +4,8 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "start": "vite", "build": "tsc -b && vite build", - "lint": "eslint .", "preview": "vite preview" }, "dependencies": { @@ -14,17 +13,11 @@ "react-dom": "^19.1.1" }, "devDependencies": { - "@eslint/js": "^9.36.0", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.3", "babel-plugin-react-compiler": "^19.1.0-rc.3", - "eslint": "^9.36.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.4.0", - "typescript": "~5.8.3", - "typescript-eslint": "^8.44.0", "vite": "^7.1.7" } } diff --git a/deep-sea-stories/packages/web/src/App.tsx b/deep-sea-stories/packages/web/src/App.tsx index 3d7ded3..65d3290 100644 --- a/deep-sea-stories/packages/web/src/App.tsx +++ b/deep-sea-stories/packages/web/src/App.tsx @@ -9,16 +9,16 @@ function App() { return ( <>

Vite + React

-

diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index bef5202..9ae3272 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -3,6 +3,7 @@ import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' +// biome-ignore lint/style/noNonNullAssertion: root always exists createRoot(document.getElementById('root')!).render( diff --git a/deep-sea-stories/packages/web/tsconfig.app.json b/deep-sea-stories/packages/web/tsconfig.app.json index a9b5a59..e0d3796 100644 --- a/deep-sea-stories/packages/web/tsconfig.app.json +++ b/deep-sea-stories/packages/web/tsconfig.app.json @@ -1,13 +1,11 @@ { "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "target": "ES2022", "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", "types": ["vite/client"], "skipLibCheck": true, - /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, @@ -15,7 +13,6 @@ "moduleDetection": "force", "noEmit": true, "jsx": "react-jsx", - /* Linting */ "strict": true, "noUnusedLocals": true, diff --git a/deep-sea-stories/packages/web/tsconfig.node.json b/deep-sea-stories/packages/web/tsconfig.node.json index 7a77bab..d5b7c65 100644 --- a/deep-sea-stories/packages/web/tsconfig.node.json +++ b/deep-sea-stories/packages/web/tsconfig.node.json @@ -1,19 +1,16 @@ { "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", "target": "ES2023", "lib": ["ES2023"], "module": "ESNext", "types": [], "skipLibCheck": true, - /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "moduleDetection": "force", "noEmit": true, - /* Linting */ "strict": true, "noUnusedLocals": true, From 049fe438d18613ca5436d617a77811df45d91467 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:09:41 +0200 Subject: [PATCH 12/65] Add build script --- deep-sea-stories/package.json | 41 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index ba030be..b085480 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -1,22 +1,23 @@ { - "name": "deep-sea-stories", - "packageManager": "yarn@4.9.2", - "private": true, - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@biomejs/biome": "2.2.4", - "typescript": "^5.9.2" - }, - "scripts": { - "format": "biome format --write", - "format:check": "biome format", - "lint": "biome lint", - "check": "biome check --write", - "typecheck": "yarn workspaces foreach -A -p run typecheck" - }, - "engines": { - "node": ">= 24.0.0" - } + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4", + "typescript": "^5.9.2" + }, + "scripts": { + "build": "yarn workspaces foreach -A -p run build", + "format": "biome format --write", + "format:check": "biome format", + "lint": "biome lint", + "check": "biome check --write", + "typecheck": "yarn workspaces foreach -A -p run typecheck" + }, + "engines": { + "node": ">= 24.0.0" + } } From 406ea51fd514d39893641bf9bcbfc0ad44d8ed7b Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:14:38 +0200 Subject: [PATCH 13/65] Format --- deep-sea-stories/package.json | 42 +++++----- deep-sea-stories/packages/web/biome.json | 14 ++-- deep-sea-stories/packages/web/package.json | 42 +++++----- deep-sea-stories/packages/web/src/App.css | 42 +++++----- deep-sea-stories/packages/web/src/App.tsx | 70 +++++++++------- deep-sea-stories/packages/web/src/index.css | 84 +++++++++---------- deep-sea-stories/packages/web/src/main.tsx | 16 ++-- .../packages/web/tsconfig.app.json | 46 +++++----- deep-sea-stories/packages/web/tsconfig.json | 10 +-- .../packages/web/tsconfig.node.json | 42 +++++----- deep-sea-stories/packages/web/vite.config.ts | 20 ++--- 11 files changed, 219 insertions(+), 209 deletions(-) diff --git a/deep-sea-stories/package.json b/deep-sea-stories/package.json index b085480..1168ced 100644 --- a/deep-sea-stories/package.json +++ b/deep-sea-stories/package.json @@ -1,23 +1,23 @@ { - "name": "deep-sea-stories", - "packageManager": "yarn@4.9.2", - "private": true, - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@biomejs/biome": "2.2.4", - "typescript": "^5.9.2" - }, - "scripts": { - "build": "yarn workspaces foreach -A -p run build", - "format": "biome format --write", - "format:check": "biome format", - "lint": "biome lint", - "check": "biome check --write", - "typecheck": "yarn workspaces foreach -A -p run typecheck" - }, - "engines": { - "node": ">= 24.0.0" - } + "name": "deep-sea-stories", + "packageManager": "yarn@4.9.2", + "private": true, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@biomejs/biome": "2.2.4", + "typescript": "^5.9.2" + }, + "scripts": { + "build": "yarn workspaces foreach -A -p run build", + "format": "biome format --write", + "format:check": "biome format", + "lint": "biome lint", + "check": "biome check --write", + "typecheck": "yarn workspaces foreach -A -p run typecheck" + }, + "engines": { + "node": ">= 24.0.0" + } } diff --git a/deep-sea-stories/packages/web/biome.json b/deep-sea-stories/packages/web/biome.json index ed43b30..061a384 100644 --- a/deep-sea-stories/packages/web/biome.json +++ b/deep-sea-stories/packages/web/biome.json @@ -1,9 +1,9 @@ { - "root": false, - "extends": "//", - "linter": { - "domains": { - "react": "recommended" - } - } + "root": false, + "extends": "//", + "linter": { + "domains": { + "react": "recommended" + } + } } diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 20efc2e..6366d14 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -1,23 +1,23 @@ { - "name": "web", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "start": "vite", - "build": "tsc -b && vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^19.1.1", - "react-dom": "^19.1.1" - }, - "devDependencies": { - "@types/react": "^19.1.13", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.3", - "babel-plugin-react-compiler": "^19.1.0-rc.3", - "globals": "^16.4.0", - "vite": "^7.1.7" - } + "name": "web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "babel-plugin-react-compiler": "^19.1.0-rc.3", + "globals": "^16.4.0", + "vite": "^7.1.7" + } } diff --git a/deep-sea-stories/packages/web/src/App.css b/deep-sea-stories/packages/web/src/App.css index b9d355d..df674c0 100644 --- a/deep-sea-stories/packages/web/src/App.css +++ b/deep-sea-stories/packages/web/src/App.css @@ -1,42 +1,42 @@ #root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; } .logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; } .logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); + filter: drop-shadow(0 0 2em #646cffaa); } .logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); + filter: drop-shadow(0 0 2em #61dafbaa); } @keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } @media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } } .card { - padding: 2em; + padding: 2em; } .read-the-docs { - color: #888; + color: #888; } diff --git a/deep-sea-stories/packages/web/src/App.tsx b/deep-sea-stories/packages/web/src/App.tsx index 65d3290..c8f1228 100644 --- a/deep-sea-stories/packages/web/src/App.tsx +++ b/deep-sea-stories/packages/web/src/App.tsx @@ -1,35 +1,45 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' +import { useState } from 'react'; +import viteLogo from '/vite.svg'; +import reactLogo from './assets/react.svg'; +import './App.css'; function App() { - const [count, setCount] = useState(0) + const [count, setCount] = useState(0); - return ( - <> -

-

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- - ) + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ); } -export default App +export default App; diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css index 08a3ac9..e543249 100644 --- a/deep-sea-stories/packages/web/src/index.css +++ b/deep-sea-stories/packages/web/src/index.css @@ -1,68 +1,68 @@ :root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; + font-weight: 500; + color: #646cff; + text-decoration: inherit; } a:hover { - color: #535bf2; + color: #535bf2; } body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; } h1 { - font-size: 3.2em; - line-height: 1.1; + font-size: 3.2em; + line-height: 1.1; } button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; } button:hover { - border-color: #646cff; + border-color: #646cff; } button:focus, button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; + outline: 4px auto -webkit-focus-ring-color; } @media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } } diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index 9ae3272..977420d 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -1,11 +1,11 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.tsx' +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import './index.css'; +import App from './App.tsx'; // biome-ignore lint/style/noNonNullAssertion: root always exists createRoot(document.getElementById('root')!).render( - - - , -) + + + , +); diff --git a/deep-sea-stories/packages/web/tsconfig.app.json b/deep-sea-stories/packages/web/tsconfig.app.json index e0d3796..f5e68b3 100644 --- a/deep-sea-stories/packages/web/tsconfig.app.json +++ b/deep-sea-stories/packages/web/tsconfig.app.json @@ -1,25 +1,25 @@ { - "compilerOptions": { - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] } diff --git a/deep-sea-stories/packages/web/tsconfig.json b/deep-sea-stories/packages/web/tsconfig.json index 1ffef60..fb12418 100644 --- a/deep-sea-stories/packages/web/tsconfig.json +++ b/deep-sea-stories/packages/web/tsconfig.json @@ -1,7 +1,7 @@ { - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] } diff --git a/deep-sea-stories/packages/web/tsconfig.node.json b/deep-sea-stories/packages/web/tsconfig.node.json index d5b7c65..76d7fcc 100644 --- a/deep-sea-stories/packages/web/tsconfig.node.json +++ b/deep-sea-stories/packages/web/tsconfig.node.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": [], - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] + "compilerOptions": { + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": [], + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] } diff --git a/deep-sea-stories/packages/web/vite.config.ts b/deep-sea-stories/packages/web/vite.config.ts index 4efe189..ca79347 100644 --- a/deep-sea-stories/packages/web/vite.config.ts +++ b/deep-sea-stories/packages/web/vite.config.ts @@ -1,13 +1,13 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; // https://vite.dev/config/ export default defineConfig({ - plugins: [ - react({ - babel: { - plugins: [['babel-plugin-react-compiler']], - }, - }), - ], -}) + plugins: [ + react({ + babel: { + plugins: [['babel-plugin-react-compiler']], + }, + }), + ], +}); From 98d36d6ecf190f3fc3093682485376be3551fda9 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:40:12 +0200 Subject: [PATCH 14/65] Setup tRPC in the backend --- .../packages/backend/package.json | 3 +- .../packages/backend/src/config.ts | 14 +- .../packages/backend/src/context.ts | 15 + .../packages/backend/src/controllers/rooms.ts | 18 +- deep-sea-stories/packages/backend/src/main.ts | 36 +- .../packages/backend/src/plugins/fishjam.ts | 29 - .../packages/backend/src/router.ts | 9 + .../packages/backend/src/routes/index.ts | 6 - .../packages/backend/src/routes/rooms.ts | 38 - .../packages/backend/src/schemas.ts | 9 +- deep-sea-stories/packages/backend/src/trpc.ts | 7 + deep-sea-stories/yarn.lock | 1019 +---------------- 12 files changed, 80 insertions(+), 1123 deletions(-) create mode 100644 deep-sea-stories/packages/backend/src/context.ts delete mode 100644 deep-sea-stories/packages/backend/src/plugins/fishjam.ts create mode 100644 deep-sea-stories/packages/backend/src/router.ts delete mode 100644 deep-sea-stories/packages/backend/src/routes/index.ts delete mode 100644 deep-sea-stories/packages/backend/src/routes/rooms.ts create mode 100644 deep-sea-stories/packages/backend/src/trpc.ts diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 19c4ddb..f54381f 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -5,10 +5,9 @@ "type": "module", "dependencies": { "@fishjam-cloud/js-server-sdk": "^0.21.0", + "@trpc/server": "^11.6.0", "dotenv": "^17.2.3", "fastify": "^5.6.1", - "fastify-plugin": "^5.1.0", - "fastify-type-provider-zod": "^6.0.0", "pino-pretty": "^13.1.1", "zod": "^4.1.11" }, diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index 0ce6b5c..da84587 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -1,16 +1,8 @@ import dotenv from 'dotenv'; -import type { FastifyInstance } from 'fastify'; -import fp from 'fastify-plugin'; import z from 'zod'; dotenv.config(); -declare module 'fastify' { - interface FastifyInstance { - config: ConfigSchema; - } -} - export const configSchema = z.object({ PORT: z.coerce.number().int().default(8000), FISHJAM_ID: z.string(), @@ -18,8 +10,4 @@ export const configSchema = z.object({ FISHJAM_MANAGEMENT_TOKEN: z.string(), }); -type ConfigSchema = z.infer; - -export const fastifyConfig = fp((fastify: FastifyInstance) => { - fastify.decorate('config', configSchema.parse(process.env)); -}); +export const CONFIG = configSchema.parse(process.env); diff --git a/deep-sea-stories/packages/backend/src/context.ts b/deep-sea-stories/packages/backend/src/context.ts new file mode 100644 index 0000000..eafc6a5 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/context.ts @@ -0,0 +1,15 @@ +import { FishjamClient } from '@fishjam-cloud/js-server-sdk'; +import type { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify'; +import { CONFIG } from './config.js'; + +const fishjam = new FishjamClient({ + fishjamId: CONFIG.FISHJAM_ID, + fishjamUrl: CONFIG.FISHJAM_URL, + managementToken: CONFIG.FISHJAM_MANAGEMENT_TOKEN, +}); + +export function createContext({ req, res }: CreateFastifyContextOptions) { + return { req, res, fishjam }; +} + +export type Context = Awaited>; diff --git a/deep-sea-stories/packages/backend/src/controllers/rooms.ts b/deep-sea-stories/packages/backend/src/controllers/rooms.ts index f4def30..0cc1a1f 100644 --- a/deep-sea-stories/packages/backend/src/controllers/rooms.ts +++ b/deep-sea-stories/packages/backend/src/controllers/rooms.ts @@ -1,9 +1,13 @@ -import type { FishjamClient, RoomId } from '@fishjam-cloud/js-server-sdk'; +import type { RoomId } from '@fishjam-cloud/js-server-sdk'; +import { getRoomInputSchema } from '../schemas.js'; +import { publicProcedure } from '../trpc.js'; -export async function createRoom(fishjam: FishjamClient) { - return await fishjam.createRoom(); -} +export const createRoom = publicProcedure.mutation(async ({ ctx }) => { + return await ctx.fishjam.createRoom(); +}); -export async function getRoom(fishjam: FishjamClient, roomId: RoomId) { - return await fishjam.getRoom(roomId); -} +export const getRoom = publicProcedure + .input(getRoomInputSchema) + .query(async ({ ctx, input }) => { + return await ctx.fishjam.getRoom(input.roomId as RoomId); + }); diff --git a/deep-sea-stories/packages/backend/src/main.ts b/deep-sea-stories/packages/backend/src/main.ts index a2bc43c..04df58a 100644 --- a/deep-sea-stories/packages/backend/src/main.ts +++ b/deep-sea-stories/packages/backend/src/main.ts @@ -1,28 +1,30 @@ -import Fastify from 'fastify'; import { - serializerCompiler, - validatorCompiler, - type ZodTypeProvider, -} from 'fastify-type-provider-zod'; -import { fastifyConfig } from './config.js'; -import { fishjamPlugin } from './plugins/fishjam.js'; -import routes from './routes/index.js'; + type FastifyTRPCPluginOptions, + fastifyTRPCPlugin, +} from '@trpc/server/adapters/fastify'; +import Fastify from 'fastify'; +import { CONFIG } from './config.js'; +import { createContext } from './context.js'; +import { type AppRouter, appRouter } from './router.js'; const fastify = Fastify({ logger: { transport: { target: 'pino-pretty' } }, -}).withTypeProvider(); - -fastify.setValidatorCompiler(validatorCompiler); -fastify.setSerializerCompiler(serializerCompiler); - -fastify.register(fastifyConfig); -fastify.register(fishjamPlugin); +}); -fastify.register(routes, { prefix: '/api/v1' }); +fastify.register(fastifyTRPCPlugin, { + prefix: '/api/v1', + trpcOptions: { + router: appRouter, + createContext, + onError({ path, error }) { + fastify.log.error('Error in tRPC handler on path %s: %O', path, error); + }, + } satisfies FastifyTRPCPluginOptions['trpcOptions'], +}); try { await fastify.ready(); - await fastify.listen({ port: fastify.config.PORT }); + await fastify.listen({ port: CONFIG.PORT }); } catch (err) { fastify.log.error(err); process.exit(1); diff --git a/deep-sea-stories/packages/backend/src/plugins/fishjam.ts b/deep-sea-stories/packages/backend/src/plugins/fishjam.ts deleted file mode 100644 index 3754811..0000000 --- a/deep-sea-stories/packages/backend/src/plugins/fishjam.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { - FishjamBaseException, - FishjamClient, -} from '@fishjam-cloud/js-server-sdk'; -import type { FastifyInstance } from 'fastify'; -import fp from 'fastify-plugin'; - -declare module 'fastify' { - interface FastifyInstance { - fishjam: FishjamClient; - } -} - -export const fishjamPlugin = fp(async (fastify: FastifyInstance) => { - const fishjamClient = new FishjamClient({ - fishjamId: fastify.config.FISHJAM_ID, - fishjamUrl: fastify.config.FISHJAM_URL, - managementToken: fastify.config.FISHJAM_MANAGEMENT_TOKEN, - }); - - try { - await fishjamClient.getAllRooms(); - } catch (e) { - if (e instanceof FishjamBaseException) - throw Error('Invalid Fishjam configuration provided.'); - } - - fastify.decorate('fishjam', fishjamClient); -}); diff --git a/deep-sea-stories/packages/backend/src/router.ts b/deep-sea-stories/packages/backend/src/router.ts new file mode 100644 index 0000000..8f11005 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/router.ts @@ -0,0 +1,9 @@ +import { createRoom, getRoom } from './controllers/rooms.js'; +import { router } from './trpc.js'; + +export const appRouter = router({ + createRoom, + getRoom, +}); + +export type AppRouter = typeof appRouter; diff --git a/deep-sea-stories/packages/backend/src/routes/index.ts b/deep-sea-stories/packages/backend/src/routes/index.ts deleted file mode 100644 index 5ecf82e..0000000 --- a/deep-sea-stories/packages/backend/src/routes/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { FastifyInstance } from 'fastify'; -import rooms from './rooms.js'; - -export default function routes(fastify: FastifyInstance) { - fastify.register(rooms, { prefix: '/rooms' }); -} diff --git a/deep-sea-stories/packages/backend/src/routes/rooms.ts b/deep-sea-stories/packages/backend/src/routes/rooms.ts deleted file mode 100644 index 96e5612..0000000 --- a/deep-sea-stories/packages/backend/src/routes/rooms.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { RoomId } from '@fishjam-cloud/js-server-sdk'; -import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod'; -import z from 'zod'; -import { createRoom, getRoom } from '../controllers/rooms.js'; -import { roomSchema } from '../schemas.js'; - -const routes: FastifyPluginAsyncZod = async (fastify) => { - fastify.post( - '/', - { - schema: { - response: { - 201: roomSchema, - }, - }, - }, - async () => { - return await createRoom(fastify.fishjam); - }, - ); - - fastify.get( - '/:roomId', - { - schema: { - params: z.object({ - roomId: z.string(), - }), - response: { - 200: roomSchema, - }, - }, - }, - async (req) => await getRoom(fastify.fishjam, req.params.roomId as RoomId), - ); -}; - -export default routes; diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts index 796d85e..a4f162c 100644 --- a/deep-sea-stories/packages/backend/src/schemas.ts +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -1,10 +1,3 @@ import z from 'zod'; -export const peerSchema = z.object({ - id: z.string(), -}); - -export const roomSchema = z.object({ - id: z.string(), - peers: peerSchema.array(), -}); +export const getRoomInputSchema = z.object({ roomId: z.string() }); diff --git a/deep-sea-stories/packages/backend/src/trpc.ts b/deep-sea-stories/packages/backend/src/trpc.ts new file mode 100644 index 0000000..c745c90 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/trpc.ts @@ -0,0 +1,7 @@ +import { initTRPC } from '@trpc/server'; +import type { Context } from './context.js'; + +const t = initTRPC.context().create(); + +export const router = t.router; +export const publicProcedure = t.procedure; diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 42a149f..a085eb0 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -482,92 +482,6 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.7.0, @eslint-community/eslint-utils@npm:^4.8.0": - version: 4.9.0 - resolution: "@eslint-community/eslint-utils@npm:4.9.0" - dependencies: - eslint-visitor-keys: "npm:^3.4.3" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.12.1": - version: 4.12.1 - resolution: "@eslint-community/regexpp@npm:4.12.1" - checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 - languageName: node - linkType: hard - -"@eslint/config-array@npm:^0.21.0": - version: 0.21.0 - resolution: "@eslint/config-array@npm:0.21.0" - dependencies: - "@eslint/object-schema": "npm:^2.1.6" - debug: "npm:^4.3.1" - minimatch: "npm:^3.1.2" - checksum: 10c0/0ea801139166c4aa56465b309af512ef9b2d3c68f9198751bbc3e21894fe70f25fbf26e1b0e9fffff41857bc21bfddeee58649ae6d79aadcd747db0c5dca771f - languageName: node - linkType: hard - -"@eslint/config-helpers@npm:^0.3.1": - version: 0.3.1 - resolution: "@eslint/config-helpers@npm:0.3.1" - checksum: 10c0/f6c5b3a0b76a0d7d84cc93e310c259e6c3e0792ddd0a62c5fc0027796ffae44183432cb74b2c2b1162801ee1b1b34a6beb5d90a151632b4df7349f994146a856 - languageName: node - linkType: hard - -"@eslint/core@npm:^0.15.2": - version: 0.15.2 - resolution: "@eslint/core@npm:0.15.2" - dependencies: - "@types/json-schema": "npm:^7.0.15" - checksum: 10c0/c17a6dc4f5a6006ecb60165cc38bcd21fefb4a10c7a2578a0cfe5813bbd442531a87ed741da5adab5eb678e8e693fda2e2b14555b035355537e32bcec367ea17 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^3.3.1": - version: 3.3.1 - resolution: "@eslint/eslintrc@npm:3.3.1" - dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.3.2" - espree: "npm:^10.0.1" - globals: "npm:^14.0.0" - ignore: "npm:^5.2.0" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" - minimatch: "npm:^3.1.2" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/b0e63f3bc5cce4555f791a4e487bf999173fcf27c65e1ab6e7d63634d8a43b33c3693e79f192cbff486d7df1be8ebb2bd2edc6e70ddd486cbfa84a359a3e3b41 - languageName: node - linkType: hard - -"@eslint/js@npm:9.36.0, @eslint/js@npm:^9.36.0": - version: 9.36.0 - resolution: "@eslint/js@npm:9.36.0" - checksum: 10c0/e3f6fb7d6f117d79615574f7bef4f238bcfed6ece0465d28226c3a75d2b6fac9cc189121e8673562796ca8ccea2bf9861715ee5cf4a3dbef87d17811c0dac22c - languageName: node - linkType: hard - -"@eslint/object-schema@npm:^2.1.6": - version: 2.1.6 - resolution: "@eslint/object-schema@npm:2.1.6" - checksum: 10c0/b8cdb7edea5bc5f6a96173f8d768d3554a628327af536da2fc6967a93b040f2557114d98dbcdbf389d5a7b290985ad6a9ce5babc547f36fc1fde42e674d11a56 - languageName: node - linkType: hard - -"@eslint/plugin-kit@npm:^0.3.5": - version: 0.3.5 - resolution: "@eslint/plugin-kit@npm:0.3.5" - dependencies: - "@eslint/core": "npm:^0.15.2" - levn: "npm:^0.4.1" - checksum: 10c0/c178c1b58c574200c0fd125af3e4bc775daba7ce434ba6d1eeaf9bcb64b2e9fea75efabffb3ed3ab28858e55a016a5efa95f509994ee4341b341199ca630b89e - languageName: node - linkType: hard - "@fastify/ajv-compiler@npm:^4.0.0": version: 4.0.2 resolution: "@fastify/ajv-compiler@npm:4.0.2" @@ -579,7 +493,7 @@ __metadata: languageName: node linkType: hard -"@fastify/error@npm:^4.0.0, @fastify/error@npm:^4.2.0": +"@fastify/error@npm:^4.0.0": version: 4.2.0 resolution: "@fastify/error@npm:4.2.0" checksum: 10c0/8bdafe95b368a71dfc5644ef22e0a2412dfbb2f300cf4658fdbd9035c96d7c034c53fd7d38e1150437d9cf7a2d75e6bd05e458cf9ba5f2e47e527df8a5e0bd4e @@ -631,37 +545,6 @@ __metadata: languageName: node linkType: hard -"@humanfs/core@npm:^0.19.1": - version: 0.19.1 - resolution: "@humanfs/core@npm:0.19.1" - checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 - languageName: node - linkType: hard - -"@humanfs/node@npm:^0.16.6": - version: 0.16.7 - resolution: "@humanfs/node@npm:0.16.7" - dependencies: - "@humanfs/core": "npm:^0.19.1" - "@humanwhocodes/retry": "npm:^0.4.0" - checksum: 10c0/9f83d3cf2cfa37383e01e3cdaead11cd426208e04c44adcdd291aa983aaf72d7d3598844d2fe9ce54896bb1bf8bd4b56883376611c8905a19c44684642823f30 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 - languageName: node - linkType: hard - -"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": - version: 0.4.3 - resolution: "@humanwhocodes/retry@npm:0.4.3" - checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 - languageName: node - linkType: hard - "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -729,33 +612,6 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 - languageName: node - linkType: hard - "@npmcli/agent@npm:^3.0.0": version: 3.0.0 resolution: "@npmcli/agent@npm:3.0.0" @@ -946,6 +802,15 @@ __metadata: languageName: node linkType: hard +"@trpc/server@npm:^11.6.0": + version: 11.6.0 + resolution: "@trpc/server@npm:11.6.0" + peerDependencies: + typescript: ">=5.7.2" + checksum: 10c0/a9f957e276e5e78cf0495d4b9db73d6edd4dab7d269ac281c8074cde31162beace6c47be7b0871ba85a56ea2a92933d42c460cc59ea657f56db5064ee20399b5 + languageName: node + linkType: hard + "@tsconfig/node24@npm:^24.0.1": version: 24.0.1 resolution: "@tsconfig/node24@npm:24.0.1" @@ -994,20 +859,13 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.6": +"@types/estree@npm:1.0.8": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 languageName: node linkType: hard -"@types/json-schema@npm:^7.0.15": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db - languageName: node - linkType: hard - "@types/node@npm:^24.5.2": version: 24.5.2 resolution: "@types/node@npm:24.5.2" @@ -1035,143 +893,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.45.0" - dependencies: - "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.45.0" - "@typescript-eslint/type-utils": "npm:8.45.0" - "@typescript-eslint/utils": "npm:8.45.0" - "@typescript-eslint/visitor-keys": "npm:8.45.0" - graphemer: "npm:^1.4.0" - ignore: "npm:^7.0.0" - natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - "@typescript-eslint/parser": ^8.45.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/0c60a0e5d07fa8618348db38b5a81e66143d528e1b3cdb5678bbc6c60590cd559b27c98c36f5663230fc4cf6920dff2cd604de30b58df26a37fcfcc5dc1dbd45 - languageName: node - linkType: hard - -"@typescript-eslint/parser@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/parser@npm:8.45.0" - dependencies: - "@typescript-eslint/scope-manager": "npm:8.45.0" - "@typescript-eslint/types": "npm:8.45.0" - "@typescript-eslint/typescript-estree": "npm:8.45.0" - "@typescript-eslint/visitor-keys": "npm:8.45.0" - debug: "npm:^4.3.4" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/8b419bcf795b112a39fcac05dcf147835059345b6399035ffa3f76a9d8e320f3fac79cae2fe4320dcda83fa059b017ca7626a7b4e3da08a614415c8867d169b8 - languageName: node - linkType: hard - -"@typescript-eslint/project-service@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/project-service@npm:8.45.0" - dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.45.0" - "@typescript-eslint/types": "npm:^8.45.0" - debug: "npm:^4.3.4" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/98af065a1a3ed9d3d1eb265e09d3e9c2ae676d500a8c1d764f5609fe2c1b86749516b709804eb814fae688be7809d11748b9ae691d43c28da51dac390ca81fa9 - languageName: node - linkType: hard - -"@typescript-eslint/scope-manager@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/scope-manager@npm:8.45.0" - dependencies: - "@typescript-eslint/types": "npm:8.45.0" - "@typescript-eslint/visitor-keys": "npm:8.45.0" - checksum: 10c0/54cd36206f6b4fc8e1e48576ed01e0d6ab20c2a9c4c7d90d5cc3a2d317dd8a13abe148ffecf471b16f1224aba5749e0905472745626bef9ae5bed771776f4abe - languageName: node - linkType: hard - -"@typescript-eslint/tsconfig-utils@npm:8.45.0, @typescript-eslint/tsconfig-utils@npm:^8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.45.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/227a9b7a5baaf35466fd369992cb933192515df1156ddf22f438deb344c2523695208e1036f5590b20603f31724de75a47fe0ee84e2fd4c8e9f3606f23f68112 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/type-utils@npm:8.45.0" - dependencies: - "@typescript-eslint/types": "npm:8.45.0" - "@typescript-eslint/typescript-estree": "npm:8.45.0" - "@typescript-eslint/utils": "npm:8.45.0" - debug: "npm:^4.3.4" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/ce0f4c209c2418ebeb65e7de053499fb68bf6000bdd71068594fdb8c8ac3dbbd62935a3cea233989491f7da3ef5db87e7efd2910133c6abf6d0cbf57248f6442 - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:8.45.0, @typescript-eslint/types@npm:^8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/types@npm:8.45.0" - checksum: 10c0/0213a0573c671d13bc91961a2b2e814ec7f6381ff093bce6704017bd96b2fc7fee25906c815cedb32a0601cf5071ca6c7c5f940d087c3b0d3dd7d4bc03478278 - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.45.0" - dependencies: - "@typescript-eslint/project-service": "npm:8.45.0" - "@typescript-eslint/tsconfig-utils": "npm:8.45.0" - "@typescript-eslint/types": "npm:8.45.0" - "@typescript-eslint/visitor-keys": "npm:8.45.0" - debug: "npm:^4.3.4" - fast-glob: "npm:^3.3.2" - is-glob: "npm:^4.0.3" - minimatch: "npm:^9.0.4" - semver: "npm:^7.6.0" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/8c2f44a00fe859a6cd4b50157c484c5b6a1c7af5d48e89ae79c5f4924947964962fc8f478ad4c2ade788907fceee9b72d4e376508ea79b51392f91082a37d239 - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/utils@npm:8.45.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.7.0" - "@typescript-eslint/scope-manager": "npm:8.45.0" - "@typescript-eslint/types": "npm:8.45.0" - "@typescript-eslint/typescript-estree": "npm:8.45.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/b3c83a23813b15e20e303d7153789508c01e06dec355b1a80547c59aa36998d498102f45fcd13f111031fac57270608abb04d20560248d4448fd00b1cf4dc4ab - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:8.45.0": - version: 8.45.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.45.0" - dependencies: - "@typescript-eslint/types": "npm:8.45.0" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/119adcf50c902dad7f7757bcdd88fad0a23a171d309d9b7cefe78af12e451cf84c04ae611f4c31f7e23f16c2b47665ad92e6e5648fc77d542ef306f465bf1f29 - languageName: node - linkType: hard - "@vitejs/plugin-react@npm:^5.0.3": version: 5.0.4 resolution: "@vitejs/plugin-react@npm:5.0.4" @@ -1202,24 +923,6 @@ __metadata: languageName: node linkType: hard -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 - languageName: node - linkType: hard - -"acorn@npm:^8.15.0": - version: 8.15.0 - resolution: "acorn@npm:8.15.0" - bin: - acorn: bin/acorn - checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec - languageName: node - linkType: hard - "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -1241,18 +944,6 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 - languageName: node - linkType: hard - "ajv@npm:^8.0.0, ajv@npm:^8.12.0": version: 8.17.1 resolution: "ajv@npm:8.17.1" @@ -1279,7 +970,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^4.0.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1295,13 +986,6 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e - languageName: node - linkType: hard - "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -1365,12 +1049,11 @@ __metadata: resolution: "backend@workspace:packages/backend" dependencies: "@fishjam-cloud/js-server-sdk": "npm:^0.21.0" + "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" "@types/node": "npm:^24.5.2" dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" - fastify-plugin: "npm:^5.1.0" - fastify-type-provider-zod: "npm:^6.0.0" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" zod: "npm:^4.1.11" @@ -1393,16 +1076,6 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^1.1.7": - version: 1.1.12 - resolution: "brace-expansion@npm:1.1.12" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10c0/975fecac2bb7758c062c20d0b3b6288c7cc895219ee25f0a64a9de662dbac981ff0b6e89909c3897c1f84fa353113a721923afdec5f8b2350255b097f12b1f73 - languageName: node - linkType: hard - "brace-expansion@npm:^2.0.1": version: 2.0.2 resolution: "brace-expansion@npm:2.0.2" @@ -1412,15 +1085,6 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.3": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 - languageName: node - linkType: hard - "browserslist@npm:^4.24.0": version: 4.26.2 resolution: "browserslist@npm:4.26.2" @@ -1466,13 +1130,6 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 - languageName: node - linkType: hard - "caniuse-lite@npm:^1.0.30001741": version: 1.0.30001746 resolution: "caniuse-lite@npm:1.0.30001746" @@ -1480,16 +1137,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -1529,13 +1176,6 @@ __metadata: languageName: node linkType: hard -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f - languageName: node - linkType: hard - "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -1575,7 +1215,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -1587,13 +1227,6 @@ __metadata: languageName: node linkType: hard -"deep-is@npm:^0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c - languageName: node - linkType: hard - "deep-sea-stories@workspace:.": version: 0.0.0-use.local resolution: "deep-sea-stories@workspace:." @@ -1826,148 +1459,6 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^5.2.0": - version: 5.2.0 - resolution: "eslint-plugin-react-hooks@npm:5.2.0" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - checksum: 10c0/1c8d50fa5984c6dea32470651807d2922cc3934cf3425e78f84a24c2dfd972e7f019bee84aefb27e0cf2c13fea0ac1d4473267727408feeb1c56333ca1489385 - languageName: node - linkType: hard - -"eslint-plugin-react-refresh@npm:^0.4.20": - version: 0.4.22 - resolution: "eslint-plugin-react-refresh@npm:0.4.22" - peerDependencies: - eslint: ">=8.40" - checksum: 10c0/029cf19dc001c6611c9d8d29421e0c19bbe607f401a739b4049747ce3e7abadb59dea213833886c4259702eb65a2ddbcb9f406b1ccc018acc5a01ec5a62b25f5 - languageName: node - linkType: hard - -"eslint-scope@npm:^8.4.0": - version: 8.4.0 - resolution: "eslint-scope@npm:8.4.0" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^5.2.0" - checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^4.2.1": - version: 4.2.1 - resolution: "eslint-visitor-keys@npm:4.2.1" - checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 - languageName: node - linkType: hard - -"eslint@npm:^9.36.0": - version: 9.36.0 - resolution: "eslint@npm:9.36.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.8.0" - "@eslint-community/regexpp": "npm:^4.12.1" - "@eslint/config-array": "npm:^0.21.0" - "@eslint/config-helpers": "npm:^0.3.1" - "@eslint/core": "npm:^0.15.2" - "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.36.0" - "@eslint/plugin-kit": "npm:^0.3.5" - "@humanfs/node": "npm:^0.16.6" - "@humanwhocodes/module-importer": "npm:^1.0.1" - "@humanwhocodes/retry": "npm:^0.4.2" - "@types/estree": "npm:^1.0.6" - "@types/json-schema": "npm:^7.0.15" - ajv: "npm:^6.12.4" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.6" - debug: "npm:^4.3.2" - escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^8.4.0" - eslint-visitor-keys: "npm:^4.2.1" - espree: "npm:^10.4.0" - esquery: "npm:^1.5.0" - esutils: "npm:^2.0.2" - fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^8.0.0" - find-up: "npm:^5.0.0" - glob-parent: "npm:^6.0.2" - ignore: "npm:^5.2.0" - imurmurhash: "npm:^0.1.4" - is-glob: "npm:^4.0.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.3" - peerDependencies: - jiti: "*" - peerDependenciesMeta: - jiti: - optional: true - bin: - eslint: bin/eslint.js - checksum: 10c0/0e2705a94847813b03f2f3c1367c0708319cbb66458250a09b2d056a088c56e079a1c1d76c44feebf51971d9ce64d010373b2a4f007cd1026fc24f95c89836df - languageName: node - linkType: hard - -"espree@npm:^10.0.1, espree@npm:^10.4.0": - version: 10.4.0 - resolution: "espree@npm:10.4.0" - dependencies: - acorn: "npm:^8.15.0" - acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b - languageName: node - linkType: hard - -"esquery@npm:^1.5.0": - version: 1.6.0 - resolution: "esquery@npm:1.6.0" - dependencies: - estraverse: "npm:^5.1.0" - checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -1989,33 +1480,13 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": +"fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard -"fast-glob@npm:^3.3.2": - version: 3.3.3 - resolution: "fast-glob@npm:3.3.3" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.8" - checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b - languageName: node - linkType: hard - "fast-json-stringify@npm:^6.0.0": version: 6.1.1 resolution: "fast-json-stringify@npm:6.1.1" @@ -2030,13 +1501,6 @@ __metadata: languageName: node linkType: hard -"fast-levenshtein@npm:^2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 - languageName: node - linkType: hard - "fast-querystring@npm:^1.0.0": version: 1.1.2 resolution: "fast-querystring@npm:1.1.2" @@ -2060,27 +1524,6 @@ __metadata: languageName: node linkType: hard -"fastify-plugin@npm:^5.1.0": - version: 5.1.0 - resolution: "fastify-plugin@npm:5.1.0" - checksum: 10c0/61b330b8cb03a3581b796d745137499a782934abcf65dbf9a41d07248520cfd220b3ae8b16afeaf81af712e68e1ac24352895132cfeb2b372c66662c0170f365 - languageName: node - linkType: hard - -"fastify-type-provider-zod@npm:^6.0.0": - version: 6.0.0 - resolution: "fastify-type-provider-zod@npm:6.0.0" - dependencies: - "@fastify/error": "npm:^4.2.0" - peerDependencies: - "@fastify/swagger": ">=9.5.1" - fastify: ^5.0.0 - openapi-types: ^12.1.3 - zod: ">=4.1.5" - checksum: 10c0/222a32de89ad5a3d15cdb3536c004d7b36b5f969fb34ffaeda35f06a03fc9ca31dd8045bdb3b61c6c72259fd7b4d3654e2ce886d0e193036fde47eab17f4f1b6 - languageName: node - linkType: hard - "fastify@npm:^5.6.1": version: 5.6.1 resolution: "fastify@npm:5.6.1" @@ -2104,7 +1547,7 @@ __metadata: languageName: node linkType: hard -"fastq@npm:^1.17.1, fastq@npm:^1.6.0": +"fastq@npm:^1.17.1": version: 1.19.1 resolution: "fastq@npm:1.19.1" dependencies: @@ -2125,24 +1568,6 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^8.0.0": - version: 8.0.0 - resolution: "file-entry-cache@npm:8.0.0" - dependencies: - flat-cache: "npm:^4.0.0" - checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 - languageName: node - linkType: hard - "find-my-way@npm:^9.0.0": version: 9.3.0 resolution: "find-my-way@npm:9.3.0" @@ -2154,33 +1579,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: "npm:^6.0.0" - path-exists: "npm:^4.0.0" - checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a - languageName: node - linkType: hard - -"flat-cache@npm:^4.0.0": - version: 4.0.1 - resolution: "flat-cache@npm:4.0.1" - dependencies: - flatted: "npm:^3.2.9" - keyv: "npm:^4.5.4" - checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc - languageName: node - linkType: hard - -"flatted@npm:^3.2.9": - version: 3.3.3 - resolution: "flatted@npm:3.3.3" - checksum: 10c0/e957a1c6b0254aa15b8cce8533e24165abd98fadc98575db082b786b5da1b7d72062b81bfdcd1da2f4d46b6ed93bec2434e62333e9b4261d79ef2e75a10dd538 - languageName: node - linkType: hard - "follow-redirects@npm:^1.15.6": version: 1.15.11 resolution: "follow-redirects@npm:1.15.11" @@ -2303,24 +1701,6 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: "npm:^4.0.3" - checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 - languageName: node - linkType: hard - "glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -2337,13 +1717,6 @@ __metadata: languageName: node linkType: hard -"globals@npm:^14.0.0": - version: 14.0.0 - resolution: "globals@npm:14.0.0" - checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d - languageName: node - linkType: hard - "globals@npm:^16.4.0": version: 16.4.0 resolution: "globals@npm:16.4.0" @@ -2365,20 +1738,6 @@ __metadata: languageName: node linkType: hard -"graphemer@npm:^1.4.0": - version: 1.4.0 - resolution: "graphemer@npm:1.4.0" - checksum: 10c0/e951259d8cd2e0d196c72ec711add7115d42eb9a8146c8eeda5b8d3ac91e5dd816b9cd68920726d9fd4490368e7ed86e9c423f40db87e2d8dfafa00fa17c3a31 - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 - languageName: node - linkType: hard - "has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" @@ -2447,30 +1806,6 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 - languageName: node - linkType: hard - -"ignore@npm:^7.0.0": - version: 7.0.5 - resolution: "ignore@npm:7.0.5" - checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d - languageName: node - linkType: hard - -"import-fresh@npm:^3.2.1": - version: 3.3.1 - resolution: "import-fresh@npm:3.3.1" - dependencies: - parent-module: "npm:^1.0.0" - resolve-from: "npm:^4.0.0" - checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec - languageName: node - linkType: hard - "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -2492,13 +1827,6 @@ __metadata: languageName: node linkType: hard -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -2506,22 +1834,6 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -2563,17 +1875,6 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" - dependencies: - argparse: "npm:^2.0.1" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f - languageName: node - linkType: hard - "jsesc@npm:^3.0.2": version: 3.1.0 resolution: "jsesc@npm:3.1.0" @@ -2583,13 +1884,6 @@ __metadata: languageName: node linkType: hard -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 - languageName: node - linkType: hard - "json-schema-ref-resolver@npm:^3.0.0": version: 3.0.0 resolution: "json-schema-ref-resolver@npm:3.0.0" @@ -2599,13 +1893,6 @@ __metadata: languageName: node linkType: hard -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce - languageName: node - linkType: hard - "json-schema-traverse@npm:^1.0.0": version: 1.0.0 resolution: "json-schema-traverse@npm:1.0.0" @@ -2613,13 +1900,6 @@ __metadata: languageName: node linkType: hard -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 - languageName: node - linkType: hard - "json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -2629,25 +1909,6 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.5.4": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" - dependencies: - json-buffer: "npm:3.0.1" - checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: "npm:^1.2.1" - type-check: "npm:~0.4.0" - checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e - languageName: node - linkType: hard - "light-my-request@npm:^6.0.0": version: 6.6.0 resolution: "light-my-request@npm:6.6.0" @@ -2659,22 +1920,6 @@ __metadata: languageName: node linkType: hard -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: "npm:^5.0.0" - checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 - languageName: node - linkType: hard - "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -2717,23 +1962,6 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb - languageName: node - linkType: hard - -"micromatch@npm:^4.0.8": - version: 4.0.8 - resolution: "micromatch@npm:4.0.8" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 - languageName: node - linkType: hard - "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -2750,15 +1978,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 - languageName: node - linkType: hard - "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -2867,13 +2086,6 @@ __metadata: languageName: node linkType: hard -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 - languageName: node - linkType: hard - "negotiator@npm:^1.0.0": version: 1.0.0 resolution: "negotiator@npm:1.0.0" @@ -2935,38 +2147,6 @@ __metadata: languageName: node linkType: hard -"optionator@npm:^0.9.3": - version: 0.9.4 - resolution: "optionator@npm:0.9.4" - dependencies: - deep-is: "npm:^0.1.3" - fast-levenshtein: "npm:^2.0.6" - levn: "npm:^0.4.1" - prelude-ls: "npm:^1.2.1" - type-check: "npm:^0.4.0" - word-wrap: "npm:^1.2.5" - checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: "npm:^3.0.2" - checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a - languageName: node - linkType: hard - "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -2981,22 +2161,6 @@ __metadata: languageName: node linkType: hard -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: "npm:^3.0.0" - checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b - languageName: node - linkType: hard - "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -3021,13 +2185,6 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be - languageName: node - linkType: hard - "picomatch@npm:^4.0.3": version: 4.0.3 resolution: "picomatch@npm:4.0.3" @@ -3106,13 +2263,6 @@ __metadata: languageName: node linkType: hard -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd - languageName: node - linkType: hard - "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -3161,20 +2311,6 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 - languageName: node - linkType: hard - "quick-format-unescaped@npm:^4.0.3": version: 4.0.4 resolution: "quick-format-unescaped@npm:4.0.4" @@ -3221,13 +2357,6 @@ __metadata: languageName: node linkType: hard -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 - languageName: node - linkType: hard - "resolve-pkg-maps@npm:^1.0.0": version: 1.0.0 resolution: "resolve-pkg-maps@npm:1.0.0" @@ -3344,15 +2473,6 @@ __metadata: languageName: node linkType: hard -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 - languageName: node - linkType: hard - "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -3545,13 +2665,6 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd - languageName: node - linkType: hard - "strip-json-comments@npm:^5.0.2": version: 5.0.3 resolution: "strip-json-comments@npm:5.0.3" @@ -3559,15 +2672,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 - languageName: node - linkType: hard - "tar@npm:^7.4.3": version: 7.5.1 resolution: "tar@npm:7.5.1" @@ -3600,15 +2704,6 @@ __metadata: languageName: node linkType: hard -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 - languageName: node - linkType: hard - "toad-cache@npm:^3.7.0": version: 3.7.0 resolution: "toad-cache@npm:3.7.0" @@ -3616,15 +2711,6 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.1.0": - version: 2.1.0 - resolution: "ts-api-utils@npm:2.1.0" - peerDependencies: - typescript: ">=4.8.4" - checksum: 10c0/9806a38adea2db0f6aa217ccc6bc9c391ddba338a9fe3080676d0d50ed806d305bb90e8cef0276e793d28c8a929f400abb184ddd7ff83a416959c0f4d2ce754f - languageName: node - linkType: hard - "tsx@npm:^4.20.6": version: 4.20.6 resolution: "tsx@npm:4.20.6" @@ -3641,30 +2727,6 @@ __metadata: languageName: node linkType: hard -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: "npm:^1.2.1" - checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 - languageName: node - linkType: hard - -"typescript-eslint@npm:^8.44.0": - version: 8.45.0 - resolution: "typescript-eslint@npm:8.45.0" - dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.45.0" - "@typescript-eslint/parser": "npm:8.45.0" - "@typescript-eslint/typescript-estree": "npm:8.45.0" - "@typescript-eslint/utils": "npm:8.45.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/2342b0bffe6f719711adbb42116f90cb1fe1670e2e74dde2739482c9d61c2a975ee16e2d560684613050544b543342ec1b11b46e158a48ecc605f5882d2d5da7 - languageName: node - linkType: hard - "typescript@npm:^5.9.2": version: 5.9.2 resolution: "typescript@npm:5.9.2" @@ -3675,16 +2737,6 @@ __metadata: languageName: node linkType: hard -"typescript@npm:~5.8.3": - version: 5.8.3 - resolution: "typescript@npm:5.8.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48 - languageName: node - linkType: hard - "typescript@patch:typescript@npm%3A^5.9.2#optional!builtin": version: 5.9.2 resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" @@ -3695,16 +2747,6 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A~5.8.3#optional!builtin": - version: 5.8.3 - resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb - languageName: node - linkType: hard - "undici-types@npm:~7.12.0": version: 7.12.0 resolution: "undici-types@npm:7.12.0" @@ -3744,15 +2786,6 @@ __metadata: languageName: node linkType: hard -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c - languageName: node - linkType: hard - "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -3821,19 +2854,13 @@ __metadata: version: 0.0.0-use.local resolution: "web@workspace:packages/web" dependencies: - "@eslint/js": "npm:^9.36.0" "@types/react": "npm:^19.1.13" "@types/react-dom": "npm:^19.1.9" "@vitejs/plugin-react": "npm:^5.0.3" babel-plugin-react-compiler: "npm:^19.1.0-rc.3" - eslint: "npm:^9.36.0" - eslint-plugin-react-hooks: "npm:^5.2.0" - eslint-plugin-react-refresh: "npm:^0.4.20" globals: "npm:^16.4.0" react: "npm:^19.1.1" react-dom: "npm:^19.1.1" - typescript: "npm:~5.8.3" - typescript-eslint: "npm:^8.44.0" vite: "npm:^7.1.7" languageName: unknown linkType: soft @@ -3860,13 +2887,6 @@ __metadata: languageName: node linkType: hard -"word-wrap@npm:^1.2.5": - version: 1.2.5 - resolution: "word-wrap@npm:1.2.5" - checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 - languageName: node - linkType: hard - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -3917,13 +2937,6 @@ __metadata: languageName: node linkType: hard -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f - languageName: node - linkType: hard - "zod@npm:^4.1.11": version: 4.1.11 resolution: "zod@npm:4.1.11" From 9c222224743800608c6f099efff2fd3c9de03889 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 12:28:12 +0200 Subject: [PATCH 15/65] Add tRPC to web --- deep-sea-stories/packages/backend/src/main.ts | 2 + deep-sea-stories/packages/web/package.json | 5 + .../packages/web/src/contexts/trpc.tsx | 33 ++ deep-sea-stories/packages/web/src/main.tsx | 16 +- .../packages/web/src/vite-env.d.ts | 16 + deep-sea-stories/yarn.lock | 338 +++++++++++++++++- 6 files changed, 405 insertions(+), 5 deletions(-) create mode 100644 deep-sea-stories/packages/web/src/contexts/trpc.tsx create mode 100644 deep-sea-stories/packages/web/src/vite-env.d.ts diff --git a/deep-sea-stories/packages/backend/src/main.ts b/deep-sea-stories/packages/backend/src/main.ts index 04df58a..ff8684f 100644 --- a/deep-sea-stories/packages/backend/src/main.ts +++ b/deep-sea-stories/packages/backend/src/main.ts @@ -29,3 +29,5 @@ try { fastify.log.error(err); process.exit(1); } + +export type { AppRouter }; diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 6366d14..e09cb27 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -9,6 +9,11 @@ "preview": "vite preview" }, "dependencies": { + "@tanstack/react-query": "^5.90.2", + "@trpc/client": "^11.6.0", + "@trpc/server": "^11.6.0", + "@trpc/tanstack-react-query": "^11.6.0", + "backend": "workspace:*", "react": "^19.1.1", "react-dom": "^19.1.1" }, diff --git a/deep-sea-stories/packages/web/src/contexts/trpc.tsx b/deep-sea-stories/packages/web/src/contexts/trpc.tsx new file mode 100644 index 0000000..c6a4471 --- /dev/null +++ b/deep-sea-stories/packages/web/src/contexts/trpc.tsx @@ -0,0 +1,33 @@ +import type { QueryClient } from '@tanstack/react-query'; +import { createTRPCClient, httpBatchLink } from '@trpc/client'; +import { createTRPCContext } from '@trpc/tanstack-react-query'; +import type { AppRouter } from 'backend'; +import { type FC, type PropsWithChildren, useState } from 'react'; + +export const { TRPCProvider, useTRPC, useTRPCClient } = + createTRPCContext(); + +interface TRPCClientProviderProps extends PropsWithChildren { + queryClient: QueryClient; +} + +export const TRPCClientProvider: FC = ({ + queryClient, + children, +}) => { + const [trpcClient] = useState(() => + createTRPCClient({ + links: [ + httpBatchLink({ + url: import.meta.env.VITE_BACKEND_URL, + }), + ], + }), + ); + + return ( + + {children} + + ); +}; diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index 977420d..1027a0d 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -1,11 +1,25 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './index.css'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import App from './App.tsx'; +import { TRPCClientProvider } from './contexts/trpc.tsx'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retryDelay: 2000, + }, + }, +}); // biome-ignore lint/style/noNonNullAssertion: root always exists createRoot(document.getElementById('root')!).render( - + + + + + , ); diff --git a/deep-sea-stories/packages/web/src/vite-env.d.ts b/deep-sea-stories/packages/web/src/vite-env.d.ts new file mode 100644 index 0000000..e09965e --- /dev/null +++ b/deep-sea-stories/packages/web/src/vite-env.d.ts @@ -0,0 +1,16 @@ +/// + +// biome-ignore lint/correctness/noUnusedVariables: for type checking +interface ViteTypeOptions { + strictImportMetaEnv: unknown; +} + +interface ImportMetaEnv { + readonly VITE_BACKEND_URL: string; + readonly VITE_FISHJAM_ID: string; +} + +// biome-ignore lint/correctness/noUnusedVariables: for type checking +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index a085eb0..9cf76b6 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -493,6 +493,13 @@ __metadata: languageName: node linkType: hard +"@fastify/deepmerge@npm:^2.0.0": + version: 2.0.2 + resolution: "@fastify/deepmerge@npm:2.0.2" + checksum: 10c0/dfb30896d374c25a3f5bc0550cb19d2014946392b2858fadd5feb1486eb3c37751db1db24dcbf801bb11465435939d0d75fb7ee65501287e77b4df7022b3509a + languageName: node + linkType: hard + "@fastify/error@npm:^4.0.0": version: 4.2.0 resolution: "@fastify/error@npm:4.2.0" @@ -802,6 +809,34 @@ __metadata: languageName: node linkType: hard +"@tanstack/query-core@npm:5.90.2": + version: 5.90.2 + resolution: "@tanstack/query-core@npm:5.90.2" + checksum: 10c0/695a7450b0bb9f6dd21bebeacfc962dfc886631a3b3a13c33a842ef719b4c3dd30c15febe8c1ade6902a85e0f387c51a97570f430cc8f5c7032ff737d6410597 + languageName: node + linkType: hard + +"@tanstack/react-query@npm:^5.90.2": + version: 5.90.2 + resolution: "@tanstack/react-query@npm:5.90.2" + dependencies: + "@tanstack/query-core": "npm:5.90.2" + peerDependencies: + react: ^18 || ^19 + checksum: 10c0/22e76626a59890409858521b0e42b49219126a4ea5ed79eaa48a267959175dfdd28b30b9b03a415dccf703d95c18100a9d8917679818f6d2adc26d6c5f96a4d6 + languageName: node + linkType: hard + +"@trpc/client@npm:^11.6.0": + version: 11.6.0 + resolution: "@trpc/client@npm:11.6.0" + peerDependencies: + "@trpc/server": 11.6.0 + typescript: ">=5.7.2" + checksum: 10c0/663ba6ea3bc273ffb56c1dcf1a4d02b232b617c0c80a3ea296b23bae21624faf5ac71f22bab4f823c0c06bcf61a5fdc79d9a4892db35322294b51b28750b6043 + languageName: node + linkType: hard + "@trpc/server@npm:^11.6.0": version: 11.6.0 resolution: "@trpc/server@npm:11.6.0" @@ -811,6 +846,20 @@ __metadata: languageName: node linkType: hard +"@trpc/tanstack-react-query@npm:^11.6.0": + version: 11.6.0 + resolution: "@trpc/tanstack-react-query@npm:11.6.0" + peerDependencies: + "@tanstack/react-query": ^5.80.3 + "@trpc/client": 11.6.0 + "@trpc/server": 11.6.0 + react: ">=18.2.0" + react-dom: ">=18.2.0" + typescript: ">=5.7.2" + checksum: 10c0/80a555ccd5f664f288fae30bce2195cc87340092c6ab2af67101dbb1790b2f42141f74af69743ffbef6cdaf451dcd93f7774ea675e577352098f1d1e0cf9abca + languageName: node + linkType: hard + "@tsconfig/node24@npm:^24.0.1": version: 24.0.1 resolution: "@tsconfig/node24@npm:24.0.1" @@ -970,7 +1019,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1044,7 +1093,7 @@ __metadata: languageName: node linkType: hard -"backend@workspace:packages/backend": +"backend@workspace:*, backend@workspace:packages/backend": version: 0.0.0-use.local resolution: "backend@workspace:packages/backend" dependencies: @@ -1054,6 +1103,7 @@ __metadata: "@types/node": "npm:^24.5.2" dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" + fastify-cli: "npm:^7.4.0" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" zod: "npm:^4.1.11" @@ -1137,6 +1187,25 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^4.1.2": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + languageName: node + linkType: hard + +"chokidar@npm:^4.0.0": + version: 4.0.3 + resolution: "chokidar@npm:4.0.3" + dependencies: + readdirp: "npm:^4.0.1" + checksum: 10c0/a58b9df05bb452f7d105d9e7229ac82fa873741c0c40ddcc7bb82f8a909fbe3f7814c9ebe9bc9a2bef9b737c0ec6e2d699d179048ef06ad3ec46315df0ebe6ad + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -1144,6 +1213,13 @@ __metadata: languageName: node linkType: hard +"close-with-grace@npm:^2.1.0": + version: 2.3.0 + resolution: "close-with-grace@npm:2.3.0" + checksum: 10c0/b554e65a2ff52c07928095417623734473c7e1b25da5bf7c6af5cca7b2c866b0814adba6fc32a27fcae1759f349c5aaaa24bd7f20520461d5489b0a0f5e8d945 + languageName: node + linkType: hard + "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -1176,6 +1252,13 @@ __metadata: languageName: node linkType: hard +"commist@npm:^3.0.0": + version: 3.2.0 + resolution: "commist@npm:3.2.0" + checksum: 10c0/ab2d14921d30f649889adbec5dbf1712d45681bbc3f863ee5078e02465b2e8510d47a5643e137ffa0698b8199b5ce787d8be131982bcae4f294c8225d1046def + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -1250,6 +1333,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.0.0": + version: 16.6.1 + resolution: "dotenv@npm:16.6.1" + checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc + languageName: node + linkType: hard + "dotenv@npm:^17.2.3": version: 17.2.3 resolution: "dotenv@npm:17.2.3" @@ -1524,7 +1614,40 @@ __metadata: languageName: node linkType: hard -"fastify@npm:^5.6.1": +"fastify-cli@npm:^7.4.0": + version: 7.4.0 + resolution: "fastify-cli@npm:7.4.0" + dependencies: + "@fastify/deepmerge": "npm:^2.0.0" + chalk: "npm:^4.1.2" + chokidar: "npm:^4.0.0" + close-with-grace: "npm:^2.1.0" + commist: "npm:^3.0.0" + dotenv: "npm:^16.0.0" + fastify: "npm:^5.0.0" + fastify-plugin: "npm:^5.0.0" + generify: "npm:^4.0.0" + help-me: "npm:^5.0.0" + is-docker: "npm:^2.0.0" + pino-pretty: "npm:^13.0.0" + pkg-up: "npm:^3.1.0" + resolve-from: "npm:^5.0.0" + semver: "npm:^7.3.5" + yargs-parser: "npm:^21.1.1" + bin: + fastify: cli.js + checksum: 10c0/39d516f9c4e5ee57779630c24b1c96e39724a4b601775cb2a9c389f0e4248f791f4f9f3e9d4ed3c4598fbd7a1599abea1e105931f654b4adcec9a490918c62d1 + languageName: node + linkType: hard + +"fastify-plugin@npm:^5.0.0": + version: 5.1.0 + resolution: "fastify-plugin@npm:5.1.0" + checksum: 10c0/61b330b8cb03a3581b796d745137499a782934abcf65dbf9a41d07248520cfd220b3ae8b16afeaf81af712e68e1ac24352895132cfeb2b372c66662c0170f365 + languageName: node + linkType: hard + +"fastify@npm:^5.0.0, fastify@npm:^5.6.1": version: 5.6.1 resolution: "fastify@npm:5.6.1" dependencies: @@ -1579,6 +1702,15 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^3.0.0": + version: 3.0.0 + resolution: "find-up@npm:3.0.0" + dependencies: + locate-path: "npm:^3.0.0" + checksum: 10c0/2c2e7d0a26db858e2f624f39038c74739e38306dee42b45f404f770db357947be9d0d587f1cac72d20c114deb38aa57316e879eb0a78b17b46da7dab0a3bd6e3 + languageName: node + linkType: hard + "follow-redirects@npm:^1.15.6": version: 1.15.11 resolution: "follow-redirects@npm:1.15.11" @@ -1654,6 +1786,20 @@ __metadata: languageName: node linkType: hard +"generify@npm:^4.0.0": + version: 4.2.0 + resolution: "generify@npm:4.2.0" + dependencies: + isbinaryfile: "npm:^4.0.2" + pump: "npm:^3.0.0" + split2: "npm:^3.0.0" + walker: "npm:^1.0.6" + bin: + generify: generify.js + checksum: 10c0/4bfc8a46901548e1e8871c3bafdd83d55711b465c995988c43d03d63ef4622b8ba7ecbb3a6c931ca275d3514dc8021884ed549bc8c9007d9a9d9ef2bde54e591 + languageName: node + linkType: hard + "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -1738,6 +1884,13 @@ __metadata: languageName: node linkType: hard +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 + languageName: node + linkType: hard + "has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" @@ -1813,6 +1966,13 @@ __metadata: languageName: node linkType: hard +"inherits@npm:^2.0.3": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + languageName: node + linkType: hard + "ip-address@npm:^10.0.1": version: 10.0.1 resolution: "ip-address@npm:10.0.1" @@ -1827,6 +1987,15 @@ __metadata: languageName: node linkType: hard +"is-docker@npm:^2.0.0": + version: 2.2.1 + resolution: "is-docker@npm:2.2.1" + bin: + is-docker: cli.js + checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc + languageName: node + linkType: hard + "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -1834,6 +2003,13 @@ __metadata: languageName: node linkType: hard +"isbinaryfile@npm:^4.0.2": + version: 4.0.10 + resolution: "isbinaryfile@npm:4.0.10" + checksum: 10c0/0703d8cfeb69ed79e6d173120f327450011a066755150a6bbf97ffecec1069a5f2092777868315b21359098c84b54984871cad1abce877ad9141fb2caf3dcabf + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -1920,6 +2096,16 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^3.0.0": + version: 3.0.0 + resolution: "locate-path@npm:3.0.0" + dependencies: + p-locate: "npm:^3.0.0" + path-exists: "npm:^3.0.0" + checksum: 10c0/3db394b7829a7fe2f4fbdd25d3c4689b85f003c318c5da4052c7e56eed697da8f1bce5294f685c69ff76e32cba7a33629d94396976f6d05fb7f4c755c5e2ae8b + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -1955,6 +2141,15 @@ __metadata: languageName: node linkType: hard +"makeerror@npm:1.0.12": + version: 1.0.12 + resolution: "makeerror@npm:1.0.12" + dependencies: + tmpl: "npm:1.0.5" + checksum: 10c0/b0e6e599780ce6bab49cc413eba822f7d1f0dfebd1c103eaa3785c59e43e22c59018323cf9e1708f0ef5329e94a745d163fcbb6bff8e4c6742f9be9e86f3500c + languageName: node + linkType: hard + "math-intrinsics@npm:^1.1.0": version: 1.1.0 resolution: "math-intrinsics@npm:1.1.0" @@ -2147,6 +2342,24 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^2.0.0": + version: 2.3.0 + resolution: "p-limit@npm:2.3.0" + dependencies: + p-try: "npm:^2.0.0" + checksum: 10c0/8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12 + languageName: node + linkType: hard + +"p-locate@npm:^3.0.0": + version: 3.0.0 + resolution: "p-locate@npm:3.0.0" + dependencies: + p-limit: "npm:^2.0.0" + checksum: 10c0/7b7f06f718f19e989ce6280ed4396fb3c34dabdee0df948376483032f9d5ec22fdf7077ec942143a75827bb85b11da72016497fc10dac1106c837ed593969ee8 + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -2154,6 +2367,13 @@ __metadata: languageName: node linkType: hard +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: 10c0/c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f + languageName: node + linkType: hard + "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -2161,6 +2381,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^3.0.0": + version: 3.0.0 + resolution: "path-exists@npm:3.0.0" + checksum: 10c0/17d6a5664bc0a11d48e2b2127d28a0e58822c6740bde30403f08013da599182289c56518bec89407e3f31d3c2b6b296a4220bc3f867f0911fee6952208b04167 + languageName: node + linkType: hard + "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -2201,7 +2428,7 @@ __metadata: languageName: node linkType: hard -"pino-pretty@npm:^13.1.1": +"pino-pretty@npm:^13.0.0, pino-pretty@npm:^13.1.1": version: 13.1.1 resolution: "pino-pretty@npm:13.1.1" dependencies: @@ -2252,6 +2479,15 @@ __metadata: languageName: node linkType: hard +"pkg-up@npm:^3.1.0": + version: 3.1.0 + resolution: "pkg-up@npm:3.1.0" + dependencies: + find-up: "npm:^3.0.0" + checksum: 10c0/ecb60e1f8e1f611c0bdf1a0b6a474d6dfb51185567dc6f29cdef37c8d480ecba5362e006606bb290519bbb6f49526c403fabea93c3090c20368d98bb90c999ab + languageName: node + linkType: hard + "postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -2343,6 +2579,24 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^3.0.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 + languageName: node + linkType: hard + +"readdirp@npm:^4.0.1": + version: 4.1.2 + resolution: "readdirp@npm:4.1.2" + checksum: 10c0/60a14f7619dec48c9c850255cd523e2717001b0e179dc7037cfa0895da7b9e9ab07532d324bfb118d73a710887d1e35f79c495fa91582784493e085d18c72c62 + languageName: node + linkType: hard + "real-require@npm:^0.2.0": version: 0.2.0 resolution: "real-require@npm:0.2.0" @@ -2357,6 +2611,13 @@ __metadata: languageName: node linkType: hard +"resolve-from@npm:^5.0.0": + version: 5.0.0 + resolution: "resolve-from@npm:5.0.0" + checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2 + languageName: node + linkType: hard + "resolve-pkg-maps@npm:^1.0.0": version: 1.0.0 resolution: "resolve-pkg-maps@npm:1.0.0" @@ -2473,6 +2734,13 @@ __metadata: languageName: node linkType: hard +"safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -2609,6 +2877,15 @@ __metadata: languageName: node linkType: hard +"split2@npm:^3.0.0": + version: 3.2.2 + resolution: "split2@npm:3.2.2" + dependencies: + readable-stream: "npm:^3.0.0" + checksum: 10c0/2dad5603c52b353939befa3e2f108f6e3aff42b204ad0f5f16dd12fd7c2beab48d117184ce6f7c8854f9ee5ffec6faae70d243711dd7d143a9f635b4a285de4e + languageName: node + linkType: hard + "split2@npm:^4.0.0": version: 4.2.0 resolution: "split2@npm:4.2.0" @@ -2647,6 +2924,15 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -2672,6 +2958,15 @@ __metadata: languageName: node linkType: hard +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.5.1 resolution: "tar@npm:7.5.1" @@ -2704,6 +2999,13 @@ __metadata: languageName: node linkType: hard +"tmpl@npm:1.0.5": + version: 1.0.5 + resolution: "tmpl@npm:1.0.5" + checksum: 10c0/f935537799c2d1922cb5d6d3805f594388f75338fe7a4a9dac41504dd539704ca4db45b883b52e7b0aa5b2fd5ddadb1452bf95cd23a69da2f793a843f9451cc9 + languageName: node + linkType: hard + "toad-cache@npm:^3.7.0": version: 3.7.0 resolution: "toad-cache@npm:3.7.0" @@ -2786,6 +3088,13 @@ __metadata: languageName: node linkType: hard +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 + languageName: node + linkType: hard + "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -2850,14 +3159,28 @@ __metadata: languageName: node linkType: hard +"walker@npm:^1.0.6": + version: 1.0.8 + resolution: "walker@npm:1.0.8" + dependencies: + makeerror: "npm:1.0.12" + checksum: 10c0/a17e037bccd3ca8a25a80cb850903facdfed0de4864bd8728f1782370715d679fa72e0a0f5da7c1c1379365159901e5935f35be531229da53bbfc0efdabdb48e + languageName: node + linkType: hard + "web@workspace:packages/web": version: 0.0.0-use.local resolution: "web@workspace:packages/web" dependencies: + "@tanstack/react-query": "npm:^5.90.2" + "@trpc/client": "npm:^11.6.0" + "@trpc/server": "npm:^11.6.0" + "@trpc/tanstack-react-query": "npm:^11.6.0" "@types/react": "npm:^19.1.13" "@types/react-dom": "npm:^19.1.9" "@vitejs/plugin-react": "npm:^5.0.3" babel-plugin-react-compiler: "npm:^19.1.0-rc.3" + backend: "workspace:*" globals: "npm:^16.4.0" react: "npm:^19.1.1" react-dom: "npm:^19.1.1" @@ -2937,6 +3260,13 @@ __metadata: languageName: node linkType: hard +"yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 + languageName: node + linkType: hard + "zod@npm:^4.1.11": version: 4.1.11 resolution: "zod@npm:4.1.11" From daf67b41f5312a47bd8d2d11912030f6a75de819 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:02:48 +0200 Subject: [PATCH 16/65] Remove redundant ignore comment --- deep-sea-stories/packages/web/src/vite-env.d.ts | 2 -- deep-sea-stories/packages/web/vite.config.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/deep-sea-stories/packages/web/src/vite-env.d.ts b/deep-sea-stories/packages/web/src/vite-env.d.ts index e09965e..61fdf84 100644 --- a/deep-sea-stories/packages/web/src/vite-env.d.ts +++ b/deep-sea-stories/packages/web/src/vite-env.d.ts @@ -1,6 +1,5 @@ /// -// biome-ignore lint/correctness/noUnusedVariables: for type checking interface ViteTypeOptions { strictImportMetaEnv: unknown; } @@ -10,7 +9,6 @@ interface ImportMetaEnv { readonly VITE_FISHJAM_ID: string; } -// biome-ignore lint/correctness/noUnusedVariables: for type checking interface ImportMeta { readonly env: ImportMetaEnv; } diff --git a/deep-sea-stories/packages/web/vite.config.ts b/deep-sea-stories/packages/web/vite.config.ts index ca79347..e22b3b8 100644 --- a/deep-sea-stories/packages/web/vite.config.ts +++ b/deep-sea-stories/packages/web/vite.config.ts @@ -1,5 +1,5 @@ -import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; // https://vite.dev/config/ export default defineConfig({ From f07b729552b7f8f8cf28936de5cee0747e8bda83 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:03:52 +0200 Subject: [PATCH 17/65] Update lock --- deep-sea-stories/yarn.lock | 289 +------------------------------------ 1 file changed, 3 insertions(+), 286 deletions(-) diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 9cf76b6..c6a5e2d 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -493,13 +493,6 @@ __metadata: languageName: node linkType: hard -"@fastify/deepmerge@npm:^2.0.0": - version: 2.0.2 - resolution: "@fastify/deepmerge@npm:2.0.2" - checksum: 10c0/dfb30896d374c25a3f5bc0550cb19d2014946392b2858fadd5feb1486eb3c37751db1db24dcbf801bb11465435939d0d75fb7ee65501287e77b4df7022b3509a - languageName: node - linkType: hard - "@fastify/error@npm:^4.0.0": version: 4.2.0 resolution: "@fastify/error@npm:4.2.0" @@ -1019,7 +1012,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^4.0.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1103,7 +1096,6 @@ __metadata: "@types/node": "npm:^24.5.2" dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" - fastify-cli: "npm:^7.4.0" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" zod: "npm:^4.1.11" @@ -1187,25 +1179,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.1.2": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 - languageName: node - linkType: hard - -"chokidar@npm:^4.0.0": - version: 4.0.3 - resolution: "chokidar@npm:4.0.3" - dependencies: - readdirp: "npm:^4.0.1" - checksum: 10c0/a58b9df05bb452f7d105d9e7229ac82fa873741c0c40ddcc7bb82f8a909fbe3f7814c9ebe9bc9a2bef9b737c0ec6e2d699d179048ef06ad3ec46315df0ebe6ad - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -1213,13 +1186,6 @@ __metadata: languageName: node linkType: hard -"close-with-grace@npm:^2.1.0": - version: 2.3.0 - resolution: "close-with-grace@npm:2.3.0" - checksum: 10c0/b554e65a2ff52c07928095417623734473c7e1b25da5bf7c6af5cca7b2c866b0814adba6fc32a27fcae1759f349c5aaaa24bd7f20520461d5489b0a0f5e8d945 - languageName: node - linkType: hard - "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -1252,13 +1218,6 @@ __metadata: languageName: node linkType: hard -"commist@npm:^3.0.0": - version: 3.2.0 - resolution: "commist@npm:3.2.0" - checksum: 10c0/ab2d14921d30f649889adbec5dbf1712d45681bbc3f863ee5078e02465b2e8510d47a5643e137ffa0698b8199b5ce787d8be131982bcae4f294c8225d1046def - languageName: node - linkType: hard - "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -1333,13 +1292,6 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:^16.0.0": - version: 16.6.1 - resolution: "dotenv@npm:16.6.1" - checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc - languageName: node - linkType: hard - "dotenv@npm:^17.2.3": version: 17.2.3 resolution: "dotenv@npm:17.2.3" @@ -1614,40 +1566,7 @@ __metadata: languageName: node linkType: hard -"fastify-cli@npm:^7.4.0": - version: 7.4.0 - resolution: "fastify-cli@npm:7.4.0" - dependencies: - "@fastify/deepmerge": "npm:^2.0.0" - chalk: "npm:^4.1.2" - chokidar: "npm:^4.0.0" - close-with-grace: "npm:^2.1.0" - commist: "npm:^3.0.0" - dotenv: "npm:^16.0.0" - fastify: "npm:^5.0.0" - fastify-plugin: "npm:^5.0.0" - generify: "npm:^4.0.0" - help-me: "npm:^5.0.0" - is-docker: "npm:^2.0.0" - pino-pretty: "npm:^13.0.0" - pkg-up: "npm:^3.1.0" - resolve-from: "npm:^5.0.0" - semver: "npm:^7.3.5" - yargs-parser: "npm:^21.1.1" - bin: - fastify: cli.js - checksum: 10c0/39d516f9c4e5ee57779630c24b1c96e39724a4b601775cb2a9c389f0e4248f791f4f9f3e9d4ed3c4598fbd7a1599abea1e105931f654b4adcec9a490918c62d1 - languageName: node - linkType: hard - -"fastify-plugin@npm:^5.0.0": - version: 5.1.0 - resolution: "fastify-plugin@npm:5.1.0" - checksum: 10c0/61b330b8cb03a3581b796d745137499a782934abcf65dbf9a41d07248520cfd220b3ae8b16afeaf81af712e68e1ac24352895132cfeb2b372c66662c0170f365 - languageName: node - linkType: hard - -"fastify@npm:^5.0.0, fastify@npm:^5.6.1": +"fastify@npm:^5.6.1": version: 5.6.1 resolution: "fastify@npm:5.6.1" dependencies: @@ -1702,15 +1621,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^3.0.0": - version: 3.0.0 - resolution: "find-up@npm:3.0.0" - dependencies: - locate-path: "npm:^3.0.0" - checksum: 10c0/2c2e7d0a26db858e2f624f39038c74739e38306dee42b45f404f770db357947be9d0d587f1cac72d20c114deb38aa57316e879eb0a78b17b46da7dab0a3bd6e3 - languageName: node - linkType: hard - "follow-redirects@npm:^1.15.6": version: 1.15.11 resolution: "follow-redirects@npm:1.15.11" @@ -1786,20 +1696,6 @@ __metadata: languageName: node linkType: hard -"generify@npm:^4.0.0": - version: 4.2.0 - resolution: "generify@npm:4.2.0" - dependencies: - isbinaryfile: "npm:^4.0.2" - pump: "npm:^3.0.0" - split2: "npm:^3.0.0" - walker: "npm:^1.0.6" - bin: - generify: generify.js - checksum: 10c0/4bfc8a46901548e1e8871c3bafdd83d55711b465c995988c43d03d63ef4622b8ba7ecbb3a6c931ca275d3514dc8021884ed549bc8c9007d9a9d9ef2bde54e591 - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -1884,13 +1780,6 @@ __metadata: languageName: node linkType: hard -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 - languageName: node - linkType: hard - "has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" @@ -1966,13 +1855,6 @@ __metadata: languageName: node linkType: hard -"inherits@npm:^2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - "ip-address@npm:^10.0.1": version: 10.0.1 resolution: "ip-address@npm:10.0.1" @@ -1987,15 +1869,6 @@ __metadata: languageName: node linkType: hard -"is-docker@npm:^2.0.0": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -2003,13 +1876,6 @@ __metadata: languageName: node linkType: hard -"isbinaryfile@npm:^4.0.2": - version: 4.0.10 - resolution: "isbinaryfile@npm:4.0.10" - checksum: 10c0/0703d8cfeb69ed79e6d173120f327450011a066755150a6bbf97ffecec1069a5f2092777868315b21359098c84b54984871cad1abce877ad9141fb2caf3dcabf - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -2096,16 +1962,6 @@ __metadata: languageName: node linkType: hard -"locate-path@npm:^3.0.0": - version: 3.0.0 - resolution: "locate-path@npm:3.0.0" - dependencies: - p-locate: "npm:^3.0.0" - path-exists: "npm:^3.0.0" - checksum: 10c0/3db394b7829a7fe2f4fbdd25d3c4689b85f003c318c5da4052c7e56eed697da8f1bce5294f685c69ff76e32cba7a33629d94396976f6d05fb7f4c755c5e2ae8b - languageName: node - linkType: hard - "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -2141,15 +1997,6 @@ __metadata: languageName: node linkType: hard -"makeerror@npm:1.0.12": - version: 1.0.12 - resolution: "makeerror@npm:1.0.12" - dependencies: - tmpl: "npm:1.0.5" - checksum: 10c0/b0e6e599780ce6bab49cc413eba822f7d1f0dfebd1c103eaa3785c59e43e22c59018323cf9e1708f0ef5329e94a745d163fcbb6bff8e4c6742f9be9e86f3500c - languageName: node - linkType: hard - "math-intrinsics@npm:^1.1.0": version: 1.1.0 resolution: "math-intrinsics@npm:1.1.0" @@ -2342,24 +2189,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^2.0.0": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: "npm:^2.0.0" - checksum: 10c0/8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12 - languageName: node - linkType: hard - -"p-locate@npm:^3.0.0": - version: 3.0.0 - resolution: "p-locate@npm:3.0.0" - dependencies: - p-limit: "npm:^2.0.0" - checksum: 10c0/7b7f06f718f19e989ce6280ed4396fb3c34dabdee0df948376483032f9d5ec22fdf7077ec942143a75827bb85b11da72016497fc10dac1106c837ed593969ee8 - languageName: node - linkType: hard - "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -2367,13 +2196,6 @@ __metadata: languageName: node linkType: hard -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: 10c0/c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f - languageName: node - linkType: hard - "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -2381,13 +2203,6 @@ __metadata: languageName: node linkType: hard -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 10c0/17d6a5664bc0a11d48e2b2127d28a0e58822c6740bde30403f08013da599182289c56518bec89407e3f31d3c2b6b296a4220bc3f867f0911fee6952208b04167 - languageName: node - linkType: hard - "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -2428,7 +2243,7 @@ __metadata: languageName: node linkType: hard -"pino-pretty@npm:^13.0.0, pino-pretty@npm:^13.1.1": +"pino-pretty@npm:^13.1.1": version: 13.1.1 resolution: "pino-pretty@npm:13.1.1" dependencies: @@ -2479,15 +2294,6 @@ __metadata: languageName: node linkType: hard -"pkg-up@npm:^3.1.0": - version: 3.1.0 - resolution: "pkg-up@npm:3.1.0" - dependencies: - find-up: "npm:^3.0.0" - checksum: 10c0/ecb60e1f8e1f611c0bdf1a0b6a474d6dfb51185567dc6f29cdef37c8d480ecba5362e006606bb290519bbb6f49526c403fabea93c3090c20368d98bb90c999ab - languageName: node - linkType: hard - "postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -2579,24 +2385,6 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.0.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 - languageName: node - linkType: hard - -"readdirp@npm:^4.0.1": - version: 4.1.2 - resolution: "readdirp@npm:4.1.2" - checksum: 10c0/60a14f7619dec48c9c850255cd523e2717001b0e179dc7037cfa0895da7b9e9ab07532d324bfb118d73a710887d1e35f79c495fa91582784493e085d18c72c62 - languageName: node - linkType: hard - "real-require@npm:^0.2.0": version: 0.2.0 resolution: "real-require@npm:0.2.0" @@ -2611,13 +2399,6 @@ __metadata: languageName: node linkType: hard -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2 - languageName: node - linkType: hard - "resolve-pkg-maps@npm:^1.0.0": version: 1.0.0 resolution: "resolve-pkg-maps@npm:1.0.0" @@ -2734,13 +2515,6 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 - languageName: node - linkType: hard - "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -2877,15 +2651,6 @@ __metadata: languageName: node linkType: hard -"split2@npm:^3.0.0": - version: 3.2.2 - resolution: "split2@npm:3.2.2" - dependencies: - readable-stream: "npm:^3.0.0" - checksum: 10c0/2dad5603c52b353939befa3e2f108f6e3aff42b204ad0f5f16dd12fd7c2beab48d117184ce6f7c8854f9ee5ffec6faae70d243711dd7d143a9f635b4a285de4e - languageName: node - linkType: hard - "split2@npm:^4.0.0": version: 4.2.0 resolution: "split2@npm:4.2.0" @@ -2924,15 +2689,6 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d - languageName: node - linkType: hard - "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -2958,15 +2714,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 - languageName: node - linkType: hard - "tar@npm:^7.4.3": version: 7.5.1 resolution: "tar@npm:7.5.1" @@ -2999,13 +2746,6 @@ __metadata: languageName: node linkType: hard -"tmpl@npm:1.0.5": - version: 1.0.5 - resolution: "tmpl@npm:1.0.5" - checksum: 10c0/f935537799c2d1922cb5d6d3805f594388f75338fe7a4a9dac41504dd539704ca4db45b883b52e7b0aa5b2fd5ddadb1452bf95cd23a69da2f793a843f9451cc9 - languageName: node - linkType: hard - "toad-cache@npm:^3.7.0": version: 3.7.0 resolution: "toad-cache@npm:3.7.0" @@ -3088,13 +2828,6 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 - languageName: node - linkType: hard - "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -3159,15 +2892,6 @@ __metadata: languageName: node linkType: hard -"walker@npm:^1.0.6": - version: 1.0.8 - resolution: "walker@npm:1.0.8" - dependencies: - makeerror: "npm:1.0.12" - checksum: 10c0/a17e037bccd3ca8a25a80cb850903facdfed0de4864bd8728f1782370715d679fa72e0a0f5da7c1c1379365159901e5935f35be531229da53bbfc0efdabdb48e - languageName: node - linkType: hard - "web@workspace:packages/web": version: 0.0.0-use.local resolution: "web@workspace:packages/web" @@ -3260,13 +2984,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.1.1": - version: 21.1.1 - resolution: "yargs-parser@npm:21.1.1" - checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 - languageName: node - linkType: hard - "zod@npm:^4.1.11": version: 4.1.11 resolution: "zod@npm:4.1.11" From 00c972f19a8cbad87c9ebe3b64d44b48c39a44f8 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 16:48:05 +0200 Subject: [PATCH 18/65] Init theme --- deep-sea-stories/packages/web/components.json | 22 + deep-sea-stories/packages/web/package.json | 10 +- deep-sea-stories/packages/web/public/vite.svg | 1 - deep-sea-stories/packages/web/src/App.css | 42 -- deep-sea-stories/packages/web/src/App.tsx | 42 +- .../packages/web/src/assets/angler.webp | Bin 0 -> 61582 bytes .../web/src/assets/fonts/AktivGrotesk.otf | Bin 0 -> 111408 bytes .../web/src/assets/fonts/AktivGrotesk.woff | Bin 0 -> 42828 bytes .../web/src/assets/fonts/AktivGrotesk.woff2 | Bin 0 -> 36688 bytes .../web/src/assets/fonts/JuneExptActive.ttf | Bin 0 -> 115836 bytes .../packages/web/src/assets/react.svg | 1 - .../packages/web/src/components/ui/button.tsx | 56 +++ deep-sea-stories/packages/web/src/index.css | 179 +++++-- .../packages/web/src/lib/utils.ts | 6 + .../packages/web/tsconfig.app.json | 22 +- deep-sea-stories/packages/web/tsconfig.json | 18 +- deep-sea-stories/packages/web/vite.config.ts | 8 + deep-sea-stories/yarn.lock | 461 +++++++++++++++++- 18 files changed, 724 insertions(+), 144 deletions(-) create mode 100644 deep-sea-stories/packages/web/components.json delete mode 100644 deep-sea-stories/packages/web/public/vite.svg delete mode 100644 deep-sea-stories/packages/web/src/App.css create mode 100644 deep-sea-stories/packages/web/src/assets/angler.webp create mode 100644 deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.otf create mode 100644 deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.woff create mode 100644 deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.woff2 create mode 100644 deep-sea-stories/packages/web/src/assets/fonts/JuneExptActive.ttf delete mode 100644 deep-sea-stories/packages/web/src/assets/react.svg create mode 100644 deep-sea-stories/packages/web/src/components/ui/button.tsx create mode 100644 deep-sea-stories/packages/web/src/lib/utils.ts diff --git a/deep-sea-stories/packages/web/components.json b/deep-sea-stories/packages/web/components.json new file mode 100644 index 0000000..364f6ca --- /dev/null +++ b/deep-sea-stories/packages/web/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index e09cb27..0494336 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -9,13 +9,20 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-slot": "^1.2.3", + "@tailwindcss/vite": "^4.1.13", "@tanstack/react-query": "^5.90.2", "@trpc/client": "^11.6.0", "@trpc/server": "^11.6.0", "@trpc/tanstack-react-query": "^11.6.0", "backend": "workspace:*", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.544.0", "react": "^19.1.1", - "react-dom": "^19.1.1" + "react-dom": "^19.1.1", + "tailwind-merge": "^3.3.1", + "tailwindcss": "^4.1.13" }, "devDependencies": { "@types/react": "^19.1.13", @@ -23,6 +30,7 @@ "@vitejs/plugin-react": "^5.0.3", "babel-plugin-react-compiler": "^19.1.0-rc.3", "globals": "^16.4.0", + "tw-animate-css": "^1.4.0", "vite": "^7.1.7" } } diff --git a/deep-sea-stories/packages/web/public/vite.svg b/deep-sea-stories/packages/web/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/deep-sea-stories/packages/web/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/deep-sea-stories/packages/web/src/App.css b/deep-sea-stories/packages/web/src/App.css deleted file mode 100644 index df674c0..0000000 --- a/deep-sea-stories/packages/web/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/deep-sea-stories/packages/web/src/App.tsx b/deep-sea-stories/packages/web/src/App.tsx index c8f1228..32767de 100644 --- a/deep-sea-stories/packages/web/src/App.tsx +++ b/deep-sea-stories/packages/web/src/App.tsx @@ -1,44 +1,10 @@ -import { useState } from 'react'; -import viteLogo from '/vite.svg'; -import reactLogo from './assets/react.svg'; -import './App.css'; +import angler from './assets/angler.webp'; function App() { - const [count, setCount] = useState(0); - return ( - <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- +
+ angler +
); } diff --git a/deep-sea-stories/packages/web/src/assets/angler.webp b/deep-sea-stories/packages/web/src/assets/angler.webp new file mode 100644 index 0000000000000000000000000000000000000000..a5fcff3e91a8d16668a23a5b8502348d20fee7d1 GIT binary patch literal 61582 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 z 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

-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�W`Pv!9IWkQbm1(4JwR@A3ytP;xM}?53Q73 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 E0NxQjEC2ui literal 0 HcmV?d00001 diff --git a/deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.otf b/deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.otf new file mode 100644 index 0000000000000000000000000000000000000000..914fb0e4102e0758cbf948d75a3896b935e973d7 GIT binary patch literal 111408 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 z𝔧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 VS)F8aoz*}#&tc!ck*ZPt008I%^^pJo literal 0 HcmV?d00001 diff --git a/deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.woff2 b/deep-sea-stories/packages/web/src/assets/fonts/AktivGrotesk.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..6642d80c8fb7d06bbab2c3a92f536dec0df867b6 GIT binary patch literal 36688 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 literal 0 HcmV?d00001 diff --git a/deep-sea-stories/packages/web/src/assets/fonts/JuneExptActive.ttf b/deep-sea-stories/packages/web/src/assets/fonts/JuneExptActive.ttf new file mode 100644 index 0000000000000000000000000000000000000000..57fe6eaa07875022e1cd21375c6f4ff55d8f1af1 GIT binary patch literal 115836 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

$&#Lj-{i$8Dd`R10$G@uk!>q30XJzO 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 literal 0 HcmV?d00001 diff --git a/deep-sea-stories/packages/web/src/assets/react.svg b/deep-sea-stories/packages/web/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/deep-sea-stories/packages/web/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/deep-sea-stories/packages/web/src/components/ui/button.tsx b/deep-sea-stories/packages/web/src/components/ui/button.tsx new file mode 100644 index 0000000..36496a2 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/button.tsx @@ -0,0 +1,56 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css index e543249..84a2bb7 100644 --- a/deep-sea-stories/packages/web/src/index.css +++ b/deep-sea-stories/packages/web/src/index.css @@ -1,68 +1,145 @@ -:root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; +@import "tailwindcss"; +@import "tw-animate-css"; - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; +@custom-variant dark (&:is(.dark *)); - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +:root { + --radius: 0.625rem; + --background: #fcf6e7; + --foreground: oklch(0.129 0.042 264.695); + --card: oklch(1 0 0); + --card-foreground: oklch(0.129 0.042 264.695); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.129 0.042 264.695); + --primary: oklch(0.208 0.042 265.755); + --primary-foreground: oklch(0.984 0.003 247.858); + --secondary: oklch(0.968 0.007 247.896); + --secondary-foreground: oklch(0.208 0.042 265.755); + --muted: oklch(0.968 0.007 247.896); + --muted-foreground: oklch(0.554 0.046 257.417); + --accent: #fad8d1; + --accent-foreground: oklch(0.208 0.042 265.755); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.929 0.013 255.508); + --input: oklch(0.929 0.013 255.508); + --ring: oklch(0.704 0.04 256.788); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.984 0.003 247.858); + --sidebar-foreground: oklch(0.129 0.042 264.695); + --sidebar-primary: oklch(0.208 0.042 265.755); + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); + --sidebar-accent: oklch(0.968 0.007 247.896); + --sidebar-accent-foreground: oklch(0.208 0.042 265.755); + --sidebar-border: oklch(0.929 0.013 255.508); + --sidebar-ring: oklch(0.704 0.04 256.788); } -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; +@font-face { + font-family: aktiv-grotesk; + src: + url("./assets/fonts/AktivGrotesk.woff2") format("woff2"), + url("./assets/fonts/AktivGrotesk.woff") format("woff"), + url("./assets/fonts/AktivGrotesk.otf") format("opentype"); + font-display: auto; } -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; +@font-face { + font-family: june-expt; + src: url("./assets/fonts/JuneExptActive.ttf") format("truetype"); + font-display: auto; } -h1 { - font-size: 3.2em; - line-height: 1.1; +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); } -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; +.dark { + --background: oklch(0.129 0.042 264.695); + --foreground: oklch(0.984 0.003 247.858); + --card: oklch(0.208 0.042 265.755); + --card-foreground: oklch(0.984 0.003 247.858); + --popover: oklch(0.208 0.042 265.755); + --popover-foreground: oklch(0.984 0.003 247.858); + --primary: oklch(0.929 0.013 255.508); + --primary-foreground: oklch(0.208 0.042 265.755); + --secondary: oklch(0.279 0.041 260.031); + --secondary-foreground: oklch(0.984 0.003 247.858); + --muted: oklch(0.279 0.041 260.031); + --muted-foreground: oklch(0.704 0.04 256.788); + --accent: oklch(0.279 0.041 260.031); + --accent-foreground: oklch(0.984 0.003 247.858); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.551 0.027 264.364); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.208 0.042 265.755); + --sidebar-foreground: oklch(0.984 0.003 247.858); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); + --sidebar-accent: oklch(0.279 0.041 260.031); + --sidebar-accent-foreground: oklch(0.984 0.003 247.858); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.551 0.027 264.364); } -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; + +@theme { + --font-sans: aktiv-grotesk, sans-serif; + --font-display: june-expt, sans-serif; } -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; +@layer base { + * { + @apply border-border outline-ring/50; } - a:hover { - color: #747bff; + body { + @apply bg-background text-foreground; } - button { - background-color: #f9f9f9; + + button:not([disabled]), + [role="button"]:not([disabled]) { + cursor: pointer; } } diff --git a/deep-sea-stories/packages/web/src/lib/utils.ts b/deep-sea-stories/packages/web/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/deep-sea-stories/packages/web/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/deep-sea-stories/packages/web/tsconfig.app.json b/deep-sea-stories/packages/web/tsconfig.app.json index f5e68b3..d6d2a9b 100644 --- a/deep-sea-stories/packages/web/tsconfig.app.json +++ b/deep-sea-stories/packages/web/tsconfig.app.json @@ -2,9 +2,15 @@ "compilerOptions": { "target": "ES2022", "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], "module": "ESNext", - "types": ["vite/client"], + "types": [ + "vite/client" + ], "skipLibCheck": true, /* Bundler mode */ "moduleResolution": "bundler", @@ -19,7 +25,15 @@ "noUnusedParameters": true, "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } }, - "include": ["src"] + "include": [ + "src" + ] } diff --git a/deep-sea-stories/packages/web/tsconfig.json b/deep-sea-stories/packages/web/tsconfig.json index fb12418..eeabc0d 100644 --- a/deep-sea-stories/packages/web/tsconfig.json +++ b/deep-sea-stories/packages/web/tsconfig.json @@ -1,7 +1,19 @@ { "files": [], "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + } } diff --git a/deep-sea-stories/packages/web/vite.config.ts b/deep-sea-stories/packages/web/vite.config.ts index e22b3b8..d685860 100644 --- a/deep-sea-stories/packages/web/vite.config.ts +++ b/deep-sea-stories/packages/web/vite.config.ts @@ -1,3 +1,5 @@ +import path from 'node:path'; +import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; @@ -9,5 +11,11 @@ export default defineConfig({ plugins: [['babel-plugin-react-compiler']], }, }), + tailwindcss(), ], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, }); diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index c6a5e2d..0d1d3c4 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -300,6 +300,34 @@ __metadata: languageName: node linkType: hard +"@emnapi/core@npm:^1.4.3, @emnapi/core@npm:^1.4.5": + version: 1.5.0 + resolution: "@emnapi/core@npm:1.5.0" + dependencies: + "@emnapi/wasi-threads": "npm:1.1.0" + tslib: "npm:^2.4.0" + checksum: 10c0/52ba3485277706d92fa27d92b37e5b4f6ef0742c03ed68f8096f294c6bfa30f0752c82d4c2bfa14bff4dc30d63c9f71a8f9fb64a92743d00807d9e468fafd5ff + languageName: node + linkType: hard + +"@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.4.5": + version: 1.5.0 + resolution: "@emnapi/runtime@npm:1.5.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/a85c9fc4e3af49cbe41e5437e5be2551392a931910cd0a5b5d3572532786927810c9cc1db11b232ec8f9657b33d4e6f7c4f985f1a052917d7cd703b5b2a20faa + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.1.0, @emnapi/wasi-threads@npm:^1.0.4": + version: 1.1.0 + resolution: "@emnapi/wasi-threads@npm:1.1.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/e6d54bf2b1e64cdd83d2916411e44e579b6ae35d5def0dea61a3c452d9921373044dff32a8b8473ae60c80692bdc39323e98b96a3f3d87ba6886b24dd0ef7ca1 + languageName: node + linkType: hard + "@esbuild/aix-ppc64@npm:0.25.10": version: 0.25.10 resolution: "@esbuild/aix-ppc64@npm:0.25.10" @@ -578,7 +606,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/remapping@npm:^2.3.5": +"@jridgewell/remapping@npm:^2.3.4, @jridgewell/remapping@npm:^2.3.5": version: 2.3.5 resolution: "@jridgewell/remapping@npm:2.3.5" dependencies: @@ -595,7 +623,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5": version: 1.5.5 resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 @@ -612,6 +640,17 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^0.2.12": + version: 0.2.12 + resolution: "@napi-rs/wasm-runtime@npm:0.2.12" + dependencies: + "@emnapi/core": "npm:^1.4.3" + "@emnapi/runtime": "npm:^1.4.3" + "@tybys/wasm-util": "npm:^0.10.0" + checksum: 10c0/6d07922c0613aab30c6a497f4df297ca7c54e5b480e00035e0209b872d5c6aab7162fc49477267556109c2c7ed1eb9c65a174e27e9b87568106a87b0a6e3ca7d + languageName: node + linkType: hard + "@npmcli/agent@npm:^3.0.0": version: 3.0.0 resolution: "@npmcli/agent@npm:3.0.0" @@ -641,6 +680,34 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-compose-refs@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-compose-refs@npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d36a9c589eb75d634b9b139c80f916aadaf8a68a7c1c4b8c6c6b88755af1a92f2e343457042089f04cc3f23073619d08bb65419ced1402e9d4e299576d970771 + languageName: node + linkType: hard + +"@radix-ui/react-slot@npm:^1.2.3": + version: 1.2.3 + resolution: "@radix-ui/react-slot@npm:1.2.3" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5913aa0d760f505905779515e4b1f0f71a422350f077cc8d26d1aafe53c97f177fec0e6d7fbbb50d8b5e498aa9df9f707ca75ae3801540c283b26b0136138eef + languageName: node + linkType: hard + "@rolldown/pluginutils@npm:1.0.0-beta.38": version: 1.0.0-beta.38 resolution: "@rolldown/pluginutils@npm:1.0.0-beta.38" @@ -802,6 +869,172 @@ __metadata: languageName: node linkType: hard +"@tailwindcss/node@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/node@npm:4.1.13" + dependencies: + "@jridgewell/remapping": "npm:^2.3.4" + enhanced-resolve: "npm:^5.18.3" + jiti: "npm:^2.5.1" + lightningcss: "npm:1.30.1" + magic-string: "npm:^0.30.18" + source-map-js: "npm:^1.2.1" + tailwindcss: "npm:4.1.13" + checksum: 10c0/969b2eaefced271655fdf53a07737103736115c6b55fa1559c78147d17871da988c165ab2236bf4da8cdbde1e50a5116b8df2225e20f63de981d43da5b69e3f1 + languageName: node + linkType: hard + +"@tailwindcss/oxide-android-arm64@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-android-arm64@npm:4.1.13" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@tailwindcss/oxide-darwin-arm64@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-darwin-arm64@npm:4.1.13" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@tailwindcss/oxide-darwin-x64@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-darwin-x64@npm:4.1.13" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@tailwindcss/oxide-freebsd-x64@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-freebsd-x64@npm:4.1.13" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.1.13" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@tailwindcss/oxide-linux-arm64-gnu@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-linux-arm64-gnu@npm:4.1.13" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@tailwindcss/oxide-linux-arm64-musl@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-linux-arm64-musl@npm:4.1.13" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@tailwindcss/oxide-linux-x64-gnu@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-linux-x64-gnu@npm:4.1.13" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@tailwindcss/oxide-linux-x64-musl@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-linux-x64-musl@npm:4.1.13" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@tailwindcss/oxide-wasm32-wasi@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-wasm32-wasi@npm:4.1.13" + dependencies: + "@emnapi/core": "npm:^1.4.5" + "@emnapi/runtime": "npm:^1.4.5" + "@emnapi/wasi-threads": "npm:^1.0.4" + "@napi-rs/wasm-runtime": "npm:^0.2.12" + "@tybys/wasm-util": "npm:^0.10.0" + tslib: "npm:^2.8.0" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@tailwindcss/oxide-win32-arm64-msvc@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-win32-arm64-msvc@npm:4.1.13" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@tailwindcss/oxide-win32-x64-msvc@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide-win32-x64-msvc@npm:4.1.13" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@tailwindcss/oxide@npm:4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/oxide@npm:4.1.13" + dependencies: + "@tailwindcss/oxide-android-arm64": "npm:4.1.13" + "@tailwindcss/oxide-darwin-arm64": "npm:4.1.13" + "@tailwindcss/oxide-darwin-x64": "npm:4.1.13" + "@tailwindcss/oxide-freebsd-x64": "npm:4.1.13" + "@tailwindcss/oxide-linux-arm-gnueabihf": "npm:4.1.13" + "@tailwindcss/oxide-linux-arm64-gnu": "npm:4.1.13" + "@tailwindcss/oxide-linux-arm64-musl": "npm:4.1.13" + "@tailwindcss/oxide-linux-x64-gnu": "npm:4.1.13" + "@tailwindcss/oxide-linux-x64-musl": "npm:4.1.13" + "@tailwindcss/oxide-wasm32-wasi": "npm:4.1.13" + "@tailwindcss/oxide-win32-arm64-msvc": "npm:4.1.13" + "@tailwindcss/oxide-win32-x64-msvc": "npm:4.1.13" + detect-libc: "npm:^2.0.4" + tar: "npm:^7.4.3" + dependenciesMeta: + "@tailwindcss/oxide-android-arm64": + optional: true + "@tailwindcss/oxide-darwin-arm64": + optional: true + "@tailwindcss/oxide-darwin-x64": + optional: true + "@tailwindcss/oxide-freebsd-x64": + optional: true + "@tailwindcss/oxide-linux-arm-gnueabihf": + optional: true + "@tailwindcss/oxide-linux-arm64-gnu": + optional: true + "@tailwindcss/oxide-linux-arm64-musl": + optional: true + "@tailwindcss/oxide-linux-x64-gnu": + optional: true + "@tailwindcss/oxide-linux-x64-musl": + optional: true + "@tailwindcss/oxide-wasm32-wasi": + optional: true + "@tailwindcss/oxide-win32-arm64-msvc": + optional: true + "@tailwindcss/oxide-win32-x64-msvc": + optional: true + checksum: 10c0/7cc64827b0c854724a3b371a7f1484535db5cca9f53dda359631bce9c42b043f2822db6c5359f7ed9f1c8adbc48ecb52c414454f9330ffd25a9a679686d2a83e + languageName: node + linkType: hard + +"@tailwindcss/vite@npm:^4.1.13": + version: 4.1.13 + resolution: "@tailwindcss/vite@npm:4.1.13" + dependencies: + "@tailwindcss/node": "npm:4.1.13" + "@tailwindcss/oxide": "npm:4.1.13" + tailwindcss: "npm:4.1.13" + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + checksum: 10c0/4e9b1d54a64655b775f26816a7be52236d4716a35f88af6b835fcb4f7f466db3c9cbb6c052e5550a97b3e5cff821f337cd6d9ddefd480e71db21a2844719b20e + languageName: node + linkType: hard + "@tanstack/query-core@npm:5.90.2": version: 5.90.2 resolution: "@tanstack/query-core@npm:5.90.2" @@ -860,6 +1093,15 @@ __metadata: languageName: node linkType: hard +"@tybys/wasm-util@npm:^0.10.0": + version: 0.10.1 + resolution: "@tybys/wasm-util@npm:0.10.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/b255094f293794c6d2289300c5fbcafbb5532a3aed3a5ffd2f8dc1828e639b88d75f6a376dd8f94347a44813fd7a7149d8463477a9a49525c8b2dcaa38c2d1e8 + languageName: node + linkType: hard + "@types/babel__core@npm:^7.20.5": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" @@ -1186,6 +1428,22 @@ __metadata: languageName: node linkType: hard +"class-variance-authority@npm:^0.7.1": + version: 0.7.1 + resolution: "class-variance-authority@npm:0.7.1" + dependencies: + clsx: "npm:^2.1.1" + checksum: 10c0/0f438cea22131808b99272de0fa933c2532d5659773bfec0c583de7b3f038378996d3350683426b8e9c74a6286699382106d71fbec52f0dd5fbb191792cccb5b + languageName: node + linkType: hard + +"clsx@npm:^2.1.1": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -1292,6 +1550,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.3, detect-libc@npm:^2.0.4": + version: 2.1.1 + resolution: "detect-libc@npm:2.1.1" + checksum: 10c0/97053299c1f68c7c4adf7b78c8d506e1d5f3a3fbc775920aaa0ecf7f8fcc6dfa46338a6ca82fe4500b4a51937def314584265a4ec9d565577485c4496aa7d64e + languageName: node + linkType: hard + "dotenv@npm:^17.2.3": version: 17.2.3 resolution: "dotenv@npm:17.2.3" @@ -1356,6 +1621,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.18.3": + version: 5.18.3 + resolution: "enhanced-resolve@npm:5.18.3" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: 10c0/d413c23c2d494e4c1c9c9ac7d60b812083dc6d446699ed495e69c920988af0a3c66bf3f8d0e7a45cb1686c2d4c1df9f4e7352d973f5b56fe63d8d711dd0ccc54 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -1773,7 +2048,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -1903,6 +2178,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:^2.5.1": + version: 2.6.1 + resolution: "jiti@npm:2.6.1" + bin: + jiti: lib/jiti-cli.mjs + checksum: 10c0/79b2e96a8e623f66c1b703b98ec1b8be4500e1d217e09b09e343471bbb9c105381b83edbb979d01cef18318cc45ce6e153571b6c83122170eefa531c64b6789b + languageName: node + linkType: hard + "joycon@npm:^3.1.1": version: 3.1.1 resolution: "joycon@npm:3.1.1" @@ -1962,6 +2246,116 @@ __metadata: languageName: node linkType: hard +"lightningcss-darwin-arm64@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-darwin-arm64@npm:1.30.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-x64@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-darwin-x64@npm:1.30.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-freebsd-x64@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-freebsd-x64@npm:1.30.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-linux-arm-gnueabihf@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.30.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"lightningcss-linux-arm64-gnu@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-arm64-gnu@npm:1.30.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-arm64-musl@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-arm64-musl@npm:1.30.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-linux-x64-gnu@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-x64-gnu@npm:1.30.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-x64-musl@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-x64-musl@npm:1.30.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-win32-arm64-msvc@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-win32-arm64-msvc@npm:1.30.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-win32-x64-msvc@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-win32-x64-msvc@npm:1.30.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"lightningcss@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss@npm:1.30.1" + dependencies: + detect-libc: "npm:^2.0.3" + lightningcss-darwin-arm64: "npm:1.30.1" + lightningcss-darwin-x64: "npm:1.30.1" + lightningcss-freebsd-x64: "npm:1.30.1" + lightningcss-linux-arm-gnueabihf: "npm:1.30.1" + lightningcss-linux-arm64-gnu: "npm:1.30.1" + lightningcss-linux-arm64-musl: "npm:1.30.1" + lightningcss-linux-x64-gnu: "npm:1.30.1" + lightningcss-linux-x64-musl: "npm:1.30.1" + lightningcss-win32-arm64-msvc: "npm:1.30.1" + lightningcss-win32-x64-msvc: "npm:1.30.1" + dependenciesMeta: + lightningcss-darwin-arm64: + optional: true + lightningcss-darwin-x64: + optional: true + lightningcss-freebsd-x64: + optional: true + lightningcss-linux-arm-gnueabihf: + optional: true + lightningcss-linux-arm64-gnu: + optional: true + lightningcss-linux-arm64-musl: + optional: true + lightningcss-linux-x64-gnu: + optional: true + lightningcss-linux-x64-musl: + optional: true + lightningcss-win32-arm64-msvc: + optional: true + lightningcss-win32-x64-msvc: + optional: true + checksum: 10c0/1e1ad908f3c68bf39d964a6735435a8dd5474fb2765076732d64a7b6aa2af1f084da65a9462443a9adfebf7dcfb02fb532fce1d78697f2a9de29c8f40f09aee3 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -1978,6 +2372,24 @@ __metadata: languageName: node linkType: hard +"lucide-react@npm:^0.544.0": + version: 0.544.0 + resolution: "lucide-react@npm:0.544.0" + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/2503f8cf65e62915997073b6053423bf8091b9470cb397560b417ef2f1628ea162c49e821b787cf153afb86828482d941f051c3f2aa642a1fa58c3de227e0113 + languageName: node + linkType: hard + +"magic-string@npm:^0.30.18": + version: 0.30.19 + resolution: "magic-string@npm:0.30.19" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + checksum: 10c0/db23fd2e2ee98a1aeb88a4cdb2353137fcf05819b883c856dd79e4c7dfb25151e2a5a4d5dbd88add5e30ed8ae5c51bcf4accbc6becb75249d924ec7b4fbcae27 + languageName: node + linkType: hard + "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" @@ -2714,6 +3126,27 @@ __metadata: languageName: node linkType: hard +"tailwind-merge@npm:^3.3.1": + version: 3.3.1 + resolution: "tailwind-merge@npm:3.3.1" + checksum: 10c0/b84c6a78d4669fa12bf5ab8f0cdc4400a3ce0a7c006511af4af4be70bb664a27466dbe13ee9e3b31f50ddf6c51d380e8192ce0ec9effce23ca729d71a9f63818 + languageName: node + linkType: hard + +"tailwindcss@npm:4.1.13, tailwindcss@npm:^4.1.13": + version: 4.1.13 + resolution: "tailwindcss@npm:4.1.13" + checksum: 10c0/2b80b4b11463818fd16063b7cc13fd0f6e18d7e3c3e54bbdc98742981be807884addb1dd657bc6816cb4085197b7d583f5064f619e1039a54221ffa36b7ed4c0 + languageName: node + linkType: hard + +"tapable@npm:^2.2.0": + version: 2.2.3 + resolution: "tapable@npm:2.2.3" + checksum: 10c0/e57fd8e2d756c317f8726a1bec8f2c904bc42e37fcbd4a78211daeab89f42c734b6a20e61774321f47be9a421da628a0c78b62d36c5ed186f4d5232d09ae15f2 + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.5.1 resolution: "tar@npm:7.5.1" @@ -2753,6 +3186,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.4.0, tslib@npm:^2.8.0": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "tsx@npm:^4.20.6": version: 4.20.6 resolution: "tsx@npm:4.20.6" @@ -2769,6 +3209,13 @@ __metadata: languageName: node linkType: hard +"tw-animate-css@npm:^1.4.0": + version: 1.4.0 + resolution: "tw-animate-css@npm:1.4.0" + checksum: 10c0/6cfbc19ccc73883ec80ef1f9147f43e736cb01ee99c8172968b37eb81b720523d30e38b1a96aef92db3c586d864204db5510b51744ddacbbf0ad8e3c7fb56ec7 + languageName: node + linkType: hard + "typescript@npm:^5.9.2": version: 5.9.2 resolution: "typescript@npm:5.9.2" @@ -2896,6 +3343,8 @@ __metadata: version: 0.0.0-use.local resolution: "web@workspace:packages/web" dependencies: + "@radix-ui/react-slot": "npm:^1.2.3" + "@tailwindcss/vite": "npm:^4.1.13" "@tanstack/react-query": "npm:^5.90.2" "@trpc/client": "npm:^11.6.0" "@trpc/server": "npm:^11.6.0" @@ -2905,9 +3354,15 @@ __metadata: "@vitejs/plugin-react": "npm:^5.0.3" babel-plugin-react-compiler: "npm:^19.1.0-rc.3" backend: "workspace:*" + class-variance-authority: "npm:^0.7.1" + clsx: "npm:^2.1.1" globals: "npm:^16.4.0" + lucide-react: "npm:^0.544.0" react: "npm:^19.1.1" react-dom: "npm:^19.1.1" + tailwind-merge: "npm:^3.3.1" + tailwindcss: "npm:^4.1.13" + tw-animate-css: "npm:^1.4.0" vite: "npm:^7.1.7" languageName: unknown linkType: soft From 7482924d72cb91199f781fc95af187ff176f945a Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 16:52:17 +0200 Subject: [PATCH 19/65] Format and lint --- deep-sea-stories/packages/web/components.json | 40 ++++---- .../packages/web/src/components/ui/button.tsx | 94 +++++++++---------- deep-sea-stories/packages/web/src/index.css | 2 + .../packages/web/src/lib/utils.ts | 6 +- .../packages/web/tsconfig.app.json | 18 +--- deep-sea-stories/packages/web/tsconfig.json | 4 +- 6 files changed, 77 insertions(+), 87 deletions(-) diff --git a/deep-sea-stories/packages/web/components.json b/deep-sea-stories/packages/web/components.json index 364f6ca..e05588c 100644 --- a/deep-sea-stories/packages/web/components.json +++ b/deep-sea-stories/packages/web/components.json @@ -1,22 +1,22 @@ { - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "", - "css": "src/index.css", - "baseColor": "slate", - "cssVariables": true, - "prefix": "" - }, - "iconLibrary": "lucide", - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "registries": {} + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} } diff --git a/deep-sea-stories/packages/web/src/components/ui/button.tsx b/deep-sea-stories/packages/web/src/components/ui/button.tsx index 36496a2..754a1d0 100644 --- a/deep-sea-stories/packages/web/src/components/ui/button.tsx +++ b/deep-sea-stories/packages/web/src/components/ui/button.tsx @@ -1,56 +1,56 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) + 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; } const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + }, +); +Button.displayName = 'Button'; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css index 84a2bb7..90d3dc9 100644 --- a/deep-sea-stories/packages/web/src/index.css +++ b/deep-sea-stories/packages/web/src/index.css @@ -1,3 +1,5 @@ +/* biome-ignore-all lint/suspicious/noUnknownAtRules: tailwind */ + @import "tailwindcss"; @import "tw-animate-css"; diff --git a/deep-sea-stories/packages/web/src/lib/utils.ts b/deep-sea-stories/packages/web/src/lib/utils.ts index bd0c391..256f86f 100644 --- a/deep-sea-stories/packages/web/src/lib/utils.ts +++ b/deep-sea-stories/packages/web/src/lib/utils.ts @@ -1,6 +1,6 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); } diff --git a/deep-sea-stories/packages/web/tsconfig.app.json b/deep-sea-stories/packages/web/tsconfig.app.json index d6d2a9b..c40e9bf 100644 --- a/deep-sea-stories/packages/web/tsconfig.app.json +++ b/deep-sea-stories/packages/web/tsconfig.app.json @@ -2,15 +2,9 @@ "compilerOptions": { "target": "ES2022", "useDefineForClassFields": true, - "lib": [ - "ES2022", - "DOM", - "DOM.Iterable" - ], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", - "types": [ - "vite/client" - ], + "types": ["vite/client"], "skipLibCheck": true, /* Bundler mode */ "moduleResolution": "bundler", @@ -28,12 +22,8 @@ "noUncheckedSideEffectImports": true, "baseUrl": ".", "paths": { - "@/*": [ - "./src/*" - ] + "@/*": ["./src/*"] } }, - "include": [ - "src" - ] + "include": ["src"] } diff --git a/deep-sea-stories/packages/web/tsconfig.json b/deep-sea-stories/packages/web/tsconfig.json index eeabc0d..827701b 100644 --- a/deep-sea-stories/packages/web/tsconfig.json +++ b/deep-sea-stories/packages/web/tsconfig.json @@ -11,9 +11,7 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": [ - "./src/*" - ] + "@/*": ["./src/*"] } } } From 519a31b249ed63ab571a59f9d2450439854c722a Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Wed, 1 Oct 2025 17:00:12 +0200 Subject: [PATCH 20/65] Include fishjam --- deep-sea-stories/packages/web/.env.example | 2 + deep-sea-stories/packages/web/package.json | 1 + deep-sea-stories/packages/web/src/main.tsx | 9 ++- deep-sea-stories/yarn.lock | 76 +++++++++++++++++++++- 4 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 deep-sea-stories/packages/web/.env.example diff --git a/deep-sea-stories/packages/web/.env.example b/deep-sea-stories/packages/web/.env.example new file mode 100644 index 0000000..a041231 --- /dev/null +++ b/deep-sea-stories/packages/web/.env.example @@ -0,0 +1,2 @@ +VITE_BACKEND_URL="" +VITE_FISHJAM_ID="" diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 0494336..cb92638 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "@fishjam-cloud/react-client": "^0.20.0", "@radix-ui/react-slot": "^1.2.3", "@tailwindcss/vite": "^4.1.13", "@tanstack/react-query": "^5.90.2", diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index 1027a0d..fd05ebd 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -1,9 +1,10 @@ +import { FishjamProvider } from '@fishjam-cloud/react-client'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import './index.css'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import App from './App.tsx'; import { TRPCClientProvider } from './contexts/trpc.tsx'; +import './index.css'; const queryClient = new QueryClient({ defaultOptions: { @@ -18,7 +19,9 @@ createRoot(document.getElementById('root')!).render( - + + + , diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 0d1d3c4..b06a26d 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -209,6 +209,13 @@ __metadata: languageName: node linkType: hard +"@binbat/whip-whep@npm:^1.1.1-sdp-trickle-throw": + version: 1.1.1-sdp-trickle-throw + resolution: "@binbat/whip-whep@npm:1.1.1-sdp-trickle-throw" + checksum: 10c0/073dc456898c51cccfa3bc766741d84b883881bf0dfa9b663bb3e42d5eba3d9843447c85892662d7c98221fdbb4e9d4858b56533241f919c5699b8bb54a059d7 + languageName: node + linkType: hard + "@biomejs/biome@npm:2.2.4": version: 2.2.4 resolution: "@biomejs/biome@npm:2.2.4" @@ -300,6 +307,13 @@ __metadata: languageName: node linkType: hard +"@bufbuild/protobuf@npm:^2.2.3": + version: 2.9.0 + resolution: "@bufbuild/protobuf@npm:2.9.0" + checksum: 10c0/fe46723c12204c00ff1f4eefb3636a7e7ad9e3c87736ed92e9de77aad6f29edae9b903a1517bb0cd8d1b24da46934ab1ae7acebc04c151b8f3a6151b7583f20f + languageName: node + linkType: hard + "@emnapi/core@npm:^1.4.3, @emnapi/core@npm:^1.4.5": version: 1.5.0 resolution: "@emnapi/core@npm:1.5.0" @@ -573,6 +587,30 @@ __metadata: languageName: node linkType: hard +"@fishjam-cloud/react-client@npm:^0.20.0": + version: 0.20.0 + resolution: "@fishjam-cloud/react-client@npm:0.20.0" + dependencies: + "@fishjam-cloud/ts-client": "npm:0.20.0" + events: "npm:3.3.0" + lodash.isequal: "npm:4.5.0" + checksum: 10c0/1cb74e11e2f193881d548963ee9acc19a24e6c1f8c2263de7636446bc4186f71d1cc7883e4087511ec04bd3582cd32657f51383ee4c3418b57cea56a29f9a1cb + languageName: node + linkType: hard + +"@fishjam-cloud/ts-client@npm:0.20.0": + version: 0.20.0 + resolution: "@fishjam-cloud/ts-client@npm:0.20.0" + dependencies: + "@binbat/whip-whep": "npm:^1.1.1-sdp-trickle-throw" + "@bufbuild/protobuf": "npm:^2.2.3" + events: "npm:^3.3.0" + typed-emitter: "npm:^2.1.0" + uuid: "npm:^11.1.0" + checksum: 10c0/78b831399d56c012b65882af70ac87b44c022c4bcec72612e9e90baef839665a5795bfdc9f0e0ed902bab8ecb3f1cb9946b1b9a5a006ad4fcf0eabc2dafc99f2 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -1776,6 +1814,13 @@ __metadata: languageName: node linkType: hard +"events@npm:3.3.0, events@npm:^3.3.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -2356,6 +2401,13 @@ __metadata: languageName: node linkType: hard +"lodash.isequal@npm:4.5.0": + version: 4.5.0 + resolution: "lodash.isequal@npm:4.5.0" + checksum: 10c0/dfdb2356db19631a4b445d5f37868a095e2402292d59539a987f134a8778c62a2810c2452d11ae9e6dcac71fc9de40a6fedcb20e2952a15b431ad8b29e50e28f + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -2927,6 +2979,15 @@ __metadata: languageName: node linkType: hard +"rxjs@npm:*": + version: 7.8.2 + resolution: "rxjs@npm:7.8.2" + dependencies: + tslib: "npm:^2.1.0" + checksum: 10c0/1fcd33d2066ada98ba8f21fcbbcaee9f0b271de1d38dc7f4e256bfbc6ffcdde68c8bfb69093de7eeb46f24b1fb820620bf0223706cff26b4ab99a7ff7b2e2c45 + languageName: node + linkType: hard + "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -3186,7 +3247,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.8.0": +"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -3216,6 +3277,18 @@ __metadata: languageName: node linkType: hard +"typed-emitter@npm:^2.1.0": + version: 2.1.0 + resolution: "typed-emitter@npm:2.1.0" + dependencies: + rxjs: "npm:*" + dependenciesMeta: + rxjs: + optional: true + checksum: 10c0/01fc354ba8e87bd39b1bf4fe1c96fe7ecff7fde83161003b0f8c7f4b285a368052e185ba655dd8c102c4445301b7a1e032c8972f181b440fc95bd810450f1314 + languageName: node + linkType: hard + "typescript@npm:^5.9.2": version: 5.9.2 resolution: "typescript@npm:5.9.2" @@ -3343,6 +3416,7 @@ __metadata: version: 0.0.0-use.local resolution: "web@workspace:packages/web" dependencies: + "@fishjam-cloud/react-client": "npm:^0.20.0" "@radix-ui/react-slot": "npm:^1.2.3" "@tailwindcss/vite": "npm:^4.1.13" "@tanstack/react-query": "npm:^5.90.2" From 5ed9902067e8a5ccf964cd461224a5423f5e3dcf Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Wed, 1 Oct 2025 17:52:58 +0200 Subject: [PATCH 21/65] Draft backend --- .../packages/backend/package.json | 1 + .../packages/backend/src/config.ts | 11 +- .../packages/backend/src/controllers/peers.ts | 21 + .../packages/backend/src/prompts/greet.md | 0 .../backend/src/prompts/instructions.md | 48 ++ .../packages/backend/src/router.ts | 6 +- .../packages/backend/src/schemas.ts | 1 + .../packages/backend/src/service/agent.ts | 9 + .../packages/backend/src/service/notifier.ts | 14 + deep-sea-stories/yarn.lock | 743 +++++++++++++++++- 10 files changed, 810 insertions(+), 44 deletions(-) create mode 100644 deep-sea-stories/packages/backend/src/controllers/peers.ts create mode 100644 deep-sea-stories/packages/backend/src/prompts/greet.md create mode 100644 deep-sea-stories/packages/backend/src/prompts/instructions.md create mode 100644 deep-sea-stories/packages/backend/src/service/agent.ts create mode 100644 deep-sea-stories/packages/backend/src/service/notifier.ts diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index f54381f..98263a6 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -5,6 +5,7 @@ "type": "module", "dependencies": { "@fishjam-cloud/js-server-sdk": "^0.21.0", + "@openai/agents-realtime": "^0.1.7", "@trpc/server": "^11.6.0", "dotenv": "^17.2.3", "fastify": "^5.6.1", diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index da84587..56f2110 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -1,13 +1,16 @@ import dotenv from 'dotenv'; import z from 'zod'; +import * as fs from 'fs'; dotenv.config(); export const configSchema = z.object({ - PORT: z.coerce.number().int().default(8000), - FISHJAM_ID: z.string(), - FISHJAM_URL: z.string().optional(), - FISHJAM_MANAGEMENT_TOKEN: z.string(), + PORT: z.coerce.number().int().default(8000), + FISHJAM_ID: z.string(), + FISHJAM_URL: z.string().optional(), + FISHJAM_MANAGEMENT_TOKEN: z.string(), }); export const CONFIG = configSchema.parse(process.env); + +export const AGENT_INSTRUCTIONS = fs.readFileSync('./prompts/instructions.md', 'utf8'); diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts new file mode 100644 index 0000000..ce5174f --- /dev/null +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -0,0 +1,21 @@ +import type { RoomId } from '@fishjam-cloud/js-server-sdk'; +import { z } from 'zod'; +import { publicProcedure } from '../trpc.js'; + +const createPeerInputSchema = z.object({ + roomId: z.string(), + displayName: z.string().optional(), +}); + +export const createPeer = publicProcedure + .input(createPeerInputSchema) + .mutation(async ({ ctx, input }) => { + const peer = await ctx.fishjam.createPeer(input.roomId as RoomId, { + enableSimulcast: true, + }); + + return { + peer: peer.peer, + token: peer.peerToken, + }; + }); diff --git a/deep-sea-stories/packages/backend/src/prompts/greet.md b/deep-sea-stories/packages/backend/src/prompts/greet.md new file mode 100644 index 0000000..e69de29 diff --git a/deep-sea-stories/packages/backend/src/prompts/instructions.md b/deep-sea-stories/packages/backend/src/prompts/instructions.md new file mode 100644 index 0000000..555083b --- /dev/null +++ b/deep-sea-stories/packages/backend/src/prompts/instructions.md @@ -0,0 +1,48 @@ +We will play a game called Black Stories +Game Rules + +Black Stories is a storytelling and guessing game designed to challenge players' deductive reasoning skills through mysterious and often morbid scenarios. Here's how it generally works: + + Players: The game requires at least two players – one person acts as the "riddle master" (the one who knows the full story of the scenario), and the rest are the guessers. + + + Game Cards: The game consists of cards, each containing a brief and cryptic description of a mysterious, usually dark incident on the front, such as an unusual death or crime. The back of the card reveals the full backstory and how the scenario occurred. + + + Objective: The goal for the guessers is to reconstruct the full story of the scenario using yes-or-no questions based on the limited information provided. + + + Gameplay: + + The riddle master reads the initial scenario or mystery to the guessers. + + The guessers ask the riddle master questions that can only be answered with "yes" or "no". + + The riddle master responds truthfully to each question. + + If the guessers think they have correctly pieced together the backstory of the scenario, as detailed on the back of the card, then they may tell the riddle master the full story. + + If they guess all the key aspects of the backstory correctly, then they win. The riddle master tells them that they have won and reads them the exact wording of the back of the card. Otherwise, the game continues and the riddle master may try to give a suggestion to a part of the story that the guessers have not included in their answer. + + + + Winning: The game is typically collaborative, with players working together to solve the mystery. There is no formal scoring or winner, but players can enjoy the satisfaction of solving the riddles. + How we will play +Your role + + You will play as the riddle master. + + +My role + + I will play as a guesser. + +Your card content is: + +### Front of the Card + +A man was found dead in the middle of a field. There were no footprints around him and he had nothing in his hands. The only thing on him was a small parachute harness without a parachute attached. + +### Back of the Card + +The man was a skydiver. He had gone on a jump with a group of skydivers and had accidentally grabbed a faulty parachute. Mid-air, when he realized it was not functional, he attempted to fix it but couldn't. As he descended, the wind blew him away from the group, causing him to land in the open field, without any footprints nearby due to being airborne before the landing. diff --git a/deep-sea-stories/packages/backend/src/router.ts b/deep-sea-stories/packages/backend/src/router.ts index 8f11005..924ec02 100644 --- a/deep-sea-stories/packages/backend/src/router.ts +++ b/deep-sea-stories/packages/backend/src/router.ts @@ -1,9 +1,11 @@ import { createRoom, getRoom } from './controllers/rooms.js'; +import { createPeer } from './controllers/peers.js'; import { router } from './trpc.js'; export const appRouter = router({ - createRoom, - getRoom, + createRoom, + getRoom, + createPeer, }); export type AppRouter = typeof appRouter; diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts index a4f162c..4431159 100644 --- a/deep-sea-stories/packages/backend/src/schemas.ts +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -1,3 +1,4 @@ import z from 'zod'; export const getRoomInputSchema = z.object({ roomId: z.string() }); + diff --git a/deep-sea-stories/packages/backend/src/service/agent.ts b/deep-sea-stories/packages/backend/src/service/agent.ts new file mode 100644 index 0000000..6f82132 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/agent.ts @@ -0,0 +1,9 @@ +import { RealtimeAgent } from "@openai/agents-realtime"; +import { AGENT_INSTRUCTIONS } from "../config.js"; + +export function getRealtimeAgent(): RealtimeAgent { + return new RealtimeAgent({ + name: 'Riddle Master', + instructions: AGENT_INSTRUCTIONS + }) +} diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts new file mode 100644 index 0000000..a051b0b --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -0,0 +1,14 @@ +import { FishjamWSNotifier, FishjamConfig } from "@fishjam-cloud/js-server-sdk"; +import { RealtimeSession } from "@openai/agents-realtime"; +import { getRealtimeAgent } from "./agent.js"; + +export async function getNotifier(session: RealtimeSession, config: FishjamConfig): Promise { + const notifier = new FishjamWSNotifier(config, () => { }, () => { }); + + notifier.on('peerConnected', () => { + const agent = getRealtimeAgent(); + const session = new RealtimeSession(agent); + session.sendMessage("start"); + }); + return notifier; +} diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 0d1d3c4..3e16087 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -640,6 +640,26 @@ __metadata: languageName: node linkType: hard +"@modelcontextprotocol/sdk@npm:^1.17.2": + version: 1.18.2 + resolution: "@modelcontextprotocol/sdk@npm:1.18.2" + dependencies: + ajv: "npm:^6.12.6" + content-type: "npm:^1.0.5" + cors: "npm:^2.8.5" + cross-spawn: "npm:^7.0.5" + eventsource: "npm:^3.0.2" + eventsource-parser: "npm:^3.0.0" + express: "npm:^5.0.1" + express-rate-limit: "npm:^7.5.0" + pkce-challenge: "npm:^5.0.0" + raw-body: "npm:^3.0.0" + zod: "npm:^3.23.8" + zod-to-json-schema: "npm:^3.24.1" + checksum: 10c0/f0cb7a97ff264cbd389753b038c7dd197f359445324a7d4eb1d8e9be2cfb1e19d6375a12098cdd71c06847e9978c976950fc17f8d4f5e7778dd99d6f9416a48e + languageName: node + linkType: hard + "@napi-rs/wasm-runtime@npm:^0.2.12": version: 0.2.12 resolution: "@napi-rs/wasm-runtime@npm:0.2.12" @@ -673,6 +693,39 @@ __metadata: languageName: node linkType: hard +"@openai/agents-core@npm:0.1.7": + version: 0.1.7 + resolution: "@openai/agents-core@npm:0.1.7" + dependencies: + "@modelcontextprotocol/sdk": "npm:^1.17.2" + debug: "npm:^4.4.0" + openai: "npm:^5.20.2" + peerDependencies: + zod: ^3.25.40 + dependenciesMeta: + "@modelcontextprotocol/sdk": + optional: true + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/9178b45d85df0b2b5de9d085f7321c590c672605ad55857338bf9a8891d982d5f78d7b015a3cea99fa2c063d01438a458f26a023082ab4c9133a836f241112b0 + languageName: node + linkType: hard + +"@openai/agents-realtime@npm:^0.1.7": + version: 0.1.7 + resolution: "@openai/agents-realtime@npm:0.1.7" + dependencies: + "@openai/agents-core": "npm:0.1.7" + "@types/ws": "npm:^8.18.1" + debug: "npm:^4.4.0" + ws: "npm:^8.18.1" + peerDependencies: + zod: ^3.25.40 + checksum: 10c0/7f91960b61ec5c31ba35c64dba3736612fd997aba14bd40d878046980599438f6572848c1c55898cf671b0b0d5653f871232698d6c01ee2ccf2a6a793ff66c02 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -1150,12 +1203,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^24.5.2": - version: 24.5.2 - resolution: "@types/node@npm:24.5.2" +"@types/node@npm:*, @types/node@npm:^24.5.2": + version: 24.6.1 + resolution: "@types/node@npm:24.6.1" dependencies: - undici-types: "npm:~7.12.0" - checksum: 10c0/96baaca6564d39c6f7f6eddd73ce41e2a7594ef37225cd52df3be36fad31712af8ae178387a72d0b80f2e2799e7fd30c014bc0ae9eb9f962d9079b691be00c48 + undici-types: "npm:~7.13.0" + checksum: 10c0/f2f8aea441d72139345cfa2e392af51bc27d12eb5f74b9b4d202046a2e82ab70d6da89c46a2ac7feea98854c2919e53070869d4af9d448e173a77249fcb7bca3 languageName: node linkType: hard @@ -1177,6 +1230,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.18.1": + version: 8.18.1 + resolution: "@types/ws@npm:8.18.1" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/61aff1129143fcc4312f083bc9e9e168aa3026b7dd6e70796276dcfb2c8211c4292603f9c4864fae702f2ed86e4abd4d38aa421831c2fd7f856c931a481afbab + languageName: node + linkType: hard + "@vitejs/plugin-react@npm:^5.0.3": version: 5.0.4 resolution: "@vitejs/plugin-react@npm:5.0.4" @@ -1207,6 +1269,16 @@ __metadata: languageName: node linkType: hard +"accepts@npm:^2.0.0": + version: 2.0.0 + resolution: "accepts@npm:2.0.0" + dependencies: + mime-types: "npm:^3.0.0" + negotiator: "npm:^1.0.0" + checksum: 10c0/98374742097e140891546076215f90c32644feacf652db48412329de4c2a529178a81aa500fbb13dd3e6cbf6e68d829037b123ac037fc9a08bcec4b87b358eef + languageName: node + linkType: hard + "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -1228,6 +1300,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^6.12.6": + version: 6.12.6 + resolution: "ajv@npm:6.12.6" + dependencies: + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 + languageName: node + linkType: hard + "ajv@npm:^8.0.0, ajv@npm:^8.12.0": version: 8.17.1 resolution: "ajv@npm:8.17.1" @@ -1333,6 +1417,7 @@ __metadata: resolution: "backend@workspace:packages/backend" dependencies: "@fishjam-cloud/js-server-sdk": "npm:^0.21.0" + "@openai/agents-realtime": "npm:^0.1.7" "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" "@types/node": "npm:^24.5.2" @@ -1351,12 +1436,29 @@ __metadata: languageName: node linkType: hard -"baseline-browser-mapping@npm:^2.8.3": - version: 2.8.9 - resolution: "baseline-browser-mapping@npm:2.8.9" +"baseline-browser-mapping@npm:^2.8.9": + version: 2.8.10 + resolution: "baseline-browser-mapping@npm:2.8.10" bin: baseline-browser-mapping: dist/cli.js - checksum: 10c0/c54356eb90cf251f351708f151fa42d0331814c03baa7bdcc802767f721fd9fe069eea88ae42395984bfddcae0c2fba2e5ee25d7921ce7cdcefc2f47440673d4 + checksum: 10c0/3ab9eee25e161a689b70b82887c8ee5cefb690a50da1d15655e2dd959de70916a43789b5ddf6968e272029002891e90a5cb46ed90ee54042e6aeae3b1c9630d4 + languageName: node + linkType: hard + +"body-parser@npm:^2.2.0": + version: 2.2.0 + resolution: "body-parser@npm:2.2.0" + dependencies: + bytes: "npm:^3.1.2" + content-type: "npm:^1.0.5" + debug: "npm:^4.4.0" + http-errors: "npm:^2.0.0" + iconv-lite: "npm:^0.6.3" + on-finished: "npm:^2.4.1" + qs: "npm:^6.14.0" + raw-body: "npm:^3.0.0" + type-is: "npm:^2.0.0" + checksum: 10c0/a9ded39e71ac9668e2211afa72e82ff86cc5ef94de1250b7d1ba9cc299e4150408aaa5f1e8b03dd4578472a3ce6d1caa2a23b27a6c18e526e48b4595174c116c languageName: node linkType: hard @@ -1370,17 +1472,24 @@ __metadata: linkType: hard "browserslist@npm:^4.24.0": - version: 4.26.2 - resolution: "browserslist@npm:4.26.2" + version: 4.26.3 + resolution: "browserslist@npm:4.26.3" dependencies: - baseline-browser-mapping: "npm:^2.8.3" - caniuse-lite: "npm:^1.0.30001741" - electron-to-chromium: "npm:^1.5.218" + baseline-browser-mapping: "npm:^2.8.9" + caniuse-lite: "npm:^1.0.30001746" + electron-to-chromium: "npm:^1.5.227" node-releases: "npm:^2.0.21" update-browserslist-db: "npm:^1.1.3" bin: browserslist: cli.js - checksum: 10c0/1146339dad33fda77786b11ea07f1c40c48899edd897d73a9114ee0dbb1ee6475bb4abda263a678c104508bdca8e66760ff8e10be1947d3e20d34bae01d8b89b + checksum: 10c0/3899ee3b7fd205ece4ffe4392697c3f2b120b68f3741ef1789212b4971771aee3f66cf37c5c3accf86ce59c0605b5980c0f132711abbcc9e62c132e6e0ee45f3 + languageName: node + linkType: hard + +"bytes@npm:3.1.2, bytes@npm:^3.1.2": + version: 3.1.2 + resolution: "bytes@npm:3.1.2" + checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e languageName: node linkType: hard @@ -1414,7 +1523,17 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001741": +"call-bound@npm:^1.0.2": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + get-intrinsic: "npm:^1.3.0" + checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001746": version: 1.0.30001746 resolution: "caniuse-lite@npm:1.0.30001746" checksum: 10c0/e656a9dc811be2316e3b6dbd3bf25d0e32dbce645b1284821b4ec93fb81dc3e3f73b9473e2f66c921b620ea8b25ebbae9ee70c3d13dad85f8dd69d6bb2c91d46 @@ -1476,6 +1595,22 @@ __metadata: languageName: node linkType: hard +"content-disposition@npm:^1.0.0": + version: 1.0.0 + resolution: "content-disposition@npm:1.0.0" + dependencies: + safe-buffer: "npm:5.2.1" + checksum: 10c0/c7b1ba0cea2829da0352ebc1b7f14787c73884bc707c8bc2271d9e3bf447b372270d09f5d3980dc5037c749ceef56b9a13fccd0b0001c87c3f12579967e4dd27 + languageName: node + linkType: hard + +"content-type@npm:^1.0.5": + version: 1.0.5 + resolution: "content-type@npm:1.0.5" + checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -1483,6 +1618,20 @@ __metadata: languageName: node linkType: hard +"cookie-signature@npm:^1.2.1": + version: 1.2.2 + resolution: "cookie-signature@npm:1.2.2" + checksum: 10c0/54e05df1a293b3ce81589b27dddc445f462f6fa6812147c033350cd3561a42bc14481674e05ed14c7bd0ce1e8bb3dc0e40851bad75415733711294ddce0b7bc6 + languageName: node + linkType: hard + +"cookie@npm:^0.7.1": + version: 0.7.2 + resolution: "cookie@npm:0.7.2" + checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2 + languageName: node + linkType: hard + "cookie@npm:^1.0.1": version: 1.0.2 resolution: "cookie@npm:1.0.2" @@ -1490,7 +1639,17 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.6": +"cors@npm:^2.8.5": + version: 2.8.5 + resolution: "cors@npm:2.8.5" + dependencies: + object-assign: "npm:^4" + vary: "npm:^1" + checksum: 10c0/373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.5, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -1515,7 +1674,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -1543,6 +1702,13 @@ __metadata: languageName: node linkType: hard +"depd@npm:2.0.0, depd@npm:^2.0.0": + version: 2.0.0 + resolution: "depd@npm:2.0.0" + checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c + languageName: node + linkType: hard + "dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" @@ -1582,10 +1748,17 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.218": - version: 1.5.227 - resolution: "electron-to-chromium@npm:1.5.227" - checksum: 10c0/6b220ea024bcdd1560ffaca6b6b4c220d789b3e9c580c37509e8c176f369c93a4de8497a6e25cbfd9619ab9d129069368e4a4317dec0335d3a0cb61c2353e6f1 +"ee-first@npm:1.1.1": + version: 1.1.1 + resolution: "ee-first@npm:1.1.1" + checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.5.227": + version: 1.5.228 + resolution: "electron-to-chromium@npm:1.5.228" + checksum: 10c0/e04272ca5bf086cdea17c6ae855047bf3164c26e38ba76da38a09d57977daf5fa7ced225173315252a98d6784af4172e6cb8d8ab5ed0fe4acf3f503dcbab159b languageName: node linkType: hard @@ -1603,6 +1776,13 @@ __metadata: languageName: node linkType: hard +"encodeurl@npm:^2.0.0": + version: 2.0.0 + resolution: "encodeurl@npm:2.0.0" + checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb + languageName: node + linkType: hard + "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -1776,6 +1956,36 @@ __metadata: languageName: node linkType: hard +"escape-html@npm:^1.0.3": + version: 1.0.3 + resolution: "escape-html@npm:1.0.3" + checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 + languageName: node + linkType: hard + +"etag@npm:^1.8.1": + version: 1.8.1 + resolution: "etag@npm:1.8.1" + checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 + languageName: node + linkType: hard + +"eventsource-parser@npm:^3.0.0, eventsource-parser@npm:^3.0.1": + version: 3.0.6 + resolution: "eventsource-parser@npm:3.0.6" + checksum: 10c0/70b8ccec7dac767ef2eca43f355e0979e70415701691382a042a2df8d6a68da6c2fca35363669821f3da876d29c02abe9b232964637c1b6635c940df05ada78a + languageName: node + linkType: hard + +"eventsource@npm:^3.0.2": + version: 3.0.7 + resolution: "eventsource@npm:3.0.7" + dependencies: + eventsource-parser: "npm:^3.0.1" + checksum: 10c0/c48a73c38f300e33e9f11375d4ee969f25cbb0519608a12378a38068055ae8b55b6e0e8a49c3f91c784068434efe1d9f01eb49b6315b04b0da9157879ce2f67d + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -1783,6 +1993,50 @@ __metadata: languageName: node linkType: hard +"express-rate-limit@npm:^7.5.0": + version: 7.5.1 + resolution: "express-rate-limit@npm:7.5.1" + peerDependencies: + express: ">= 4.11" + checksum: 10c0/b07de84d700a2c07c4bf2f040e7558ed5a1f660f03ed5f30bf8ff7b51e98ba7a85215640e70fc48cbbb9151066ea51239d9a1b41febc9b84d98c7915b0186161 + languageName: node + linkType: hard + +"express@npm:^5.0.1": + version: 5.1.0 + resolution: "express@npm:5.1.0" + dependencies: + accepts: "npm:^2.0.0" + body-parser: "npm:^2.2.0" + content-disposition: "npm:^1.0.0" + content-type: "npm:^1.0.5" + cookie: "npm:^0.7.1" + cookie-signature: "npm:^1.2.1" + debug: "npm:^4.4.0" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + etag: "npm:^1.8.1" + finalhandler: "npm:^2.1.0" + fresh: "npm:^2.0.0" + http-errors: "npm:^2.0.0" + merge-descriptors: "npm:^2.0.0" + mime-types: "npm:^3.0.0" + on-finished: "npm:^2.4.1" + once: "npm:^1.4.0" + parseurl: "npm:^1.3.3" + proxy-addr: "npm:^2.0.7" + qs: "npm:^6.14.0" + range-parser: "npm:^1.2.1" + router: "npm:^2.2.0" + send: "npm:^1.1.0" + serve-static: "npm:^2.2.0" + statuses: "npm:^2.0.1" + type-is: "npm:^2.0.1" + vary: "npm:^1.1.2" + checksum: 10c0/80ce7c53c5f56887d759b94c3f2283e2e51066c98d4b72a4cc1338e832b77f1e54f30d0239cc10815a0f849bdb753e6a284d2fa48d4ab56faf9c501f55d751d6 + languageName: node + linkType: hard + "fast-copy@npm:^3.0.2": version: 3.0.2 resolution: "fast-copy@npm:3.0.2" @@ -1797,13 +2051,20 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.3": +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b + languageName: node + linkType: hard + "fast-json-stringify@npm:^6.0.0": version: 6.1.1 resolution: "fast-json-stringify@npm:6.1.1" @@ -1885,6 +2146,20 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:^2.1.0": + version: 2.1.0 + resolution: "finalhandler@npm:2.1.0" + dependencies: + debug: "npm:^4.4.0" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + on-finished: "npm:^2.4.1" + parseurl: "npm:^1.3.3" + statuses: "npm:^2.0.1" + checksum: 10c0/da0bbca6d03873472ee890564eb2183f4ed377f25f3628a0fc9d16dac40bed7b150a0d82ebb77356e4c6d97d2796ad2dba22948b951dddee2c8768b0d1b9fb1f + languageName: node + linkType: hard + "find-my-way@npm:^9.0.0": version: 9.3.0 resolution: "find-my-way@npm:9.3.0" @@ -1929,6 +2204,20 @@ __metadata: languageName: node linkType: hard +"forwarded@npm:0.2.0": + version: 0.2.0 + resolution: "forwarded@npm:0.2.0" + checksum: 10c0/9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 + languageName: node + linkType: hard + +"fresh@npm:^2.0.0": + version: 2.0.0 + resolution: "fresh@npm:2.0.0" + checksum: 10c0/0557548194cb9a809a435bf92bcfbc20c89e8b5eb38861b73ced36750437251e39a111fc3a18b98531be9dd91fe1411e4969f229dc579ec0251ce6c5d4900bbc + languageName: node + linkType: hard + "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -1965,9 +2254,9 @@ __metadata: linkType: hard "generator-function@npm:^2.0.0": - version: 2.0.0 - resolution: "generator-function@npm:2.0.0" - checksum: 10c0/27574ccb34deb4ff89155c4b417601522f770cc823c2806ffadc3c1d679b2c862dc22374ac22cfe0198034f6aca95dd8ee8d7d6a35d038a5e2db2dd8bf4e0b80 + version: 2.0.1 + resolution: "generator-function@npm:2.0.1" + checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 languageName: node linkType: hard @@ -1978,7 +2267,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.6": +"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0": version: 1.3.1 resolution: "get-intrinsic@npm:1.3.1" dependencies: @@ -2094,6 +2383,19 @@ __metadata: languageName: node linkType: hard +"http-errors@npm:2.0.0, http-errors@npm:^2.0.0": + version: 2.0.0 + resolution: "http-errors@npm:2.0.0" + dependencies: + depd: "npm:2.0.0" + inherits: "npm:2.0.4" + setprototypeof: "npm:1.2.0" + statuses: "npm:2.0.1" + toidentifier: "npm:1.0.1" + checksum: 10c0/fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19 + languageName: node + linkType: hard + "http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" @@ -2114,7 +2416,16 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:^0.6.2": +"iconv-lite@npm:0.7.0": + version: 0.7.0 + resolution: "iconv-lite@npm:0.7.0" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/2382400469071c55b6746c531eed5fa4d033e5db6690b7331fb2a5f59a30d7a9782932e92253db26df33c1cf46fa200a3fbe524a2a7c62037c762283f188ec2f + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -2130,6 +2441,13 @@ __metadata: languageName: node linkType: hard +"inherits@npm:2.0.4": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + languageName: node + linkType: hard + "ip-address@npm:^10.0.1": version: 10.0.1 resolution: "ip-address@npm:10.0.1" @@ -2137,6 +2455,13 @@ __metadata: languageName: node linkType: hard +"ipaddr.js@npm:1.9.1": + version: 1.9.1 + resolution: "ipaddr.js@npm:1.9.1" + checksum: 10c0/0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a + languageName: node + linkType: hard + "ipaddr.js@npm:^2.1.0": version: 2.2.0 resolution: "ipaddr.js@npm:2.2.0" @@ -2151,6 +2476,13 @@ __metadata: languageName: node linkType: hard +"is-promise@npm:^4.0.0": + version: 4.0.0 + resolution: "is-promise@npm:4.0.0" + checksum: 10c0/ebd5c672d73db781ab33ccb155fb9969d6028e37414d609b115cc534654c91ccd061821d5b987eefaa97cf4c62f0b909bb2f04db88306de26e91bfe8ddc01503 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -2219,6 +2551,13 @@ __metadata: languageName: node linkType: hard +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce + languageName: node + linkType: hard + "json-schema-traverse@npm:^1.0.0": version: 1.0.0 resolution: "json-schema-traverse@npm:1.0.0" @@ -2416,6 +2755,20 @@ __metadata: languageName: node linkType: hard +"media-typer@npm:^1.1.0": + version: 1.1.0 + resolution: "media-typer@npm:1.1.0" + checksum: 10c0/7b4baa40b25964bb90e2121ee489ec38642127e48d0cc2b6baa442688d3fde6262bfdca86d6bbf6ba708784afcac168c06840c71facac70e390f5f759ac121b9 + languageName: node + linkType: hard + +"merge-descriptors@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-descriptors@npm:2.0.0" + checksum: 10c0/95389b7ced3f9b36fbdcf32eb946dc3dd1774c2fdf164609e55b18d03aa499b12bd3aae3a76c1c7185b96279e9803525550d3eb292b5224866060a288f335cb3 + languageName: node + linkType: hard + "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -2423,6 +2776,13 @@ __metadata: languageName: node linkType: hard +"mime-db@npm:^1.54.0": + version: 1.54.0 + resolution: "mime-db@npm:1.54.0" + checksum: 10c0/8d907917bc2a90fa2df842cdf5dfeaf509adc15fe0531e07bb2f6ab15992416479015828d6a74200041c492e42cce3ebf78e5ce714388a0a538ea9c53eece284 + languageName: node + linkType: hard + "mime-types@npm:^2.1.12": version: 2.1.35 resolution: "mime-types@npm:2.1.35" @@ -2432,6 +2792,15 @@ __metadata: languageName: node linkType: hard +"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1": + version: 3.0.1 + resolution: "mime-types@npm:3.0.1" + dependencies: + mime-db: "npm:^1.54.0" + checksum: 10c0/bd8c20d3694548089cf229016124f8f40e6a60bbb600161ae13e45f793a2d5bb40f96bbc61f275836696179c77c1d6bf4967b2a75e0a8ad40fe31f4ed5be4da5 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -2585,6 +2954,20 @@ __metadata: languageName: node linkType: hard +"object-assign@npm:^4": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 + languageName: node + linkType: hard + +"object-inspect@npm:^1.13.3": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 + languageName: node + linkType: hard + "on-exit-leak-free@npm:^2.1.0": version: 2.1.2 resolution: "on-exit-leak-free@npm:2.1.2" @@ -2592,6 +2975,15 @@ __metadata: languageName: node linkType: hard +"on-finished@npm:^2.4.1": + version: 2.4.1 + resolution: "on-finished@npm:2.4.1" + dependencies: + ee-first: "npm:1.1.1" + checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 + languageName: node + linkType: hard + "once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -2601,6 +2993,23 @@ __metadata: languageName: node linkType: hard +"openai@npm:^5.20.2": + version: 5.23.2 + resolution: "openai@npm:5.23.2" + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + bin: + openai: bin/cli + checksum: 10c0/8ee37f37c64fd04a61622c4782d231e8f0245e2d85956d833e43d30946edbf07d5276cd74e09aa5d23006de8da43dad312246a9dd7ca6ca6d65d983fc976ffa6 + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -2615,6 +3024,13 @@ __metadata: languageName: node linkType: hard +"parseurl@npm:^1.3.3": + version: 1.3.3 + resolution: "parseurl@npm:1.3.3" + checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 + languageName: node + linkType: hard + "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -2632,6 +3048,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:^8.0.0": + version: 8.3.0 + resolution: "path-to-regexp@npm:8.3.0" + checksum: 10c0/ee1544a73a3f294a97a4c663b0ce71bbf1621d732d80c9c9ed201b3e911a86cb628ebad691b9d40f40a3742fe22011e5a059d8eed2cf63ec2cb94f6fb4efe67c + languageName: node + linkType: hard + "picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -2706,6 +3129,13 @@ __metadata: languageName: node linkType: hard +"pkce-challenge@npm:^5.0.0": + version: 5.0.0 + resolution: "pkce-challenge@npm:5.0.0" + checksum: 10c0/c6706d627fdbb6f22bf8cc5d60d96d6b6a7bb481399b336a3d3f4e9bfba3e167a2c32f8ec0b5e74be686a0ba3bcc9894865d4c2dd1b91cea4c05dba1f28602c3 + languageName: node + linkType: hard + "postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -2748,6 +3178,16 @@ __metadata: languageName: node linkType: hard +"proxy-addr@npm:^2.0.7": + version: 2.0.7 + resolution: "proxy-addr@npm:2.0.7" + dependencies: + forwarded: "npm:0.2.0" + ipaddr.js: "npm:1.9.1" + checksum: 10c0/c3eed999781a35f7fd935f398b6d8920b6fb00bbc14287bc6de78128ccc1a02c89b95b56742bf7cf0362cc333c61d138532049c7dedc7a328ef13343eff81210 + languageName: node + linkType: hard + "proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" @@ -2765,6 +3205,22 @@ __metadata: languageName: node linkType: hard +"punycode@npm:^2.1.0": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 + languageName: node + linkType: hard + +"qs@npm:^6.14.0": + version: 6.14.0 + resolution: "qs@npm:6.14.0" + dependencies: + side-channel: "npm:^1.1.0" + checksum: 10c0/8ea5d91bf34f440598ee389d4a7d95820e3b837d3fd9f433871f7924801becaa0cd3b3b4628d49a7784d06a8aea9bc4554d2b6d8d584e2d221dc06238a42909c + languageName: node + linkType: hard + "quick-format-unescaped@npm:^4.0.3": version: 4.0.4 resolution: "quick-format-unescaped@npm:4.0.4" @@ -2772,6 +3228,25 @@ __metadata: languageName: node linkType: hard +"range-parser@npm:^1.2.1": + version: 1.2.1 + resolution: "range-parser@npm:1.2.1" + checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 + languageName: node + linkType: hard + +"raw-body@npm:^3.0.0": + version: 3.0.1 + resolution: "raw-body@npm:3.0.1" + dependencies: + bytes: "npm:3.1.2" + http-errors: "npm:2.0.0" + iconv-lite: "npm:0.7.0" + unpipe: "npm:1.0.0" + checksum: 10c0/892f4fbd21ecab7e2fed0f045f7af9e16df7e8050879639d4e482784a2f4640aaaa33d916a0e98013f23acb82e09c2e3c57f84ab97104449f728d22f65a7d79a + languageName: node + linkType: hard + "react-dom@npm:^19.1.1": version: 19.1.1 resolution: "react-dom@npm:19.1.1" @@ -2927,6 +3402,26 @@ __metadata: languageName: node linkType: hard +"router@npm:^2.2.0": + version: 2.2.0 + resolution: "router@npm:2.2.0" + dependencies: + debug: "npm:^4.4.0" + depd: "npm:^2.0.0" + is-promise: "npm:^4.0.0" + parseurl: "npm:^1.3.3" + path-to-regexp: "npm:^8.0.0" + checksum: 10c0/3279de7450c8eae2f6e095e9edacbdeec0abb5cb7249c6e719faa0db2dba43574b4fff5892d9220631c9abaff52dd3cad648cfea2aaace845e1a071915ac8867 + languageName: node + linkType: hard + +"safe-buffer@npm:5.2.1": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -2982,6 +3477,37 @@ __metadata: languageName: node linkType: hard +"send@npm:^1.1.0, send@npm:^1.2.0": + version: 1.2.0 + resolution: "send@npm:1.2.0" + dependencies: + debug: "npm:^4.3.5" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + etag: "npm:^1.8.1" + fresh: "npm:^2.0.0" + http-errors: "npm:^2.0.0" + mime-types: "npm:^3.0.1" + ms: "npm:^2.1.3" + on-finished: "npm:^2.4.1" + range-parser: "npm:^1.2.1" + statuses: "npm:^2.0.1" + checksum: 10c0/531bcfb5616948d3468d95a1fd0adaeb0c20818ba4a500f439b800ca2117971489e02074ce32796fd64a6772ea3e7235fe0583d8241dbd37a053dc3378eff9a5 + languageName: node + linkType: hard + +"serve-static@npm:^2.2.0": + version: 2.2.0 + resolution: "serve-static@npm:2.2.0" + dependencies: + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + parseurl: "npm:^1.3.3" + send: "npm:^1.2.0" + checksum: 10c0/30e2ed1dbff1984836cfd0c65abf5d3f3f83bcd696c99d2d3c97edbd4e2a3ff4d3f87108a7d713640d290a7b6fe6c15ddcbc61165ab2eaad48ea8d3b52c7f913 + languageName: node + linkType: hard + "set-cookie-parser@npm:^2.6.0": version: 2.7.1 resolution: "set-cookie-parser@npm:2.7.1" @@ -2989,6 +3515,13 @@ __metadata: languageName: node linkType: hard +"setprototypeof@npm:1.2.0": + version: 1.2.0 + resolution: "setprototypeof@npm:1.2.0" + checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -3005,6 +3538,54 @@ __metadata: languageName: node linkType: hard +"side-channel-list@npm:^1.0.0": + version: 1.0.0 + resolution: "side-channel-list@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 + languageName: node + linkType: hard + +"side-channel@npm:^1.1.0": + version: 1.1.0 + resolution: "side-channel@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + side-channel-list: "npm:^1.0.0" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 + languageName: node + linkType: hard + "signal-exit@npm:^4.0.1": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -3079,6 +3660,20 @@ __metadata: languageName: node linkType: hard +"statuses@npm:2.0.1": + version: 2.0.1 + resolution: "statuses@npm:2.0.1" + checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 + languageName: node + linkType: hard + +"statuses@npm:^2.0.1": + version: 2.0.2 + resolution: "statuses@npm:2.0.2" + checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f + languageName: node + linkType: hard + "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -3186,6 +3781,13 @@ __metadata: languageName: node linkType: hard +"toidentifier@npm:1.0.1": + version: 1.0.1 + resolution: "toidentifier@npm:1.0.1" + checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 + languageName: node + linkType: hard + "tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" @@ -3216,30 +3818,41 @@ __metadata: languageName: node linkType: hard +"type-is@npm:^2.0.0, type-is@npm:^2.0.1": + version: 2.0.1 + resolution: "type-is@npm:2.0.1" + dependencies: + content-type: "npm:^1.0.5" + media-typer: "npm:^1.1.0" + mime-types: "npm:^3.0.0" + checksum: 10c0/7f7ec0a060b16880bdad36824ab37c26019454b67d73e8a465ed5a3587440fbe158bc765f0da68344498235c877e7dbbb1600beccc94628ed05599d667951b99 + languageName: node + linkType: hard + "typescript@npm:^5.9.2": - version: 5.9.2 - resolution: "typescript@npm:5.9.2" + version: 5.9.3 + resolution: "typescript@npm:5.9.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 + checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 languageName: node linkType: hard "typescript@patch:typescript@npm%3A^5.9.2#optional!builtin": - version: 5.9.2 - resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e + checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 languageName: node linkType: hard -"undici-types@npm:~7.12.0": - version: 7.12.0 - resolution: "undici-types@npm:7.12.0" - checksum: 10c0/326e455bbc0026db1d6b81c76a1cf10c63f7e2f9821db2e24fdc258f482814e5bfa8481f8910d07c68e305937c5c049610fdc441c5e8b7bb0daca7154fb8a306 +"undici-types@npm:~7.13.0": + version: 7.13.0 + resolution: "undici-types@npm:7.13.0" + checksum: 10c0/44bbb0935425291351bfd8039571f017295b5d6dc5727045d0a4fea8c6ffe73a6703b48ce010f9cb539b9041a75b463f8cfe1e7309cab7486452505fb0d66151 languageName: node linkType: hard @@ -3261,6 +3874,13 @@ __metadata: languageName: node linkType: hard +"unpipe@npm:1.0.0": + version: 1.0.0 + resolution: "unpipe@npm:1.0.0" + checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.1.3": version: 1.1.3 resolution: "update-browserslist-db@npm:1.1.3" @@ -3275,6 +3895,15 @@ __metadata: languageName: node linkType: hard +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + languageName: node + linkType: hard + "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -3284,6 +3913,13 @@ __metadata: languageName: node linkType: hard +"vary@npm:^1, vary@npm:^1.1.2": + version: 1.1.2 + resolution: "vary@npm:1.1.2" + checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f + languageName: node + linkType: hard + "vite@npm:^7.1.7": version: 7.1.7 resolution: "vite@npm:7.1.7" @@ -3418,6 +4054,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.18.1": + version: 8.18.3 + resolution: "ws@npm:8.18.3" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/eac918213de265ef7cb3d4ca348b891a51a520d839aa51cdb8ca93d4fa7ff9f6ccb339ccee89e4075324097f0a55157c89fa3f7147bde9d8d7e90335dc087b53 + languageName: node + linkType: hard + "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" @@ -3439,6 +4090,22 @@ __metadata: languageName: node linkType: hard +"zod-to-json-schema@npm:^3.24.1": + version: 3.24.6 + resolution: "zod-to-json-schema@npm:3.24.6" + peerDependencies: + zod: ^3.24.1 + checksum: 10c0/b907ab6d057100bd25a37e5545bf5f0efa5902cd84d3c3ec05c2e51541431a47bd9bf1e5e151a244273409b45f5986d55b26e5d207f98abc5200702f733eb368 + languageName: node + linkType: hard + +"zod@npm:^3.23.8": + version: 3.25.76 + resolution: "zod@npm:3.25.76" + checksum: 10c0/5718ec35e3c40b600316c5b4c5e4976f7fee68151bc8f8d90ec18a469be9571f072e1bbaace10f1e85cf8892ea12d90821b200e980ab46916a6166a4260a983c + languageName: node + linkType: hard + "zod@npm:^4.1.11": version: 4.1.11 resolution: "zod@npm:4.1.11" From 4ba6a28ad7141ec4d37439b2a5afc361cc0b56cb Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 3 Oct 2025 11:07:06 +0200 Subject: [PATCH 22/65] format --- .../packages/backend/src/config.ts | 13 +++++---- .../packages/backend/src/controllers/peers.ts | 24 +++++++-------- .../packages/backend/src/router.ts | 6 ++-- .../packages/backend/src/schemas.ts | 1 - .../packages/backend/src/service/agent.ts | 12 ++++---- .../packages/backend/src/service/notifier.ts | 29 ++++++++++++------- 6 files changed, 47 insertions(+), 38 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index 56f2110..03782b4 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -5,12 +5,15 @@ import * as fs from 'fs'; dotenv.config(); export const configSchema = z.object({ - PORT: z.coerce.number().int().default(8000), - FISHJAM_ID: z.string(), - FISHJAM_URL: z.string().optional(), - FISHJAM_MANAGEMENT_TOKEN: z.string(), + PORT: z.coerce.number().int().default(8000), + FISHJAM_ID: z.string(), + FISHJAM_URL: z.string().optional(), + FISHJAM_MANAGEMENT_TOKEN: z.string(), }); export const CONFIG = configSchema.parse(process.env); -export const AGENT_INSTRUCTIONS = fs.readFileSync('./prompts/instructions.md', 'utf8'); +export const AGENT_INSTRUCTIONS = fs.readFileSync( + './prompts/instructions.md', + 'utf8', +); diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index ce5174f..460a44e 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -3,19 +3,19 @@ import { z } from 'zod'; import { publicProcedure } from '../trpc.js'; const createPeerInputSchema = z.object({ - roomId: z.string(), - displayName: z.string().optional(), + roomId: z.string(), + displayName: z.string().optional(), }); export const createPeer = publicProcedure - .input(createPeerInputSchema) - .mutation(async ({ ctx, input }) => { - const peer = await ctx.fishjam.createPeer(input.roomId as RoomId, { - enableSimulcast: true, - }); + .input(createPeerInputSchema) + .mutation(async ({ ctx, input }) => { + const peer = await ctx.fishjam.createPeer(input.roomId as RoomId, { + enableSimulcast: true, + }); - return { - peer: peer.peer, - token: peer.peerToken, - }; - }); + return { + peer: peer.peer, + token: peer.peerToken, + }; + }); diff --git a/deep-sea-stories/packages/backend/src/router.ts b/deep-sea-stories/packages/backend/src/router.ts index 924ec02..351c404 100644 --- a/deep-sea-stories/packages/backend/src/router.ts +++ b/deep-sea-stories/packages/backend/src/router.ts @@ -3,9 +3,9 @@ import { createPeer } from './controllers/peers.js'; import { router } from './trpc.js'; export const appRouter = router({ - createRoom, - getRoom, - createPeer, + createRoom, + getRoom, + createPeer, }); export type AppRouter = typeof appRouter; diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts index 4431159..a4f162c 100644 --- a/deep-sea-stories/packages/backend/src/schemas.ts +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -1,4 +1,3 @@ import z from 'zod'; export const getRoomInputSchema = z.object({ roomId: z.string() }); - diff --git a/deep-sea-stories/packages/backend/src/service/agent.ts b/deep-sea-stories/packages/backend/src/service/agent.ts index 6f82132..dae7cef 100644 --- a/deep-sea-stories/packages/backend/src/service/agent.ts +++ b/deep-sea-stories/packages/backend/src/service/agent.ts @@ -1,9 +1,9 @@ -import { RealtimeAgent } from "@openai/agents-realtime"; -import { AGENT_INSTRUCTIONS } from "../config.js"; +import { RealtimeAgent } from '@openai/agents-realtime'; +import { AGENT_INSTRUCTIONS } from '../config.js'; export function getRealtimeAgent(): RealtimeAgent { - return new RealtimeAgent({ - name: 'Riddle Master', - instructions: AGENT_INSTRUCTIONS - }) + return new RealtimeAgent({ + name: 'Riddle Master', + instructions: AGENT_INSTRUCTIONS, + }); } diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index a051b0b..be5c1d8 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -1,14 +1,21 @@ -import { FishjamWSNotifier, FishjamConfig } from "@fishjam-cloud/js-server-sdk"; -import { RealtimeSession } from "@openai/agents-realtime"; -import { getRealtimeAgent } from "./agent.js"; +import { FishjamWSNotifier, FishjamConfig } from '@fishjam-cloud/js-server-sdk'; +import { RealtimeSession } from '@openai/agents-realtime'; +import { getRealtimeAgent } from './agent.js'; -export async function getNotifier(session: RealtimeSession, config: FishjamConfig): Promise { - const notifier = new FishjamWSNotifier(config, () => { }, () => { }); +export async function getNotifier( + session: RealtimeSession, + config: FishjamConfig, +): Promise { + const notifier = new FishjamWSNotifier( + config, + () => {}, + () => {}, + ); - notifier.on('peerConnected', () => { - const agent = getRealtimeAgent(); - const session = new RealtimeSession(agent); - session.sendMessage("start"); - }); - return notifier; + notifier.on('peerConnected', () => { + const agent = getRealtimeAgent(); + const session = new RealtimeSession(agent); + session.sendMessage('start'); + }); + return notifier; } From 9db2a6b83ab7ab500219fe855e5e71200a8c4acc Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 3 Oct 2025 18:12:50 +0200 Subject: [PATCH 23/65] /Agent integration left --- .../packages/backend/package.json | 7 +- .../packages/backend/src/config.ts | 22 ++++- .../packages/backend/src/context.ts | 1 - .../packages/backend/src/controllers/peers.ts | 26 ++--- .../packages/backend/src/controllers/rooms.ts | 5 +- .../packages/backend/src/prompts/greet.md | 0 ...structions.md => instructions-template.md} | 7 +- .../packages/backend/src/prompts/stories.json | 42 ++++++++ .../packages/backend/src/schemas.ts | 2 + .../packages/backend/src/service/agent.ts | 9 -- .../packages/backend/src/service/notifier.ts | 62 ++++++++---- .../packages/backend/src/service/room.ts | 64 ++++++++++++ .../packages/backend/src/service/session.ts | 56 +++++++++++ .../packages/backend/src/types.ts | 4 + .../packages/backend/src/utils.ts | 13 +++ .../packages/backend/tests/.env.test | 5 + .../packages/backend/tests/config.test.ts | 98 +++++++++++++++++++ .../packages/backend/tests/index.test.ts | 6 ++ .../packages/backend/tests/setup.ts | 12 +++ .../packages/backend/tests/utils.test.ts | 55 +++++++++++ deep-sea-stories/yarn.lock | 28 +++++- 21 files changed, 468 insertions(+), 56 deletions(-) delete mode 100644 deep-sea-stories/packages/backend/src/prompts/greet.md rename deep-sea-stories/packages/backend/src/prompts/{instructions.md => instructions-template.md} (78%) create mode 100644 deep-sea-stories/packages/backend/src/prompts/stories.json delete mode 100644 deep-sea-stories/packages/backend/src/service/agent.ts create mode 100644 deep-sea-stories/packages/backend/src/service/room.ts create mode 100644 deep-sea-stories/packages/backend/src/service/session.ts create mode 100644 deep-sea-stories/packages/backend/src/types.ts create mode 100644 deep-sea-stories/packages/backend/src/utils.ts create mode 100644 deep-sea-stories/packages/backend/tests/.env.test create mode 100644 deep-sea-stories/packages/backend/tests/config.test.ts create mode 100644 deep-sea-stories/packages/backend/tests/index.test.ts create mode 100644 deep-sea-stories/packages/backend/tests/setup.ts create mode 100644 deep-sea-stories/packages/backend/tests/utils.test.ts diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 98263a6..acd7960 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -4,11 +4,12 @@ "main": "./src/main.ts", "type": "module", "dependencies": { - "@fishjam-cloud/js-server-sdk": "^0.21.0", + "@fishjam-cloud/js-server-sdk": "^0.22.0", "@openai/agents-realtime": "^0.1.7", "@trpc/server": "^11.6.0", "dotenv": "^17.2.3", "fastify": "^5.6.1", + "openai": "^6.1.0", "pino-pretty": "^13.1.1", "zod": "^4.1.11" }, @@ -20,6 +21,8 @@ "scripts": { "build": "tsc -p tsconfig.json", "start": "tsx watch src/main.ts", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test": "node --test --import tsx/esm tests/index.test.ts", + "test:watch": "node --test --watch --import tsx/esm tests/index.test.ts" } } diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index 03782b4..c8be7c7 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -1,19 +1,35 @@ import dotenv from 'dotenv'; import z from 'zod'; import * as fs from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; +import type { Story } from './types.js'; +import type { PeerOptions } from '@fishjam-cloud/js-server-sdk'; dotenv.config(); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + export const configSchema = z.object({ PORT: z.coerce.number().int().default(8000), FISHJAM_ID: z.string(), - FISHJAM_URL: z.string().optional(), FISHJAM_MANAGEMENT_TOKEN: z.string(), }); +export const stories: Story[] = JSON.parse( + fs.readFileSync(join(__dirname, 'prompts', 'stories.json'), 'utf8'), +); + export const CONFIG = configSchema.parse(process.env); -export const AGENT_INSTRUCTIONS = fs.readFileSync( - './prompts/instructions.md', +export const AGENT_INSTRUCTIONS_TEMPLATE = fs.readFileSync( + join(__dirname, 'prompts', 'instructions-template.md'), 'utf8', ); + +export const FISHJAM_AGENT_OPTIONS: PeerOptions = { + output: { + audioSampleRate: 24_000, + }, +}; diff --git a/deep-sea-stories/packages/backend/src/context.ts b/deep-sea-stories/packages/backend/src/context.ts index eafc6a5..7decc11 100644 --- a/deep-sea-stories/packages/backend/src/context.ts +++ b/deep-sea-stories/packages/backend/src/context.ts @@ -4,7 +4,6 @@ import { CONFIG } from './config.js'; const fishjam = new FishjamClient({ fishjamId: CONFIG.FISHJAM_ID, - fishjamUrl: CONFIG.FISHJAM_URL, managementToken: CONFIG.FISHJAM_MANAGEMENT_TOKEN, }); diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index 460a44e..1292faa 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -1,21 +1,23 @@ -import type { RoomId } from '@fishjam-cloud/js-server-sdk'; -import { z } from 'zod'; +import { RoomId, Peer, FishjamAgent } from '@fishjam-cloud/js-server-sdk'; +import { createPeerInputSchema } from '../schemas.js'; import { publicProcedure } from '../trpc.js'; - -const createPeerInputSchema = z.object({ - roomId: z.string(), - displayName: z.string().optional(), -}); +import { roomService } from '../service/room.js'; export const createPeer = publicProcedure .input(createPeerInputSchema) .mutation(async ({ ctx, input }) => { - const peer = await ctx.fishjam.createPeer(input.roomId as RoomId, { - enableSimulcast: true, - }); + const room = await ctx.fishjam.getRoom(input.roomId as RoomId); + // TODO: if doesn't exist create + if (room.peers.length == 0) { + await roomService.createFishjamAgent(room.id, ctx.fishjam); + } + const { peer, peerToken } = await roomService.createPeer( + room.id, + ctx.fishjam, + ); return { - peer: peer.peer, - token: peer.peerToken, + peer: peer, + token: peerToken, }; }); diff --git a/deep-sea-stories/packages/backend/src/controllers/rooms.ts b/deep-sea-stories/packages/backend/src/controllers/rooms.ts index 0cc1a1f..b29a49f 100644 --- a/deep-sea-stories/packages/backend/src/controllers/rooms.ts +++ b/deep-sea-stories/packages/backend/src/controllers/rooms.ts @@ -1,9 +1,12 @@ import type { RoomId } from '@fishjam-cloud/js-server-sdk'; import { getRoomInputSchema } from '../schemas.js'; import { publicProcedure } from '../trpc.js'; +import { roomService } from '../service/room.js'; export const createRoom = publicProcedure.mutation(async ({ ctx }) => { - return await ctx.fishjam.createRoom(); + const room = await ctx.fishjam.createRoom(); + roomService.createStory(room.id); + return room; }); export const getRoom = publicProcedure diff --git a/deep-sea-stories/packages/backend/src/prompts/greet.md b/deep-sea-stories/packages/backend/src/prompts/greet.md deleted file mode 100644 index e69de29..0000000 diff --git a/deep-sea-stories/packages/backend/src/prompts/instructions.md b/deep-sea-stories/packages/backend/src/prompts/instructions-template.md similarity index 78% rename from deep-sea-stories/packages/backend/src/prompts/instructions.md rename to deep-sea-stories/packages/backend/src/prompts/instructions-template.md index 555083b..9fcf390 100644 --- a/deep-sea-stories/packages/backend/src/prompts/instructions.md +++ b/deep-sea-stories/packages/backend/src/prompts/instructions-template.md @@ -40,9 +40,6 @@ My role Your card content is: ### Front of the Card - -A man was found dead in the middle of a field. There were no footprints around him and he had nothing in his hands. The only thing on him was a small parachute harness without a parachute attached. - +{{FRONT}} ### Back of the Card - -The man was a skydiver. He had gone on a jump with a group of skydivers and had accidentally grabbed a faulty parachute. Mid-air, when he realized it was not functional, he attempted to fix it but couldn't. As he descended, the wind blew him away from the group, causing him to land in the open field, without any footprints nearby due to being airborne before the landing. +{{BACK}} \ No newline at end of file diff --git a/deep-sea-stories/packages/backend/src/prompts/stories.json b/deep-sea-stories/packages/backend/src/prompts/stories.json new file mode 100644 index 0000000..66b62d2 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/prompts/stories.json @@ -0,0 +1,42 @@ +[ + { + "front": "A man was found dead in the middle of a field. There were no footprints around him and he had nothing in his hands. The only thing on him was a small parachute harness without a parachute attached.", + "back": "The man was a skydiver. He had gone on a jump with a group of skydivers and had accidentally grabbed a faulty parachute. Mid-air, when he realized it was not functional, he attempted to fix it but couldn't. As he descended, the wind blew him away from the group, causing him to land in the open field, without any footprints nearby due to being airborne before the landing." + }, + { + "front": "A man is found dead in his locked apartment. The door is bolted from the inside, all the windows are closed, and there are no signs of forced entry. Next to him lies a puddle of water and some shattered glass.", + "back": "The man had kept a large ice block propped against the door as an improvised barricade, fearing someone was after him. When he sat down to rest, the ice eventually melted, leaving only the puddle of water. The door closed and locked itself, and no one had to enter. He later died of unrelated causes (a heart attack)." + }, + { + "front": "Two men are found dead in a cabin on a mountain. The windows are shattered, but there are no footprints leading away from the cabin.", + "back": "The men had been flying in a small airplane that crashed into the mountainside. What the rescuers thought was a 'cabin' was actually the remains of the airplane fuselage. They died on impact, and the shattered 'windows' were airplane windows, not a house." + }, + { + "front": "A man dies of thirst in the middle of a bar full of people. Nobody helped him.", + "back": "The bar was not a drinking establishment, but a sandbar in the desert. He was stranded, saw no one around, and perished from dehydration. The wording misleads the guessers into thinking of an alcohol-serving bar." + }, + { + "front": "A body is found in a library, with dozens of books scattered around. Cause of death: blunt force trauma. There are no weapons nearby.", + "back": "The man died when a heavy bookshelf collapsed on him while he was trying to reach a book from the top. The books scattered everywhere during the fall, concealing the true cause of his death until closer inspection." + }, + { + "front": "A man is found hanged in a room with a ceiling 4 meters high. There is no chair, no furniture, and the floor is bare.", + "back": "The man stood on a large block of ice to hang himself. Over time, the ice melted completely, leaving no trace and creating the illusion of an impossible hanging." + }, + { + "front": "A sailor is found dead on the deck of his ship. His pockets are full of sand, and there are no signs of injury.", + "back": "The sailor had been rescued after a shipwreck. During the accident, he swallowed a large amount of seawater containing sand and silt. Though he survived the wreck, he later collapsed and died from internal damage caused by inhaling sand-filled water into his lungs." + }, + { + "front": "A man lies dead in a phone booth. The glass is shattered, and he is clutching torn pages from a phone book.", + "back": "The man was a fisherman who had boasted about the size of a fish he caught. His friends didn’t believe him, so he rushed to the phone booth to call and confirm it with someone. He angrily tore pages looking for the number but accidentally broke the glass and cut himself fatally in his frustration." + }, + { + "front": "A woman is found dead in front of her television. The TV is on, but the screen shows only static. She has a smile on her face.", + "back": "The woman had been terminally ill and bedridden. She watched a TV show religiously every week, and on the night of her death, the show aired its final episode. She smiled, having seen the ending she long awaited, and then peacefully passed away. The static was just the end of transmission." + }, + { + "front": "A man is found shot to death in a car. All the doors are locked from the inside, and there is no gun in the vehicle.", + "back": "The man was killed in a drive-by shooting. After he was shot, his car rolled forward and hit an obstacle, automatically locking the central locking system on impact. The attacker left with the weapon, leaving behind a locked car with a dead man inside." + } +] diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts index a4f162c..92f86c5 100644 --- a/deep-sea-stories/packages/backend/src/schemas.ts +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -1,3 +1,5 @@ import z from 'zod'; export const getRoomInputSchema = z.object({ roomId: z.string() }); + +export const createPeerInputSchema = z.object({ roomId: z.string() }); diff --git a/deep-sea-stories/packages/backend/src/service/agent.ts b/deep-sea-stories/packages/backend/src/service/agent.ts deleted file mode 100644 index dae7cef..0000000 --- a/deep-sea-stories/packages/backend/src/service/agent.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RealtimeAgent } from '@openai/agents-realtime'; -import { AGENT_INSTRUCTIONS } from '../config.js'; - -export function getRealtimeAgent(): RealtimeAgent { - return new RealtimeAgent({ - name: 'Riddle Master', - instructions: AGENT_INSTRUCTIONS, - }); -} diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index be5c1d8..216699b 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -1,21 +1,47 @@ -import { FishjamWSNotifier, FishjamConfig } from '@fishjam-cloud/js-server-sdk'; -import { RealtimeSession } from '@openai/agents-realtime'; -import { getRealtimeAgent } from './agent.js'; +import { FishjamWSNotifier } from '@fishjam-cloud/js-server-sdk'; +import { CONFIG } from '../config.js'; +import { roomService } from './room.js'; -export async function getNotifier( - session: RealtimeSession, - config: FishjamConfig, -): Promise { - const notifier = new FishjamWSNotifier( - config, - () => {}, - () => {}, - ); +class NotifierService { + private notifier: FishjamWSNotifier | null = null; + private isConnected = false; - notifier.on('peerConnected', () => { - const agent = getRealtimeAgent(); - const session = new RealtimeSession(agent); - session.sendMessage('start'); - }); - return notifier; + async initialize() { + if (this.notifier !== null) { + return; + } + this.notifier = new FishjamWSNotifier( + { + fishjamId: CONFIG.FISHJAM_ID, + managementToken: CONFIG.FISHJAM_MANAGEMENT_TOKEN, + }, + (msg) => { + console.log(`Got error: ${msg}`); + }, + (code, reason) => { + this.isConnected = false; + console.log( + `FishjamWSNotifier closed with code: ${code}, reason: ${reason}`, + ); + }, + ); + this.isConnected = true; + + this.setupEventHandlers(); + } + + private setupEventHandlers() { + if (!this.notifier) return; + this.notifier.on('peerConnected', async (msg) => { + const sessionManager = roomService.getSessionManager(msg.roomId); + await sessionManager?.createSession(msg.peerId, msg.roomId); + }); + + this.notifier.on('peerDisconnected', async (msg) => { + const sessionManager = roomService.getSessionManager(msg.roomId); + await sessionManager?.deleteSession(msg.peerId); + }); + } } + +export const notifierService = new NotifierService(); diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts new file mode 100644 index 0000000..c405bd4 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -0,0 +1,64 @@ +import { + FishjamAgent, + FishjamClient, + Peer, + RoomId, +} from '@fishjam-cloud/js-server-sdk'; +import { Story } from '../types.js'; +import { getRandomStory } from '../utils.js'; +import { FISHJAM_AGENT_OPTIONS } from '../config.js'; +import { SessionManager } from './session.js'; + +class RoomService { + private RoomToStory = new Map(); + private RoomToFishjamAgent = new Map(); + private RoomToPeers = new Map(); + private RoomToSessionManager = new Map(); + + getStory(roomId: RoomId) { + return this.RoomToStory.get(roomId); + } + + getAgent(roomId: RoomId) { + return this.RoomToFishjamAgent.get(roomId); + } + + getSessionManager(roomId: RoomId) { + if (!this.RoomToSessionManager.get(roomId)) { + this.RoomToSessionManager.set(roomId, new SessionManager()); + } + return this.RoomToSessionManager.get(roomId); + } + + createStory(roomId: RoomId) { + const story = getRandomStory(); + this.RoomToStory.set(roomId, story); + } + + async createPeer(roomId: RoomId, fishjam: FishjamClient) { + const { peer, peerToken } = await fishjam.createPeer(roomId); + const peers = this.RoomToPeers.get(roomId) || []; + peers.push(peer); + this.RoomToPeers.set(roomId, peers); + return { peer, peerToken }; + } + + async createFishjamAgent(roomId: RoomId, fishjam: FishjamClient) { + const { agent } = await fishjam.createAgent( + roomId, + FISHJAM_AGENT_OPTIONS, + (msg) => { + console.log(`Fishjam Agent for room: ${roomId} got error: ${msg}`); + }, + (code, reason) => { + console.log( + `Fishjam Agent for room: ${roomId} closed with code: ${code}, reason: ${reason}`, + ); + }, + ); + + this.RoomToFishjamAgent.set(roomId, agent); + } +} + +export const roomService = new RoomService(); diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts new file mode 100644 index 0000000..fe341eb --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -0,0 +1,56 @@ +import { RealtimeSession } from '@openai/agents-realtime'; +import type { RoomId, PeerId } from '@fishjam-cloud/js-server-sdk'; +import { roomService } from './room.js'; +import { RealtimeAgent } from '@openai/agents-realtime'; +import { getInstructionsForStory } from '../utils.js'; + +export class SessionManager { + private sessions = new Map(); + + async createSession( + peerId: PeerId, + roomId: RoomId, + ): Promise { + await this.deleteSession(peerId); + + const story = roomService.getStory(roomId); + if (!story) { + throw new Error(`No story found for room ${roomId}`); + } + + const agent = new RealtimeAgent({ + name: 'Riddle Master', + instructions: getInstructionsForStory(story), + }); + const session = new RealtimeSession(agent); + + this.sessions.set(peerId, session); + + session.sendMessage('start'); + + return session; + } + + async deleteSession(peerId: PeerId): Promise { + const session = this.sessions.get(peerId); + if (session) { + try { + session.close(); + } catch (error) { + console.error(`Error closing session for peer ${peerId}:`, error); + } + this.sessions.delete(peerId); + } + } + + getSession(peerId: PeerId): RealtimeSession | undefined { + return this.sessions.get(peerId); + } + + async cleanup(): Promise { + const promises = Array.from(this.sessions.keys()).map((peerId) => + this.deleteSession(peerId), + ); + await Promise.all(promises); + } +} diff --git a/deep-sea-stories/packages/backend/src/types.ts b/deep-sea-stories/packages/backend/src/types.ts new file mode 100644 index 0000000..2cb6a43 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/types.ts @@ -0,0 +1,4 @@ +export interface Story { + front: string; + back: string; +} diff --git a/deep-sea-stories/packages/backend/src/utils.ts b/deep-sea-stories/packages/backend/src/utils.ts new file mode 100644 index 0000000..ecacfcd --- /dev/null +++ b/deep-sea-stories/packages/backend/src/utils.ts @@ -0,0 +1,13 @@ +import { stories, AGENT_INSTRUCTIONS_TEMPLATE } from './config.js'; +import type { Story } from './types.js'; + +export function getRandomStory(): Story { + return stories[Math.floor(Math.random() * stories.length)]; +} + +export function getInstructionsForStory(story: Story): string { + return AGENT_INSTRUCTIONS_TEMPLATE.replace('{{FRONT}}', story.front).replace( + '{{BACK}}', + story.back, + ); +} diff --git a/deep-sea-stories/packages/backend/tests/.env.test b/deep-sea-stories/packages/backend/tests/.env.test new file mode 100644 index 0000000..99b091b --- /dev/null +++ b/deep-sea-stories/packages/backend/tests/.env.test @@ -0,0 +1,5 @@ +# Test environment variables for running tests +FISHJAM_ID=test-fishjam-id +FISHJAM_MANAGEMENT_TOKEN=test-management-token +FISHJAM_URL=https://test.fishjam.cloud +PORT=8001 \ No newline at end of file diff --git a/deep-sea-stories/packages/backend/tests/config.test.ts b/deep-sea-stories/packages/backend/tests/config.test.ts new file mode 100644 index 0000000..b394d72 --- /dev/null +++ b/deep-sea-stories/packages/backend/tests/config.test.ts @@ -0,0 +1,98 @@ +import { test, describe } from 'node:test'; +import assert from 'node:assert'; +import { + stories, + AGENT_INSTRUCTIONS_TEMPLATE, + configSchema, +} from '../src/config.js'; + +describe('Configuration', () => { + test('stories should be loaded and be a valid array', () => { + assert(Array.isArray(stories), 'Stories should be an array'); + assert(stories.length > 0, 'Stories array should not be empty'); + }); + + test('each story should have valid front and back properties', () => { + stories.forEach((story, index) => { + assert(typeof story === 'object', `Story ${index} should be an object`); + assert(story !== null, `Story ${index} should not be null`); + + assert( + typeof story.front === 'string', + `Story ${index} should have a front property of type string`, + ); + assert( + typeof story.back === 'string', + `Story ${index} should have a back property of type string`, + ); + + assert( + story.front.length > 0, + `Story ${index} front should not be empty`, + ); + assert(story.back.length > 0, `Story ${index} back should not be empty`); + }); + }); + + test('AGENT_INSTRUCTIONS_TEMPLATE should be loaded and contain placeholders', () => { + assert( + typeof AGENT_INSTRUCTIONS_TEMPLATE === 'string', + 'Instructions template should be a string', + ); + assert( + AGENT_INSTRUCTIONS_TEMPLATE.length > 0, + 'Instructions template should not be empty', + ); + + assert( + AGENT_INSTRUCTIONS_TEMPLATE.includes('{{FRONT}}'), + 'Template should contain {{FRONT}} placeholder', + ); + assert( + AGENT_INSTRUCTIONS_TEMPLATE.includes('{{BACK}}'), + 'Template should contain {{BACK}} placeholder', + ); + }); + + test('configSchema should validate required environment variables', () => { + assert.throws(() => { + configSchema.parse({}); + }, 'Should throw when required FISHJAM_ID is missing'); + + assert.throws(() => { + configSchema.parse({ + FISHJAM_ID: 'test-id', + }); + }, 'Should throw when required FISHJAM_MANAGEMENT_TOKEN is missing'); + + assert.doesNotThrow(() => { + configSchema.parse({ + FISHJAM_ID: 'test-id', + FISHJAM_MANAGEMENT_TOKEN: 'test-token', + }); + }, 'Should not throw with valid required fields'); + }); + + test('configSchema should provide default PORT value', () => { + const config = configSchema.parse({ + FISHJAM_ID: 'test-id', + FISHJAM_MANAGEMENT_TOKEN: 'test-token', + }); + + assert.strictEqual(config.PORT, 8000, 'Should default PORT to 8000'); + }); + + test('configSchema should accept custom PORT value', () => { + const config = configSchema.parse({ + FISHJAM_ID: 'test-id', + FISHJAM_MANAGEMENT_TOKEN: 'test-token', + PORT: '3000', + }); + + assert.strictEqual( + config.PORT, + 3000, + 'Should accept and convert custom PORT value', + ); + }); +}); diff --git a/deep-sea-stories/packages/backend/tests/index.test.ts b/deep-sea-stories/packages/backend/tests/index.test.ts new file mode 100644 index 0000000..8149735 --- /dev/null +++ b/deep-sea-stories/packages/backend/tests/index.test.ts @@ -0,0 +1,6 @@ +console.log('🧪 Running Deep Sea Stories Backend Tests...\n'); + +import './setup.js'; + +import './config.test.js'; +import './utils.test.js'; diff --git a/deep-sea-stories/packages/backend/tests/setup.ts b/deep-sea-stories/packages/backend/tests/setup.ts new file mode 100644 index 0000000..b80db42 --- /dev/null +++ b/deep-sea-stories/packages/backend/tests/setup.ts @@ -0,0 +1,12 @@ +import dotenv from 'dotenv'; +import { join } from 'path'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +dotenv.config({ + path: join(__dirname, '.env.test'), + override: true, +}); diff --git a/deep-sea-stories/packages/backend/tests/utils.test.ts b/deep-sea-stories/packages/backend/tests/utils.test.ts new file mode 100644 index 0000000..ad8c72e --- /dev/null +++ b/deep-sea-stories/packages/backend/tests/utils.test.ts @@ -0,0 +1,55 @@ +import { test, describe } from 'node:test'; +import assert from 'node:assert'; +import { getRandomStory, getInstructionsForStory } from '../src/utils.js'; +import type { Story } from '../src/types.js'; + +describe('Stories Service', () => { + test('getRandomStory should return a valid Story object', () => { + const story = getRandomStory(); + + assert.strictEqual(typeof story, 'object'); + assert(story !== null, 'Story should not be null'); + + assert( + typeof story.front === 'string', + 'Story should have a front property of type string', + ); + assert( + typeof story.back === 'string', + 'Story should have a back property of type string', + ); + + assert(story.front.length > 0, 'Story front should not be empty'); + assert(story.back.length > 0, 'Story back should not be empty'); + }); + + test('getInstructionsForStory should replace template placeholders', () => { + const testStory: Story = { + front: 'Test front story', + back: 'Test back story', + }; + + const instructions = getInstructionsForStory(testStory); + + assert( + !instructions.includes('{{FRONT}}'), + 'Should replace {{FRONT}} placeholder', + ); + assert( + !instructions.includes('{{BACK}}'), + 'Should replace {{BACK}} placeholder', + ); + + assert( + instructions.includes(testStory.front), + 'Should include front story content', + ); + assert( + instructions.includes(testStory.back), + 'Should include back story content', + ); + + assert(typeof instructions === 'string', 'Should return a string'); + assert(instructions.length > 0, 'Should return non-empty instructions'); + }); +}); diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 3e16087..a2bd510 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -563,13 +563,13 @@ __metadata: languageName: node linkType: hard -"@fishjam-cloud/js-server-sdk@npm:^0.21.0": - version: 0.21.0 - resolution: "@fishjam-cloud/js-server-sdk@npm:0.21.0" +"@fishjam-cloud/js-server-sdk@npm:^0.22.0": + version: 0.22.0 + resolution: "@fishjam-cloud/js-server-sdk@npm:0.22.0" dependencies: axios: "npm:^1.7.9" uuid: "npm:^11.1.0" - checksum: 10c0/6574e887a731b6a2e0db691ea4320fe726ce7bd51731fbe51d697c91842d18d4d70aa55bb43e487b472ef255e904fef721a4abef2170e9588f119ffe22ca234b + checksum: 10c0/cf1022a0887e4df018c9b449999d85349b64214c20a7620d78d11d9b9c26571d126e82ebb448115e72054cd13112eb386df1db2a87bbfffc26feb8a385f662c4 languageName: node linkType: hard @@ -1416,13 +1416,14 @@ __metadata: version: 0.0.0-use.local resolution: "backend@workspace:packages/backend" dependencies: - "@fishjam-cloud/js-server-sdk": "npm:^0.21.0" + "@fishjam-cloud/js-server-sdk": "npm:^0.22.0" "@openai/agents-realtime": "npm:^0.1.7" "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" "@types/node": "npm:^24.5.2" dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" + openai: "npm:^6.1.0" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" zod: "npm:^4.1.11" @@ -3010,6 +3011,23 @@ __metadata: languageName: node linkType: hard +"openai@npm:^6.1.0": + version: 6.1.0 + resolution: "openai@npm:6.1.0" + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + bin: + openai: bin/cli + checksum: 10c0/770808d8afbbe084691e65738fc2cbd02f816fd0bd7240346ec55b39e4652532d0a30dd0be3bd2593f53c6035968713a4a51ac34ee4fbc9602c03fb0568a1771 + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" From 3452cf8e441c46362e9b68a1ee1a9978bb1915ee Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 6 Oct 2025 10:22:02 +0200 Subject: [PATCH 24/65] lint, format --- deep-sea-stories/packages/backend/src/config.ts | 6 +++--- deep-sea-stories/packages/backend/src/controllers/peers.ts | 4 ++-- deep-sea-stories/packages/backend/src/service/notifier.ts | 3 --- deep-sea-stories/packages/backend/src/service/room.ts | 4 ++-- deep-sea-stories/packages/backend/tests/setup.ts | 6 +++--- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index c8be7c7..b121be0 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -1,8 +1,8 @@ import dotenv from 'dotenv'; import z from 'zod'; -import * as fs from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname, join } from 'path'; +import * as fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; import type { Story } from './types.js'; import type { PeerOptions } from '@fishjam-cloud/js-server-sdk'; diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index 1292faa..2814250 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -1,4 +1,4 @@ -import { RoomId, Peer, FishjamAgent } from '@fishjam-cloud/js-server-sdk'; +import type { RoomId } from '@fishjam-cloud/js-server-sdk'; import { createPeerInputSchema } from '../schemas.js'; import { publicProcedure } from '../trpc.js'; import { roomService } from '../service/room.js'; @@ -8,7 +8,7 @@ export const createPeer = publicProcedure .mutation(async ({ ctx, input }) => { const room = await ctx.fishjam.getRoom(input.roomId as RoomId); // TODO: if doesn't exist create - if (room.peers.length == 0) { + if (room.peers.length === 0) { await roomService.createFishjamAgent(room.id, ctx.fishjam); } const { peer, peerToken } = await roomService.createPeer( diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 216699b..02961e9 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -4,7 +4,6 @@ import { roomService } from './room.js'; class NotifierService { private notifier: FishjamWSNotifier | null = null; - private isConnected = false; async initialize() { if (this.notifier !== null) { @@ -19,13 +18,11 @@ class NotifierService { console.log(`Got error: ${msg}`); }, (code, reason) => { - this.isConnected = false; console.log( `FishjamWSNotifier closed with code: ${code}, reason: ${reason}`, ); }, ); - this.isConnected = true; this.setupEventHandlers(); } diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index c405bd4..06805a7 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -1,10 +1,10 @@ -import { +import type { FishjamAgent, FishjamClient, Peer, RoomId, } from '@fishjam-cloud/js-server-sdk'; -import { Story } from '../types.js'; +import type { Story } from '../types.js'; import { getRandomStory } from '../utils.js'; import { FISHJAM_AGENT_OPTIONS } from '../config.js'; import { SessionManager } from './session.js'; diff --git a/deep-sea-stories/packages/backend/tests/setup.ts b/deep-sea-stories/packages/backend/tests/setup.ts index b80db42..dec3bf9 100644 --- a/deep-sea-stories/packages/backend/tests/setup.ts +++ b/deep-sea-stories/packages/backend/tests/setup.ts @@ -1,7 +1,7 @@ import dotenv from 'dotenv'; -import { join } from 'path'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); From 1a92cf8f53a2966a175eae9743425d0876e0a35e Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 6 Oct 2025 16:53:02 +0200 Subject: [PATCH 25/65] elevenlabs integration --- .../packages/backend/.env.example | 1 + .../packages/backend/package.json | 4 +- .../packages/backend/src/config.ts | 1 + .../packages/backend/src/controllers/peers.ts | 4 +- deep-sea-stories/packages/backend/src/main.ts | 3 + .../backend/src/service/elevenlabs.ts | 312 ++++++++ .../packages/backend/src/service/notifier.ts | 25 + .../packages/backend/src/service/room.ts | 6 +- .../packages/backend/src/service/session.ts | 31 +- .../packages/backend/tests/config.test.ts | 12 +- deep-sea-stories/yarn.lock | 693 +----------------- 11 files changed, 406 insertions(+), 686 deletions(-) create mode 100644 deep-sea-stories/packages/backend/src/service/elevenlabs.ts diff --git a/deep-sea-stories/packages/backend/.env.example b/deep-sea-stories/packages/backend/.env.example index 3360907..429ef28 100644 --- a/deep-sea-stories/packages/backend/.env.example +++ b/deep-sea-stories/packages/backend/.env.example @@ -1,2 +1,3 @@ FISHJAM_ID="your-fishjam-id" FISHJAM_MANAGEMENT_TOKEN="your-management-token" +ELEVENLABS_API_KEY="your-elevenlabs-api-key" diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index acd7960..674dc0b 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -5,12 +5,12 @@ "type": "module", "dependencies": { "@fishjam-cloud/js-server-sdk": "^0.22.0", - "@openai/agents-realtime": "^0.1.7", "@trpc/server": "^11.6.0", + "@types/ws": "^8.18.1", "dotenv": "^17.2.3", "fastify": "^5.6.1", - "openai": "^6.1.0", "pino-pretty": "^13.1.1", + "ws": "^8.18.3", "zod": "^4.1.11" }, "devDependencies": { diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index b121be0..5faf222 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -15,6 +15,7 @@ export const configSchema = z.object({ PORT: z.coerce.number().int().default(8000), FISHJAM_ID: z.string(), FISHJAM_MANAGEMENT_TOKEN: z.string(), + ELEVENLABS_API_KEY: z.string(), }); export const stories: Story[] = JSON.parse( diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index 2814250..d88f965 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -7,7 +7,9 @@ export const createPeer = publicProcedure .input(createPeerInputSchema) .mutation(async ({ ctx, input }) => { const room = await ctx.fishjam.getRoom(input.roomId as RoomId); - // TODO: if doesn't exist create + if (!room) { + throw new Error(`Room with id ${input.roomId} does not exist`); + } if (room.peers.length === 0) { await roomService.createFishjamAgent(room.id, ctx.fishjam); } diff --git a/deep-sea-stories/packages/backend/src/main.ts b/deep-sea-stories/packages/backend/src/main.ts index ff8684f..c977f36 100644 --- a/deep-sea-stories/packages/backend/src/main.ts +++ b/deep-sea-stories/packages/backend/src/main.ts @@ -6,6 +6,7 @@ import Fastify from 'fastify'; import { CONFIG } from './config.js'; import { createContext } from './context.js'; import { type AppRouter, appRouter } from './router.js'; +import { notifierService } from './service/notifier.js'; const fastify = Fastify({ logger: { transport: { target: 'pino-pretty' } }, @@ -23,6 +24,8 @@ fastify.register(fastifyTRPCPlugin, { }); try { + await notifierService.initialize(); + await fastify.ready(); await fastify.listen({ port: CONFIG.PORT }); } catch (err) { diff --git a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts new file mode 100644 index 0000000..adea68b --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts @@ -0,0 +1,312 @@ +import { CONFIG } from "../config.js"; +import WebSocket from 'ws'; +import { EventEmitter } from 'events'; + + +interface ConversationInitiationMetadataEvent { + conversation_id: string; + agent_output_audio_format: string; + user_input_audio_format: string; +} + +interface ConversationConfig { + agent_prompt?: string; + first_message?: string; + language?: string; + voice_id?: string; + [key: string]: any; +} + +interface AgentCreateRequest { + conversation_config: ConversationConfig; + platform_settings?: { + [key: string]: any; + }; + name?: string; + tags?: string[]; +} + +export interface AgentId { + agent_id: string; +} + +class ElevenLabs { + private apiKey: string; + private baseUrl: string = 'https://api.elevenlabs.io'; + + constructor(apiKey: string) { + this.apiKey = apiKey; + } + + async createAgent( + conversationConfig: ConversationConfig, + options?: { + name?: string; + tags?: string[]; + platformSettings?: { [key: string]: any }; + } + ): Promise { + try { + const requestBody: AgentCreateRequest = { + conversation_config: conversationConfig, + ...(options?.name && { name: options.name }), + ...(options?.tags && { tags: options.tags }), + ...(options?.platformSettings && { platform_settings: options.platformSettings }) + }; + + const response = await fetch(`${this.baseUrl}/v1/convai/agents/create`, { + method: 'POST', + headers: { + 'xi-api-key': this.apiKey, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody) + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`ElevenLabs API error: ${response.status} ${response.statusText} - ${errorText}`); + } + + return await response.json() as AgentId; + } catch (error) { + throw new Error(`Failed to create ElevenLabs agent: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + } +} + +/** + * WebSocket-based conversation with ElevenLabs for real-time audio streaming + * https://elevenlabs.io/docs/agents-platform/api-reference/agents-platform/websocket + * + * Events emitted: + * - 'ready': ({ conversationId, audioFormat, inputFormat }) - When conversation is ready + * - 'agentResponse': (AgentResponseEvent) - Text response from agent + * - 'userTranscript': (UserTranscriptEvent) - User speech transcription + * - 'agentAudio': (AudioEvent) - Audio response from agent + * - 'interruption': (InterruptionEvent) - When conversation is interrupted + * - 'vadScore': (VadScoreEvent) - Voice activity detection score + * - 'tentativeResponse': (TentativeAgentResponseEvent) - Tentative response + * - 'clientToolCall': (ClientToolCall) - Client tool call request + * - 'disconnected': ({ code, reason }) - When WebSocket disconnects + */ +export class ElevenLabsConversation extends EventEmitter { + private ws: WebSocket | null = null; + private conversationId: string | null = null; + private isConnected = false; + private audioFormat: string | null = null; + private inputFormat: string | null = null; + + constructor( + private agentId: string, + private apiKey: string, + private baseUrl: string = 'wss://api.elevenlabs.io' + ) { + super(); + } + + /** + * Start a conversation session with the ElevenLabs agent + */ + async connect(): Promise { + return new Promise((resolve, reject) => { + try { + const wsUrl = `${this.baseUrl}/v1/convai/conversation?agent_id=${this.agentId}`; + + this.ws = new WebSocket(wsUrl, { + headers: { + 'xi-api-key': this.apiKey, + 'User-Agent': 'Deep-Sea-Stories-Backend/1.0.0', + }, + }); + + this.ws.on('open', () => { + console.log('Connected to ElevenLabs WebSocket'); + this.isConnected = true; + + this.sendMessage({ + type: 'conversation_initiation_client_data', + conversation_config_override: {} + }); + + resolve(); + }); + + this.ws.on('message', (data: Buffer) => { + try { + const message = JSON.parse(data.toString()); + this.handleMessage(message); + } catch (error) { + console.error('Failed to parse WebSocket message:', error); + } + }); + + this.ws.on('close', (code: number, reason: Buffer) => { + console.log(`ElevenLabs WebSocket connection closed: ${code} - ${reason.toString()}`); + this.isConnected = false; + this.emit('disconnected', { code, reason: reason.toString() }); + }); + + this.ws.on('error', (error) => { + console.error('ElevenLabs WebSocket error:', error); + this.isConnected = false; + reject(error); + }); + + } catch (error) { + reject(error); + } + }); + } + + /** + * Send raw audio data to ElevenLabs + * @param audioBuffer Raw audio data as Buffer + */ + sendAudio(audioBuffer: Buffer): void { + if (!this.isConnected || !this.ws) { + console.warn('Cannot send audio: WebSocket not connected'); + return; + } + + try { + const audioBase64 = audioBuffer.toString('base64'); + + this.sendMessage({ + user_audio_chunk: audioBase64 + }); + } catch (error) { + console.error('Failed to send audio to ElevenLabs:', error); + } + } + + sendUserMessage(text: string): void { + this.sendMessage({ + type: 'user_message', + text: text + }); + } + + sendContextualUpdate(text: string): void { + this.sendMessage({ + type: 'contextual_update', + text: text + }); + } + + sendUserActivity(): void { + this.sendMessage({ + type: 'user_activity' + }); + } + + sendClientToolResult(toolCallId: string, result: string, isError: boolean = false): void { + this.sendMessage({ + type: 'client_tool_result', + tool_call_id: toolCallId, + result: result, + is_error: isError + }); + } + + async disconnect(): Promise { + if (this.ws) { + this.isConnected = false; + this.ws.close(); + this.ws = null; + } + } + + isSessionActive(): boolean { + return this.isConnected && this.ws?.readyState === WebSocket.OPEN; + } + + private sendMessage(message: any): void { + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(message)); + } + } + + private handleMessage(message: any): void { + switch (message.type) { + case 'conversation_initiation_metadata': + const metadata: ConversationInitiationMetadataEvent = message.conversation_initiation_metadata_event; + this.conversationId = metadata?.conversation_id; + this.audioFormat = metadata?.agent_output_audio_format; + this.inputFormat = metadata?.user_input_audio_format; + console.log('Conversation initiated:', { + conversationId: this.conversationId, + audioFormat: this.audioFormat, + inputFormat: this.inputFormat + }); + this.emit('ready', { + conversationId: this.conversationId, + audioFormat: this.audioFormat, + inputFormat: this.inputFormat + }); + break; + + case 'agent_response': + console.log('Agent response:', message.agent_response_event?.agent_response); + this.emit('agentResponse', message.agent_response_event); + break; + + case 'user_transcript': + console.log('User transcript:', message.user_transcription_event?.user_transcript); + this.emit('userTranscript', message.user_transcription_event); + break; + + case 'audio': + this.emit('agentAudio', message.audio_event); + break; + + case 'interruption': + console.log('Conversation interrupted'); + this.emit('interruption', message.interruption_event); + break; + + case 'ping': + console.log('Received ping, sending pong'); + this.sendMessage({ + type: 'pong', + event_id: message.ping_event?.event_id + }); + break; + + case 'vad_score': + this.emit('vadScore', message.vad_score_event); + break; + + case 'internal_tentative_agent_response': + this.emit('tentativeResponse', message.tentative_agent_response_internal_event); + break; + + case 'client_tool_call': + console.log('Client tool call:', message.client_tool_call); + this.emit('clientToolCall', message.client_tool_call); + break; + + case 'contextual_update': + this.emit('contextualUpdate', message); + break; + + default: + console.log('Received unknown message type:', message.type); + this.emit('message', message); + } + } + + getConversationId(): string | null { + return this.conversationId; + } + + getAudioFormat(): string | null { + return this.audioFormat; + } + + getInputFormat(): string | null { + return this.inputFormat; + } +} + +export const elevenLabs = new ElevenLabs(CONFIG.ELEVENLABS_API_KEY); diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 02961e9..44f7e63 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -30,11 +30,36 @@ class NotifierService { private setupEventHandlers() { if (!this.notifier) return; this.notifier.on('peerConnected', async (msg) => { + console.log(`Peer connected: ${msg.peerId} in room ${msg.roomId}`); + + if ( !roomService.getPeers(msg.roomId).find( p => p.id === msg.peerId ) ) { + return; + } + const sessionManager = roomService.getSessionManager(msg.roomId); await sessionManager?.createSession(msg.peerId, msg.roomId); + + const fishjam_agent = roomService.getAgent(msg.roomId); + fishjam_agent?.on('trackData', (msg) => { + const {data, peerId} = msg; + + const session = sessionManager?.getSession(peerId); + + if (session && data) { + console.log(`Sending ${data.byteLength} bytes of audio data to ElevenLabs for peer ${peerId}`); + try { + const audioBuffer = Buffer.from(data); + session.sendAudio(audioBuffer); + } catch (error) { + console.error(`Error sending audio to ElevenLabs for peer ${peerId}:`, error); + } + } + + }); }); this.notifier.on('peerDisconnected', async (msg) => { + console.log(`Peer disconnected: ${msg.peerId} from room ${msg.roomId}`); const sessionManager = roomService.getSessionManager(msg.roomId); await sessionManager?.deleteSession(msg.peerId); }); diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index 06805a7..69021e9 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -11,8 +11,8 @@ import { SessionManager } from './session.js'; class RoomService { private RoomToStory = new Map(); - private RoomToFishjamAgent = new Map(); private RoomToPeers = new Map(); + private RoomToFishjamAgent = new Map(); private RoomToSessionManager = new Map(); getStory(roomId: RoomId) { @@ -23,6 +23,10 @@ class RoomService { return this.RoomToFishjamAgent.get(roomId); } + getPeers(roomId: RoomId) { + return this.RoomToPeers.get(roomId) || []; + } + getSessionManager(roomId: RoomId) { if (!this.RoomToSessionManager.get(roomId)) { this.RoomToSessionManager.set(roomId, new SessionManager()); diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index fe341eb..18d5601 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -1,16 +1,16 @@ -import { RealtimeSession } from '@openai/agents-realtime'; import type { RoomId, PeerId } from '@fishjam-cloud/js-server-sdk'; +import { elevenLabs, ElevenLabsConversation } from './elevenlabs.js'; import { roomService } from './room.js'; -import { RealtimeAgent } from '@openai/agents-realtime'; import { getInstructionsForStory } from '../utils.js'; +import { CONFIG } from '../config.js'; export class SessionManager { - private sessions = new Map(); + private sessions = new Map(); async createSession( peerId: PeerId, roomId: RoomId, - ): Promise { + ): Promise { await this.deleteSession(peerId); const story = roomService.getStory(roomId); @@ -18,16 +18,21 @@ export class SessionManager { throw new Error(`No story found for room ${roomId}`); } - const agent = new RealtimeAgent({ - name: 'Riddle Master', - instructions: getInstructionsForStory(story), - }); - const session = new RealtimeSession(agent); + const instructions = getInstructionsForStory(story); - this.sessions.set(peerId, session); + const agentId = await elevenLabs.createAgent({ + agent_prompt: instructions, + first_message: "Welcome to the deep sea stories!", + language: "en" + }); - session.sendMessage('start'); + const session = new ElevenLabsConversation( + agentId.agent_id, + CONFIG.ELEVENLABS_API_KEY + ); + await session.connect(); + this.sessions.set(peerId, session); return session; } @@ -35,7 +40,7 @@ export class SessionManager { const session = this.sessions.get(peerId); if (session) { try { - session.close(); + await session.disconnect(); } catch (error) { console.error(`Error closing session for peer ${peerId}:`, error); } @@ -43,7 +48,7 @@ export class SessionManager { } } - getSession(peerId: PeerId): RealtimeSession | undefined { + getSession(peerId: PeerId): ElevenLabsConversation | undefined { return this.sessions.get(peerId); } diff --git a/deep-sea-stories/packages/backend/tests/config.test.ts b/deep-sea-stories/packages/backend/tests/config.test.ts index b394d72..f35a342 100644 --- a/deep-sea-stories/packages/backend/tests/config.test.ts +++ b/deep-sea-stories/packages/backend/tests/config.test.ts @@ -65,18 +65,27 @@ describe('Configuration', () => { }); }, 'Should throw when required FISHJAM_MANAGEMENT_TOKEN is missing'); + assert.throws(() => { + configSchema.parse({ + FISHJAM_ID: 'test-id', + FISHJAM_MANAGEMENT_TOKEN: 'test-token', + }); + }, 'Should throw when required ELEVENLABS_API_KEY is missing'); + assert.doesNotThrow(() => { configSchema.parse({ FISHJAM_ID: 'test-id', FISHJAM_MANAGEMENT_TOKEN: 'test-token', + ELEVENLABS_API_KEY: 'test-api-key', }); - }, 'Should not throw with valid required fields'); + }, 'Should not throw with all required fields'); }); test('configSchema should provide default PORT value', () => { const config = configSchema.parse({ FISHJAM_ID: 'test-id', FISHJAM_MANAGEMENT_TOKEN: 'test-token', + ELEVENLABS_API_KEY: 'test-api-key', }); assert.strictEqual(config.PORT, 8000, 'Should default PORT to 8000'); @@ -86,6 +95,7 @@ describe('Configuration', () => { const config = configSchema.parse({ FISHJAM_ID: 'test-id', FISHJAM_MANAGEMENT_TOKEN: 'test-token', + ELEVENLABS_API_KEY: 'test-api-key', PORT: '3000', }); diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index a2bd510..efa24bb 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -640,26 +640,6 @@ __metadata: languageName: node linkType: hard -"@modelcontextprotocol/sdk@npm:^1.17.2": - version: 1.18.2 - resolution: "@modelcontextprotocol/sdk@npm:1.18.2" - dependencies: - ajv: "npm:^6.12.6" - content-type: "npm:^1.0.5" - cors: "npm:^2.8.5" - cross-spawn: "npm:^7.0.5" - eventsource: "npm:^3.0.2" - eventsource-parser: "npm:^3.0.0" - express: "npm:^5.0.1" - express-rate-limit: "npm:^7.5.0" - pkce-challenge: "npm:^5.0.0" - raw-body: "npm:^3.0.0" - zod: "npm:^3.23.8" - zod-to-json-schema: "npm:^3.24.1" - checksum: 10c0/f0cb7a97ff264cbd389753b038c7dd197f359445324a7d4eb1d8e9be2cfb1e19d6375a12098cdd71c06847e9978c976950fc17f8d4f5e7778dd99d6f9416a48e - languageName: node - linkType: hard - "@napi-rs/wasm-runtime@npm:^0.2.12": version: 0.2.12 resolution: "@napi-rs/wasm-runtime@npm:0.2.12" @@ -693,39 +673,6 @@ __metadata: languageName: node linkType: hard -"@openai/agents-core@npm:0.1.7": - version: 0.1.7 - resolution: "@openai/agents-core@npm:0.1.7" - dependencies: - "@modelcontextprotocol/sdk": "npm:^1.17.2" - debug: "npm:^4.4.0" - openai: "npm:^5.20.2" - peerDependencies: - zod: ^3.25.40 - dependenciesMeta: - "@modelcontextprotocol/sdk": - optional: true - peerDependenciesMeta: - zod: - optional: true - checksum: 10c0/9178b45d85df0b2b5de9d085f7321c590c672605ad55857338bf9a8891d982d5f78d7b015a3cea99fa2c063d01438a458f26a023082ab4c9133a836f241112b0 - languageName: node - linkType: hard - -"@openai/agents-realtime@npm:^0.1.7": - version: 0.1.7 - resolution: "@openai/agents-realtime@npm:0.1.7" - dependencies: - "@openai/agents-core": "npm:0.1.7" - "@types/ws": "npm:^8.18.1" - debug: "npm:^4.4.0" - ws: "npm:^8.18.1" - peerDependencies: - zod: ^3.25.40 - checksum: 10c0/7f91960b61ec5c31ba35c64dba3736612fd997aba14bd40d878046980599438f6572848c1c55898cf671b0b0d5653f871232698d6c01ee2ccf2a6a793ff66c02 - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -1203,7 +1150,16 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^24.5.2": +"@types/node@npm:*": + version: 24.7.0 + resolution: "@types/node@npm:24.7.0" + dependencies: + undici-types: "npm:~7.14.0" + checksum: 10c0/f036c78062cb3a0d5c6586bf2dac347ed3f4af121cef4ab92c85c44e32be1c50aab5ba96955842b7f8165f0e0f1c8066d1813ae259372df6c0fa9fadb1116a3e + languageName: node + linkType: hard + +"@types/node@npm:^24.5.2": version: 24.6.1 resolution: "@types/node@npm:24.6.1" dependencies: @@ -1269,16 +1225,6 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^2.0.0": - version: 2.0.0 - resolution: "accepts@npm:2.0.0" - dependencies: - mime-types: "npm:^3.0.0" - negotiator: "npm:^1.0.0" - checksum: 10c0/98374742097e140891546076215f90c32644feacf652db48412329de4c2a529178a81aa500fbb13dd3e6cbf6e68d829037b123ac037fc9a08bcec4b87b358eef - languageName: node - linkType: hard - "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -1300,18 +1246,6 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.6": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 - languageName: node - linkType: hard - "ajv@npm:^8.0.0, ajv@npm:^8.12.0": version: 8.17.1 resolution: "ajv@npm:8.17.1" @@ -1417,15 +1351,15 @@ __metadata: resolution: "backend@workspace:packages/backend" dependencies: "@fishjam-cloud/js-server-sdk": "npm:^0.22.0" - "@openai/agents-realtime": "npm:^0.1.7" "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" "@types/node": "npm:^24.5.2" + "@types/ws": "npm:^8.18.1" dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" - openai: "npm:^6.1.0" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" + ws: "npm:^8.18.3" zod: "npm:^4.1.11" languageName: unknown linkType: soft @@ -1446,23 +1380,6 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:^2.2.0": - version: 2.2.0 - resolution: "body-parser@npm:2.2.0" - dependencies: - bytes: "npm:^3.1.2" - content-type: "npm:^1.0.5" - debug: "npm:^4.4.0" - http-errors: "npm:^2.0.0" - iconv-lite: "npm:^0.6.3" - on-finished: "npm:^2.4.1" - qs: "npm:^6.14.0" - raw-body: "npm:^3.0.0" - type-is: "npm:^2.0.0" - checksum: 10c0/a9ded39e71ac9668e2211afa72e82ff86cc5ef94de1250b7d1ba9cc299e4150408aaa5f1e8b03dd4578472a3ce6d1caa2a23b27a6c18e526e48b4595174c116c - languageName: node - linkType: hard - "brace-expansion@npm:^2.0.1": version: 2.0.2 resolution: "brace-expansion@npm:2.0.2" @@ -1487,13 +1404,6 @@ __metadata: languageName: node linkType: hard -"bytes@npm:3.1.2, bytes@npm:^3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e - languageName: node - linkType: hard - "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -1524,16 +1434,6 @@ __metadata: languageName: node linkType: hard -"call-bound@npm:^1.0.2": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 - languageName: node - linkType: hard - "caniuse-lite@npm:^1.0.30001746": version: 1.0.30001746 resolution: "caniuse-lite@npm:1.0.30001746" @@ -1596,22 +1496,6 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:^1.0.0": - version: 1.0.0 - resolution: "content-disposition@npm:1.0.0" - dependencies: - safe-buffer: "npm:5.2.1" - checksum: 10c0/c7b1ba0cea2829da0352ebc1b7f14787c73884bc707c8bc2271d9e3bf447b372270d09f5d3980dc5037c749ceef56b9a13fccd0b0001c87c3f12579967e4dd27 - languageName: node - linkType: hard - -"content-type@npm:^1.0.5": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af - languageName: node - linkType: hard - "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -1619,20 +1503,6 @@ __metadata: languageName: node linkType: hard -"cookie-signature@npm:^1.2.1": - version: 1.2.2 - resolution: "cookie-signature@npm:1.2.2" - checksum: 10c0/54e05df1a293b3ce81589b27dddc445f462f6fa6812147c033350cd3561a42bc14481674e05ed14c7bd0ce1e8bb3dc0e40851bad75415733711294ddce0b7bc6 - languageName: node - linkType: hard - -"cookie@npm:^0.7.1": - version: 0.7.2 - resolution: "cookie@npm:0.7.2" - checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2 - languageName: node - linkType: hard - "cookie@npm:^1.0.1": version: 1.0.2 resolution: "cookie@npm:1.0.2" @@ -1640,17 +1510,7 @@ __metadata: languageName: node linkType: hard -"cors@npm:^2.8.5": - version: 2.8.5 - resolution: "cors@npm:2.8.5" - dependencies: - object-assign: "npm:^4" - vary: "npm:^1" - checksum: 10c0/373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.5, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -1675,7 +1535,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -1703,13 +1563,6 @@ __metadata: languageName: node linkType: hard -"depd@npm:2.0.0, depd@npm:^2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c - languageName: node - linkType: hard - "dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" @@ -1749,13 +1602,6 @@ __metadata: languageName: node linkType: hard -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 - languageName: node - linkType: hard - "electron-to-chromium@npm:^1.5.227": version: 1.5.228 resolution: "electron-to-chromium@npm:1.5.228" @@ -1777,13 +1623,6 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:^2.0.0": - version: 2.0.0 - resolution: "encodeurl@npm:2.0.0" - checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb - languageName: node - linkType: hard - "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -1957,36 +1796,6 @@ __metadata: languageName: node linkType: hard -"escape-html@npm:^1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 - languageName: node - linkType: hard - -"etag@npm:^1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 - languageName: node - linkType: hard - -"eventsource-parser@npm:^3.0.0, eventsource-parser@npm:^3.0.1": - version: 3.0.6 - resolution: "eventsource-parser@npm:3.0.6" - checksum: 10c0/70b8ccec7dac767ef2eca43f355e0979e70415701691382a042a2df8d6a68da6c2fca35363669821f3da876d29c02abe9b232964637c1b6635c940df05ada78a - languageName: node - linkType: hard - -"eventsource@npm:^3.0.2": - version: 3.0.7 - resolution: "eventsource@npm:3.0.7" - dependencies: - eventsource-parser: "npm:^3.0.1" - checksum: 10c0/c48a73c38f300e33e9f11375d4ee969f25cbb0519608a12378a38068055ae8b55b6e0e8a49c3f91c784068434efe1d9f01eb49b6315b04b0da9157879ce2f67d - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -1994,50 +1803,6 @@ __metadata: languageName: node linkType: hard -"express-rate-limit@npm:^7.5.0": - version: 7.5.1 - resolution: "express-rate-limit@npm:7.5.1" - peerDependencies: - express: ">= 4.11" - checksum: 10c0/b07de84d700a2c07c4bf2f040e7558ed5a1f660f03ed5f30bf8ff7b51e98ba7a85215640e70fc48cbbb9151066ea51239d9a1b41febc9b84d98c7915b0186161 - languageName: node - linkType: hard - -"express@npm:^5.0.1": - version: 5.1.0 - resolution: "express@npm:5.1.0" - dependencies: - accepts: "npm:^2.0.0" - body-parser: "npm:^2.2.0" - content-disposition: "npm:^1.0.0" - content-type: "npm:^1.0.5" - cookie: "npm:^0.7.1" - cookie-signature: "npm:^1.2.1" - debug: "npm:^4.4.0" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - etag: "npm:^1.8.1" - finalhandler: "npm:^2.1.0" - fresh: "npm:^2.0.0" - http-errors: "npm:^2.0.0" - merge-descriptors: "npm:^2.0.0" - mime-types: "npm:^3.0.0" - on-finished: "npm:^2.4.1" - once: "npm:^1.4.0" - parseurl: "npm:^1.3.3" - proxy-addr: "npm:^2.0.7" - qs: "npm:^6.14.0" - range-parser: "npm:^1.2.1" - router: "npm:^2.2.0" - send: "npm:^1.1.0" - serve-static: "npm:^2.2.0" - statuses: "npm:^2.0.1" - type-is: "npm:^2.0.1" - vary: "npm:^1.1.2" - checksum: 10c0/80ce7c53c5f56887d759b94c3f2283e2e51066c98d4b72a4cc1338e832b77f1e54f30d0239cc10815a0f849bdb753e6a284d2fa48d4ab56faf9c501f55d751d6 - languageName: node - linkType: hard - "fast-copy@npm:^3.0.2": version: 3.0.2 resolution: "fast-copy@npm:3.0.2" @@ -2052,20 +1817,13 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": +"fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b - languageName: node - linkType: hard - "fast-json-stringify@npm:^6.0.0": version: 6.1.1 resolution: "fast-json-stringify@npm:6.1.1" @@ -2147,20 +1905,6 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:^2.1.0": - version: 2.1.0 - resolution: "finalhandler@npm:2.1.0" - dependencies: - debug: "npm:^4.4.0" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - on-finished: "npm:^2.4.1" - parseurl: "npm:^1.3.3" - statuses: "npm:^2.0.1" - checksum: 10c0/da0bbca6d03873472ee890564eb2183f4ed377f25f3628a0fc9d16dac40bed7b150a0d82ebb77356e4c6d97d2796ad2dba22948b951dddee2c8768b0d1b9fb1f - languageName: node - linkType: hard - "find-my-way@npm:^9.0.0": version: 9.3.0 resolution: "find-my-way@npm:9.3.0" @@ -2205,20 +1949,6 @@ __metadata: languageName: node linkType: hard -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: 10c0/9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 - languageName: node - linkType: hard - -"fresh@npm:^2.0.0": - version: 2.0.0 - resolution: "fresh@npm:2.0.0" - checksum: 10c0/0557548194cb9a809a435bf92bcfbc20c89e8b5eb38861b73ced36750437251e39a111fc3a18b98531be9dd91fe1411e4969f229dc579ec0251ce6c5d4900bbc - languageName: node - linkType: hard - "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -2268,7 +1998,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0": +"get-intrinsic@npm:^1.2.6": version: 1.3.1 resolution: "get-intrinsic@npm:1.3.1" dependencies: @@ -2384,19 +2114,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:2.0.0, http-errors@npm:^2.0.0": - version: 2.0.0 - resolution: "http-errors@npm:2.0.0" - dependencies: - depd: "npm:2.0.0" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - toidentifier: "npm:1.0.1" - checksum: 10c0/fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19 - languageName: node - linkType: hard - "http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" @@ -2417,16 +2134,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.7.0": - version: 0.7.0 - resolution: "iconv-lite@npm:0.7.0" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/2382400469071c55b6746c531eed5fa4d033e5db6690b7331fb2a5f59a30d7a9782932e92253db26df33c1cf46fa200a3fbe524a2a7c62037c762283f188ec2f - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": +"iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -2442,13 +2150,6 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2.0.4": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - "ip-address@npm:^10.0.1": version: 10.0.1 resolution: "ip-address@npm:10.0.1" @@ -2456,13 +2157,6 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: 10c0/0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a - languageName: node - linkType: hard - "ipaddr.js@npm:^2.1.0": version: 2.2.0 resolution: "ipaddr.js@npm:2.2.0" @@ -2477,13 +2171,6 @@ __metadata: languageName: node linkType: hard -"is-promise@npm:^4.0.0": - version: 4.0.0 - resolution: "is-promise@npm:4.0.0" - checksum: 10c0/ebd5c672d73db781ab33ccb155fb9969d6028e37414d609b115cc534654c91ccd061821d5b987eefaa97cf4c62f0b909bb2f04db88306de26e91bfe8ddc01503 - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -2552,13 +2239,6 @@ __metadata: languageName: node linkType: hard -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce - languageName: node - linkType: hard - "json-schema-traverse@npm:^1.0.0": version: 1.0.0 resolution: "json-schema-traverse@npm:1.0.0" @@ -2756,20 +2436,6 @@ __metadata: languageName: node linkType: hard -"media-typer@npm:^1.1.0": - version: 1.1.0 - resolution: "media-typer@npm:1.1.0" - checksum: 10c0/7b4baa40b25964bb90e2121ee489ec38642127e48d0cc2b6baa442688d3fde6262bfdca86d6bbf6ba708784afcac168c06840c71facac70e390f5f759ac121b9 - languageName: node - linkType: hard - -"merge-descriptors@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-descriptors@npm:2.0.0" - checksum: 10c0/95389b7ced3f9b36fbdcf32eb946dc3dd1774c2fdf164609e55b18d03aa499b12bd3aae3a76c1c7185b96279e9803525550d3eb292b5224866060a288f335cb3 - languageName: node - linkType: hard - "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -2777,13 +2443,6 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:^1.54.0": - version: 1.54.0 - resolution: "mime-db@npm:1.54.0" - checksum: 10c0/8d907917bc2a90fa2df842cdf5dfeaf509adc15fe0531e07bb2f6ab15992416479015828d6a74200041c492e42cce3ebf78e5ce714388a0a538ea9c53eece284 - languageName: node - linkType: hard - "mime-types@npm:^2.1.12": version: 2.1.35 resolution: "mime-types@npm:2.1.35" @@ -2793,15 +2452,6 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1": - version: 3.0.1 - resolution: "mime-types@npm:3.0.1" - dependencies: - mime-db: "npm:^1.54.0" - checksum: 10c0/bd8c20d3694548089cf229016124f8f40e6a60bbb600161ae13e45f793a2d5bb40f96bbc61f275836696179c77c1d6bf4967b2a75e0a8ad40fe31f4ed5be4da5 - languageName: node - linkType: hard - "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -2955,20 +2605,6 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.3": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 - languageName: node - linkType: hard - "on-exit-leak-free@npm:^2.1.0": version: 2.1.2 resolution: "on-exit-leak-free@npm:2.1.2" @@ -2976,15 +2612,6 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:^2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 - languageName: node - linkType: hard - "once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -2994,40 +2621,6 @@ __metadata: languageName: node linkType: hard -"openai@npm:^5.20.2": - version: 5.23.2 - resolution: "openai@npm:5.23.2" - peerDependencies: - ws: ^8.18.0 - zod: ^3.23.8 - peerDependenciesMeta: - ws: - optional: true - zod: - optional: true - bin: - openai: bin/cli - checksum: 10c0/8ee37f37c64fd04a61622c4782d231e8f0245e2d85956d833e43d30946edbf07d5276cd74e09aa5d23006de8da43dad312246a9dd7ca6ca6d65d983fc976ffa6 - languageName: node - linkType: hard - -"openai@npm:^6.1.0": - version: 6.1.0 - resolution: "openai@npm:6.1.0" - peerDependencies: - ws: ^8.18.0 - zod: ^3.25 || ^4.0 - peerDependenciesMeta: - ws: - optional: true - zod: - optional: true - bin: - openai: bin/cli - checksum: 10c0/770808d8afbbe084691e65738fc2cbd02f816fd0bd7240346ec55b39e4652532d0a30dd0be3bd2593f53c6035968713a4a51ac34ee4fbc9602c03fb0568a1771 - languageName: node - linkType: hard - "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -3042,13 +2635,6 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 - languageName: node - linkType: hard - "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -3066,13 +2652,6 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:^8.0.0": - version: 8.3.0 - resolution: "path-to-regexp@npm:8.3.0" - checksum: 10c0/ee1544a73a3f294a97a4c663b0ce71bbf1621d732d80c9c9ed201b3e911a86cb628ebad691b9d40f40a3742fe22011e5a059d8eed2cf63ec2cb94f6fb4efe67c - languageName: node - linkType: hard - "picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -3147,13 +2726,6 @@ __metadata: languageName: node linkType: hard -"pkce-challenge@npm:^5.0.0": - version: 5.0.0 - resolution: "pkce-challenge@npm:5.0.0" - checksum: 10c0/c6706d627fdbb6f22bf8cc5d60d96d6b6a7bb481399b336a3d3f4e9bfba3e167a2c32f8ec0b5e74be686a0ba3bcc9894865d4c2dd1b91cea4c05dba1f28602c3 - languageName: node - linkType: hard - "postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -3196,16 +2768,6 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:^2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: "npm:0.2.0" - ipaddr.js: "npm:1.9.1" - checksum: 10c0/c3eed999781a35f7fd935f398b6d8920b6fb00bbc14287bc6de78128ccc1a02c89b95b56742bf7cf0362cc333c61d138532049c7dedc7a328ef13343eff81210 - languageName: node - linkType: hard - "proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" @@ -3223,22 +2785,6 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 - languageName: node - linkType: hard - -"qs@npm:^6.14.0": - version: 6.14.0 - resolution: "qs@npm:6.14.0" - dependencies: - side-channel: "npm:^1.1.0" - checksum: 10c0/8ea5d91bf34f440598ee389d4a7d95820e3b837d3fd9f433871f7924801becaa0cd3b3b4628d49a7784d06a8aea9bc4554d2b6d8d584e2d221dc06238a42909c - languageName: node - linkType: hard - "quick-format-unescaped@npm:^4.0.3": version: 4.0.4 resolution: "quick-format-unescaped@npm:4.0.4" @@ -3246,25 +2792,6 @@ __metadata: languageName: node linkType: hard -"range-parser@npm:^1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 - languageName: node - linkType: hard - -"raw-body@npm:^3.0.0": - version: 3.0.1 - resolution: "raw-body@npm:3.0.1" - dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.7.0" - unpipe: "npm:1.0.0" - checksum: 10c0/892f4fbd21ecab7e2fed0f045f7af9e16df7e8050879639d4e482784a2f4640aaaa33d916a0e98013f23acb82e09c2e3c57f84ab97104449f728d22f65a7d79a - languageName: node - linkType: hard - "react-dom@npm:^19.1.1": version: 19.1.1 resolution: "react-dom@npm:19.1.1" @@ -3420,26 +2947,6 @@ __metadata: languageName: node linkType: hard -"router@npm:^2.2.0": - version: 2.2.0 - resolution: "router@npm:2.2.0" - dependencies: - debug: "npm:^4.4.0" - depd: "npm:^2.0.0" - is-promise: "npm:^4.0.0" - parseurl: "npm:^1.3.3" - path-to-regexp: "npm:^8.0.0" - checksum: 10c0/3279de7450c8eae2f6e095e9edacbdeec0abb5cb7249c6e719faa0db2dba43574b4fff5892d9220631c9abaff52dd3cad648cfea2aaace845e1a071915ac8867 - languageName: node - linkType: hard - -"safe-buffer@npm:5.2.1": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 - languageName: node - linkType: hard - "safe-regex2@npm:^5.0.0": version: 5.0.0 resolution: "safe-regex2@npm:5.0.0" @@ -3495,37 +3002,6 @@ __metadata: languageName: node linkType: hard -"send@npm:^1.1.0, send@npm:^1.2.0": - version: 1.2.0 - resolution: "send@npm:1.2.0" - dependencies: - debug: "npm:^4.3.5" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - etag: "npm:^1.8.1" - fresh: "npm:^2.0.0" - http-errors: "npm:^2.0.0" - mime-types: "npm:^3.0.1" - ms: "npm:^2.1.3" - on-finished: "npm:^2.4.1" - range-parser: "npm:^1.2.1" - statuses: "npm:^2.0.1" - checksum: 10c0/531bcfb5616948d3468d95a1fd0adaeb0c20818ba4a500f439b800ca2117971489e02074ce32796fd64a6772ea3e7235fe0583d8241dbd37a053dc3378eff9a5 - languageName: node - linkType: hard - -"serve-static@npm:^2.2.0": - version: 2.2.0 - resolution: "serve-static@npm:2.2.0" - dependencies: - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - parseurl: "npm:^1.3.3" - send: "npm:^1.2.0" - checksum: 10c0/30e2ed1dbff1984836cfd0c65abf5d3f3f83bcd696c99d2d3c97edbd4e2a3ff4d3f87108a7d713640d290a7b6fe6c15ddcbc61165ab2eaad48ea8d3b52c7f913 - languageName: node - linkType: hard - "set-cookie-parser@npm:^2.6.0": version: 2.7.1 resolution: "set-cookie-parser@npm:2.7.1" @@ -3533,13 +3009,6 @@ __metadata: languageName: node linkType: hard -"setprototypeof@npm:1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc - languageName: node - linkType: hard - "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -3556,54 +3025,6 @@ __metadata: languageName: node linkType: hard -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 - languageName: node - linkType: hard - -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 - languageName: node - linkType: hard - "signal-exit@npm:^4.0.1": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -3678,20 +3099,6 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1": - version: 2.0.1 - resolution: "statuses@npm:2.0.1" - checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 - languageName: node - linkType: hard - -"statuses@npm:^2.0.1": - version: 2.0.2 - resolution: "statuses@npm:2.0.2" - checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f - languageName: node - linkType: hard - "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -3799,13 +3206,6 @@ __metadata: languageName: node linkType: hard -"toidentifier@npm:1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 - languageName: node - linkType: hard - "tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" @@ -3836,17 +3236,6 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^2.0.0, type-is@npm:^2.0.1": - version: 2.0.1 - resolution: "type-is@npm:2.0.1" - dependencies: - content-type: "npm:^1.0.5" - media-typer: "npm:^1.1.0" - mime-types: "npm:^3.0.0" - checksum: 10c0/7f7ec0a060b16880bdad36824ab37c26019454b67d73e8a465ed5a3587440fbe158bc765f0da68344498235c877e7dbbb1600beccc94628ed05599d667951b99 - languageName: node - linkType: hard - "typescript@npm:^5.9.2": version: 5.9.3 resolution: "typescript@npm:5.9.3" @@ -3874,6 +3263,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.14.0": + version: 7.14.0 + resolution: "undici-types@npm:7.14.0" + checksum: 10c0/e7f3214b45d788f03c51ceb33817be99c65dae203863aa9386b3ccc47201a245a7955fc721fb581da9c888b6ebad59fa3f53405214afec04c455a479908f0f14 + languageName: node + linkType: hard + "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0" @@ -3892,13 +3288,6 @@ __metadata: languageName: node linkType: hard -"unpipe@npm:1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.1.3": version: 1.1.3 resolution: "update-browserslist-db@npm:1.1.3" @@ -3913,15 +3302,6 @@ __metadata: languageName: node linkType: hard -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c - languageName: node - linkType: hard - "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -3931,13 +3311,6 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1, vary@npm:^1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f - languageName: node - linkType: hard - "vite@npm:^7.1.7": version: 7.1.7 resolution: "vite@npm:7.1.7" @@ -4072,7 +3445,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.18.1": +"ws@npm:^8.18.3": version: 8.18.3 resolution: "ws@npm:8.18.3" peerDependencies: @@ -4108,22 +3481,6 @@ __metadata: languageName: node linkType: hard -"zod-to-json-schema@npm:^3.24.1": - version: 3.24.6 - resolution: "zod-to-json-schema@npm:3.24.6" - peerDependencies: - zod: ^3.24.1 - checksum: 10c0/b907ab6d057100bd25a37e5545bf5f0efa5902cd84d3c3ec05c2e51541431a47bd9bf1e5e151a244273409b45f5986d55b26e5d207f98abc5200702f733eb368 - languageName: node - linkType: hard - -"zod@npm:^3.23.8": - version: 3.25.76 - resolution: "zod@npm:3.25.76" - checksum: 10c0/5718ec35e3c40b600316c5b4c5e4976f7fee68151bc8f8d90ec18a469be9571f072e1bbaace10f1e85cf8892ea12d90821b200e980ab46916a6166a4260a983c - languageName: node - linkType: hard - "zod@npm:^4.1.11": version: 4.1.11 resolution: "zod@npm:4.1.11" From b72c5163906ed34e652dc8d89048109d70f20e94 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 6 Oct 2025 16:57:49 +0200 Subject: [PATCH 26/65] format, lint --- .../backend/src/service/elevenlabs.ts | 595 ++++++++++-------- .../packages/backend/src/service/notifier.ts | 14 +- .../packages/backend/src/service/session.ts | 6 +- .../packages/backend/tests/.env.test | 1 + 4 files changed, 331 insertions(+), 285 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts index adea68b..71bb21a 100644 --- a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts @@ -1,84 +1,108 @@ -import { CONFIG } from "../config.js"; +import { CONFIG } from '../config.js'; import WebSocket from 'ws'; -import { EventEmitter } from 'events'; - +import { EventEmitter } from 'node:events'; interface ConversationInitiationMetadataEvent { - conversation_id: string; - agent_output_audio_format: string; - user_input_audio_format: string; + conversation_id: string; + agent_output_audio_format: string; + user_input_audio_format: string; +} + +interface ElevenLabsMessage { + type: string; + conversation_initiation_metadata_event?: ConversationInitiationMetadataEvent; + agent_response_event?: { + agent_response?: string; + }; + user_transcription_event?: { + user_transcript?: string; + }; + audio_event?: unknown; + interruption_event?: unknown; + ping_event?: { + event_id?: string; + }; + vad_score_event?: unknown; + tentative_agent_response_internal_event?: unknown; + client_tool_call?: unknown; } interface ConversationConfig { - agent_prompt?: string; - first_message?: string; - language?: string; - voice_id?: string; - [key: string]: any; + agent_prompt?: string; + first_message?: string; + language?: string; + voice_id?: string; + [key: string]: unknown; } interface AgentCreateRequest { - conversation_config: ConversationConfig; - platform_settings?: { - [key: string]: any; - }; - name?: string; - tags?: string[]; + conversation_config: ConversationConfig; + platform_settings?: { + [key: string]: unknown; + }; + name?: string; + tags?: string[]; } export interface AgentId { - agent_id: string; + agent_id: string; } class ElevenLabs { - private apiKey: string; - private baseUrl: string = 'https://api.elevenlabs.io'; - - constructor(apiKey: string) { - this.apiKey = apiKey; - } - - async createAgent( - conversationConfig: ConversationConfig, - options?: { - name?: string; - tags?: string[]; - platformSettings?: { [key: string]: any }; - } - ): Promise { - try { - const requestBody: AgentCreateRequest = { - conversation_config: conversationConfig, - ...(options?.name && { name: options.name }), - ...(options?.tags && { tags: options.tags }), - ...(options?.platformSettings && { platform_settings: options.platformSettings }) - }; - - const response = await fetch(`${this.baseUrl}/v1/convai/agents/create`, { - method: 'POST', - headers: { - 'xi-api-key': this.apiKey, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(requestBody) - }); - - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`ElevenLabs API error: ${response.status} ${response.statusText} - ${errorText}`); - } - - return await response.json() as AgentId; - } catch (error) { - throw new Error(`Failed to create ElevenLabs agent: ${error instanceof Error ? error.message : 'Unknown error'}`); - } - } + private apiKey: string; + private baseUrl: string = 'https://api.elevenlabs.io'; + + constructor(apiKey: string) { + this.apiKey = apiKey; + } + + async createAgent( + conversationConfig: ConversationConfig, + options?: { + name?: string; + tags?: string[]; + platformSettings?: { [key: string]: unknown }; + }, + ): Promise { + try { + const requestBody: AgentCreateRequest = { + conversation_config: conversationConfig, + ...(options?.name && { name: options.name }), + ...(options?.tags && { tags: options.tags }), + ...(options?.platformSettings && { + platform_settings: options.platformSettings, + }), + }; + + const response = await fetch(`${this.baseUrl}/v1/convai/agents/create`, { + method: 'POST', + headers: { + 'xi-api-key': this.apiKey, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `ElevenLabs API error: ${response.status} ${response.statusText} - ${errorText}`, + ); + } + + return (await response.json()) as AgentId; + } catch (error) { + throw new Error( + `Failed to create ElevenLabs agent: ${error instanceof Error ? error.message : 'Unknown error'}`, + ); + } + } } /** * WebSocket-based conversation with ElevenLabs for real-time audio streaming * https://elevenlabs.io/docs/agents-platform/api-reference/agents-platform/websocket - * + * * Events emitted: * - 'ready': ({ conversationId, audioFormat, inputFormat }) - When conversation is ready * - 'agentResponse': (AgentResponseEvent) - Text response from agent @@ -91,222 +115,239 @@ class ElevenLabs { * - 'disconnected': ({ code, reason }) - When WebSocket disconnects */ export class ElevenLabsConversation extends EventEmitter { - private ws: WebSocket | null = null; - private conversationId: string | null = null; - private isConnected = false; - private audioFormat: string | null = null; - private inputFormat: string | null = null; - - constructor( - private agentId: string, - private apiKey: string, - private baseUrl: string = 'wss://api.elevenlabs.io' - ) { - super(); - } - - /** - * Start a conversation session with the ElevenLabs agent - */ - async connect(): Promise { - return new Promise((resolve, reject) => { - try { - const wsUrl = `${this.baseUrl}/v1/convai/conversation?agent_id=${this.agentId}`; - - this.ws = new WebSocket(wsUrl, { - headers: { - 'xi-api-key': this.apiKey, - 'User-Agent': 'Deep-Sea-Stories-Backend/1.0.0', - }, - }); - - this.ws.on('open', () => { - console.log('Connected to ElevenLabs WebSocket'); - this.isConnected = true; - - this.sendMessage({ - type: 'conversation_initiation_client_data', - conversation_config_override: {} - }); - - resolve(); - }); - - this.ws.on('message', (data: Buffer) => { - try { - const message = JSON.parse(data.toString()); - this.handleMessage(message); - } catch (error) { - console.error('Failed to parse WebSocket message:', error); - } - }); - - this.ws.on('close', (code: number, reason: Buffer) => { - console.log(`ElevenLabs WebSocket connection closed: ${code} - ${reason.toString()}`); - this.isConnected = false; - this.emit('disconnected', { code, reason: reason.toString() }); - }); - - this.ws.on('error', (error) => { - console.error('ElevenLabs WebSocket error:', error); - this.isConnected = false; - reject(error); - }); - - } catch (error) { - reject(error); - } - }); - } - - /** - * Send raw audio data to ElevenLabs - * @param audioBuffer Raw audio data as Buffer - */ - sendAudio(audioBuffer: Buffer): void { - if (!this.isConnected || !this.ws) { - console.warn('Cannot send audio: WebSocket not connected'); - return; - } - - try { - const audioBase64 = audioBuffer.toString('base64'); - - this.sendMessage({ - user_audio_chunk: audioBase64 - }); - } catch (error) { - console.error('Failed to send audio to ElevenLabs:', error); - } - } - - sendUserMessage(text: string): void { - this.sendMessage({ - type: 'user_message', - text: text - }); - } - - sendContextualUpdate(text: string): void { - this.sendMessage({ - type: 'contextual_update', - text: text - }); - } - - sendUserActivity(): void { - this.sendMessage({ - type: 'user_activity' - }); - } - - sendClientToolResult(toolCallId: string, result: string, isError: boolean = false): void { - this.sendMessage({ - type: 'client_tool_result', - tool_call_id: toolCallId, - result: result, - is_error: isError - }); - } - - async disconnect(): Promise { - if (this.ws) { - this.isConnected = false; - this.ws.close(); - this.ws = null; - } - } - - isSessionActive(): boolean { - return this.isConnected && this.ws?.readyState === WebSocket.OPEN; - } - - private sendMessage(message: any): void { - if (this.ws && this.ws.readyState === WebSocket.OPEN) { - this.ws.send(JSON.stringify(message)); - } - } - - private handleMessage(message: any): void { - switch (message.type) { - case 'conversation_initiation_metadata': - const metadata: ConversationInitiationMetadataEvent = message.conversation_initiation_metadata_event; - this.conversationId = metadata?.conversation_id; - this.audioFormat = metadata?.agent_output_audio_format; - this.inputFormat = metadata?.user_input_audio_format; - console.log('Conversation initiated:', { - conversationId: this.conversationId, - audioFormat: this.audioFormat, - inputFormat: this.inputFormat - }); - this.emit('ready', { - conversationId: this.conversationId, - audioFormat: this.audioFormat, - inputFormat: this.inputFormat - }); - break; - - case 'agent_response': - console.log('Agent response:', message.agent_response_event?.agent_response); - this.emit('agentResponse', message.agent_response_event); - break; - - case 'user_transcript': - console.log('User transcript:', message.user_transcription_event?.user_transcript); - this.emit('userTranscript', message.user_transcription_event); - break; - - case 'audio': - this.emit('agentAudio', message.audio_event); - break; - - case 'interruption': - console.log('Conversation interrupted'); - this.emit('interruption', message.interruption_event); - break; - - case 'ping': - console.log('Received ping, sending pong'); - this.sendMessage({ - type: 'pong', - event_id: message.ping_event?.event_id - }); - break; - - case 'vad_score': - this.emit('vadScore', message.vad_score_event); - break; - - case 'internal_tentative_agent_response': - this.emit('tentativeResponse', message.tentative_agent_response_internal_event); - break; - - case 'client_tool_call': - console.log('Client tool call:', message.client_tool_call); - this.emit('clientToolCall', message.client_tool_call); - break; - - case 'contextual_update': - this.emit('contextualUpdate', message); - break; - - default: - console.log('Received unknown message type:', message.type); - this.emit('message', message); - } - } - - getConversationId(): string | null { - return this.conversationId; - } - - getAudioFormat(): string | null { - return this.audioFormat; - } - - getInputFormat(): string | null { - return this.inputFormat; - } + private ws: WebSocket | null = null; + private conversationId: string | null = null; + private isConnected = false; + private audioFormat: string | null = null; + private inputFormat: string | null = null; + + constructor( + private agentId: string, + private apiKey: string, + private baseUrl: string = 'wss://api.elevenlabs.io', + ) { + super(); + } + + /** + * Start a conversation session with the ElevenLabs agent + */ + async connect(): Promise { + return new Promise((resolve, reject) => { + try { + const wsUrl = `${this.baseUrl}/v1/convai/conversation?agent_id=${this.agentId}`; + + this.ws = new WebSocket(wsUrl, { + headers: { + 'xi-api-key': this.apiKey, + 'User-Agent': 'Deep-Sea-Stories-Backend/1.0.0', + }, + }); + + this.ws.on('open', () => { + console.log('Connected to ElevenLabs WebSocket'); + this.isConnected = true; + + this.sendMessage({ + type: 'conversation_initiation_client_data', + conversation_config_override: {}, + }); + + resolve(); + }); + + this.ws.on('message', (data: Buffer) => { + try { + const message = JSON.parse(data.toString()); + this.handleMessage(message); + } catch (error) { + console.error('Failed to parse WebSocket message:', error); + } + }); + + this.ws.on('close', (code: number, reason: Buffer) => { + console.log( + `ElevenLabs WebSocket connection closed: ${code} - ${reason.toString()}`, + ); + this.isConnected = false; + this.emit('disconnected', { code, reason: reason.toString() }); + }); + + this.ws.on('error', (error) => { + console.error('ElevenLabs WebSocket error:', error); + this.isConnected = false; + reject(error); + }); + } catch (error) { + reject(error); + } + }); + } + + /** + * Send raw audio data to ElevenLabs + * @param audioBuffer Raw audio data as Buffer + */ + sendAudio(audioBuffer: Buffer): void { + if (!this.isConnected || !this.ws) { + console.warn('Cannot send audio: WebSocket not connected'); + return; + } + + try { + const audioBase64 = audioBuffer.toString('base64'); + + this.sendMessage({ + user_audio_chunk: audioBase64, + }); + } catch (error) { + console.error('Failed to send audio to ElevenLabs:', error); + } + } + + sendUserMessage(text: string): void { + this.sendMessage({ + type: 'user_message', + text: text, + }); + } + + sendContextualUpdate(text: string): void { + this.sendMessage({ + type: 'contextual_update', + text: text, + }); + } + + sendUserActivity(): void { + this.sendMessage({ + type: 'user_activity', + }); + } + + sendClientToolResult( + toolCallId: string, + result: string, + isError: boolean = false, + ): void { + this.sendMessage({ + type: 'client_tool_result', + tool_call_id: toolCallId, + result: result, + is_error: isError, + }); + } + + async disconnect(): Promise { + if (this.ws) { + this.isConnected = false; + this.ws.close(); + this.ws = null; + } + } + + isSessionActive(): boolean { + return this.isConnected && this.ws?.readyState === WebSocket.OPEN; + } + + private sendMessage(message: Record): void { + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(message)); + } + } + + private handleMessage(message: ElevenLabsMessage): void { + switch (message.type) { + case 'conversation_initiation_metadata': { + const metadata = message.conversation_initiation_metadata_event; + if (metadata) { + this.conversationId = metadata.conversation_id; + this.audioFormat = metadata.agent_output_audio_format; + this.inputFormat = metadata.user_input_audio_format; + console.log('Conversation initiated:', { + conversationId: this.conversationId, + audioFormat: this.audioFormat, + inputFormat: this.inputFormat, + }); + this.emit('ready', { + conversationId: this.conversationId, + audioFormat: this.audioFormat, + inputFormat: this.inputFormat, + }); + } + break; + } + + case 'agent_response': + console.log( + 'Agent response:', + message.agent_response_event?.agent_response, + ); + this.emit('agentResponse', message.agent_response_event); + break; + + case 'user_transcript': + console.log( + 'User transcript:', + message.user_transcription_event?.user_transcript, + ); + this.emit('userTranscript', message.user_transcription_event); + break; + + case 'audio': + this.emit('agentAudio', message.audio_event); + break; + + case 'interruption': + console.log('Conversation interrupted'); + this.emit('interruption', message.interruption_event); + break; + + case 'ping': + console.log('Received ping, sending pong'); + this.sendMessage({ + type: 'pong', + event_id: message.ping_event?.event_id, + }); + break; + + case 'vad_score': + this.emit('vadScore', message.vad_score_event); + break; + + case 'internal_tentative_agent_response': + this.emit( + 'tentativeResponse', + message.tentative_agent_response_internal_event, + ); + break; + + case 'client_tool_call': + console.log('Client tool call:', message.client_tool_call); + this.emit('clientToolCall', message.client_tool_call); + break; + + case 'contextual_update': + this.emit('contextualUpdate', message); + break; + + default: + console.log('Received unknown message type:', message.type); + this.emit('message', message); + } + } + + getConversationId(): string | null { + return this.conversationId; + } + + getAudioFormat(): string | null { + return this.audioFormat; + } + + getInputFormat(): string | null { + return this.inputFormat; + } } export const elevenLabs = new ElevenLabs(CONFIG.ELEVENLABS_API_KEY); diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 44f7e63..35d30ac 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -32,7 +32,7 @@ class NotifierService { this.notifier.on('peerConnected', async (msg) => { console.log(`Peer connected: ${msg.peerId} in room ${msg.roomId}`); - if ( !roomService.getPeers(msg.roomId).find( p => p.id === msg.peerId ) ) { + if (!roomService.getPeers(msg.roomId).find((p) => p.id === msg.peerId)) { return; } @@ -41,20 +41,24 @@ class NotifierService { const fishjam_agent = roomService.getAgent(msg.roomId); fishjam_agent?.on('trackData', (msg) => { - const {data, peerId} = msg; + const { data, peerId } = msg; const session = sessionManager?.getSession(peerId); if (session && data) { - console.log(`Sending ${data.byteLength} bytes of audio data to ElevenLabs for peer ${peerId}`); + console.log( + `Sending ${data.byteLength} bytes of audio data to ElevenLabs for peer ${peerId}`, + ); try { const audioBuffer = Buffer.from(data); session.sendAudio(audioBuffer); } catch (error) { - console.error(`Error sending audio to ElevenLabs for peer ${peerId}:`, error); + console.error( + `Error sending audio to ElevenLabs for peer ${peerId}:`, + error, + ); } } - }); }); diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index 18d5601..75eb83f 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -22,13 +22,13 @@ export class SessionManager { const agentId = await elevenLabs.createAgent({ agent_prompt: instructions, - first_message: "Welcome to the deep sea stories!", - language: "en" + first_message: 'Welcome to the deep sea stories!', + language: 'en', }); const session = new ElevenLabsConversation( agentId.agent_id, - CONFIG.ELEVENLABS_API_KEY + CONFIG.ELEVENLABS_API_KEY, ); await session.connect(); diff --git a/deep-sea-stories/packages/backend/tests/.env.test b/deep-sea-stories/packages/backend/tests/.env.test index 99b091b..5474b3c 100644 --- a/deep-sea-stories/packages/backend/tests/.env.test +++ b/deep-sea-stories/packages/backend/tests/.env.test @@ -2,4 +2,5 @@ FISHJAM_ID=test-fishjam-id FISHJAM_MANAGEMENT_TOKEN=test-management-token FISHJAM_URL=https://test.fishjam.cloud +ELEVENLABS_API_KEY=test-elevenlabs-api-key PORT=8001 \ No newline at end of file From 67c2b296784396eae888e9e24eae2fba896f728f Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 7 Oct 2025 19:04:59 +0200 Subject: [PATCH 27/65] Basic UI --- deep-sea-stories/packages/web/package.json | 10 +- deep-sea-stories/packages/web/src/App.tsx | 11 - deep-sea-stories/packages/web/src/Layout.tsx | 13 + .../packages/web/src/assets/blob.png | Bin 0 -> 295427 bytes .../packages/web/src/assets/elevenlabs.svg | 4 + .../packages/web/src/assets/fishjam.svg | 5 + .../web/src/assets/fonts/JuneExptCurious.otf | Bin 0 -> 131124 bytes .../packages/web/src/assets/github.svg | 4 + .../web/src/components/AgentPanel.tsx | 93 +++ .../web/src/components/CopyButton.tsx | 33 + .../web/src/components/DeviceSelect.tsx | 54 ++ .../packages/web/src/components/Footer.tsx | 31 + .../web/src/components/HowItWorks.tsx | 47 ++ .../packages/web/src/components/HowToPlay.tsx | 47 ++ .../packages/web/src/components/Icon.tsx | 12 + .../web/src/components/LinkButton.tsx | 21 + .../packages/web/src/components/PeerTile.tsx | 44 ++ .../web/src/components/RoomControls.tsx | 41 ++ .../packages/web/src/components/TitleBar.tsx | 14 + .../packages/web/src/components/ui/button.tsx | 19 +- .../packages/web/src/components/ui/dialog.tsx | 120 +++ .../packages/web/src/components/ui/input.tsx | 22 + .../packages/web/src/components/ui/label.tsx | 24 + .../web/src/components/ui/scroll-area.tsx | 46 ++ .../packages/web/src/components/ui/select.tsx | 158 ++++ .../packages/web/src/components/ui/sonner.tsx | 49 ++ deep-sea-stories/packages/web/src/index.css | 59 +- .../packages/web/src/lib/utils.ts | 13 + deep-sea-stories/packages/web/src/main.tsx | 14 +- .../packages/web/src/views/GameView.tsx | 42 ++ .../packages/web/src/views/HomeView.tsx | 18 + .../packages/web/src/views/JoinView.tsx | 88 +++ .../packages/web/src/views/RoomView.tsx | 12 + deep-sea-stories/yarn.lock | 688 +++++++++++++++++- 34 files changed, 1804 insertions(+), 52 deletions(-) delete mode 100644 deep-sea-stories/packages/web/src/App.tsx create mode 100644 deep-sea-stories/packages/web/src/Layout.tsx create mode 100644 deep-sea-stories/packages/web/src/assets/blob.png create mode 100644 deep-sea-stories/packages/web/src/assets/elevenlabs.svg create mode 100644 deep-sea-stories/packages/web/src/assets/fishjam.svg create mode 100644 deep-sea-stories/packages/web/src/assets/fonts/JuneExptCurious.otf create mode 100644 deep-sea-stories/packages/web/src/assets/github.svg create mode 100644 deep-sea-stories/packages/web/src/components/AgentPanel.tsx create mode 100644 deep-sea-stories/packages/web/src/components/CopyButton.tsx create mode 100644 deep-sea-stories/packages/web/src/components/DeviceSelect.tsx create mode 100644 deep-sea-stories/packages/web/src/components/Footer.tsx create mode 100644 deep-sea-stories/packages/web/src/components/HowItWorks.tsx create mode 100644 deep-sea-stories/packages/web/src/components/HowToPlay.tsx create mode 100644 deep-sea-stories/packages/web/src/components/Icon.tsx create mode 100644 deep-sea-stories/packages/web/src/components/LinkButton.tsx create mode 100644 deep-sea-stories/packages/web/src/components/PeerTile.tsx create mode 100644 deep-sea-stories/packages/web/src/components/RoomControls.tsx create mode 100644 deep-sea-stories/packages/web/src/components/TitleBar.tsx create mode 100644 deep-sea-stories/packages/web/src/components/ui/dialog.tsx create mode 100644 deep-sea-stories/packages/web/src/components/ui/input.tsx create mode 100644 deep-sea-stories/packages/web/src/components/ui/label.tsx create mode 100644 deep-sea-stories/packages/web/src/components/ui/scroll-area.tsx create mode 100644 deep-sea-stories/packages/web/src/components/ui/select.tsx create mode 100644 deep-sea-stories/packages/web/src/components/ui/sonner.tsx create mode 100644 deep-sea-stories/packages/web/src/views/GameView.tsx create mode 100644 deep-sea-stories/packages/web/src/views/HomeView.tsx create mode 100644 deep-sea-stories/packages/web/src/views/JoinView.tsx create mode 100644 deep-sea-stories/packages/web/src/views/RoomView.tsx diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index cb92638..1f7aa2a 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -6,10 +6,15 @@ "scripts": { "start": "vite", "build": "tsc -b && vite build", - "preview": "vite preview" + "preview": "vite preview", + "typecheck": "tsc --noEmit" }, "dependencies": { "@fishjam-cloud/react-client": "^0.20.0", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", "@tailwindcss/vite": "^4.1.13", "@tanstack/react-query": "^5.90.2", @@ -20,8 +25,11 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.544.0", + "next-themes": "^0.4.6", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router": "^7.9.3", + "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.13" }, diff --git a/deep-sea-stories/packages/web/src/App.tsx b/deep-sea-stories/packages/web/src/App.tsx deleted file mode 100644 index 32767de..0000000 --- a/deep-sea-stories/packages/web/src/App.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import angler from './assets/angler.webp'; - -function App() { - return ( -
- angler -
- ); -} - -export default App; diff --git a/deep-sea-stories/packages/web/src/Layout.tsx b/deep-sea-stories/packages/web/src/Layout.tsx new file mode 100644 index 0000000..c124bde --- /dev/null +++ b/deep-sea-stories/packages/web/src/Layout.tsx @@ -0,0 +1,13 @@ +import type { FC, PropsWithChildren } from 'react'; +import { Toaster } from '@/components/ui/sonner'; + +const Layout: FC = (props) => { + return ( +
+ {props.children} + +
+ ); +}; + +export default Layout; diff --git a/deep-sea-stories/packages/web/src/assets/blob.png b/deep-sea-stories/packages/web/src/assets/blob.png new file mode 100644 index 0000000000000000000000000000000000000000..92273d4db1cef3894a6da02d7f9852b10c936d1a GIT binary patch literal 295427 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
OABQu;;_Nt_fGNBjQj&hbX|%z$uk@eAEj zg~#Kr%ipK{>MhA>L}2jD2Z$$q%=04|_nW&4 zjiD%*d=gJOb4ryM-1=9RtB?CP|EX51fyRoP%pqKCb@;gAHVa8R@%ubJ<&B`S z!S&cACML$3l}tf?{>&v2!R#*O12V&p{7g|6+!!kxb%Sk%d%}~^@RqWHm4tThQgKC* zhF0Fcg=UN84S$(_(3i()4pSyjW(YQ=^UJAX0Nhr7GUM>hFQC}H3p+Eni90u#VDM)2 z%;n{_@^CjI)aFu^Qva@?qkM~9W^G*Eh}q&h40{VvVgDxPx)H>-X@Uy&+) zVwtAOWUEYm_X_exGtyW7OAWiW zNF>qInu;PDsNh(ewd_{w3MkwdT+&pR`z{sesE^7ZEzK+M@X7j%T}uC0BKfn;&Fsvo z_gC!Qq;kQKHko(XzvR`Q9HGdPO172~j}=PFlD*ExvTByRcR`aPn^f>ms#UL<=Lf2h zp%b)`2fV>D!Opl!AYk4xm!52*rps^7!I%lM;ss@1%;`_^6T_+GKeKom*vAYTby$>4 zEbpy_>Ti=m7?_){y2Wf-*jrkUHLl*NX?f_ch?rc31=D(N%sj^(Oo+Y6?f>GJWBks@ z^&|fICJtxHcHClNk!5n@2B0`t)%ezBwgc$7=_l3F5De^vcb)c{8XA{`Z`2fAKzQz6PdA~I$08*t9MBIpS>SGZ!P@5w zOmE&l%Fotj3uOv8%-0_5-*Kj@S1BWJsHiDzt#}Q%=;hL;J`?X+juySkbm2t%owYan zvhAvOjNKv7(Dsk&#LtFxrM>eDsA@8gyl$wLd;{p3S%FtkS>wRHlXa{Hh~)HvHssAQ zqZNs9n~NL{w!2)y_y^96#5R*fN~s59O=I!b7sOl|+edL#h&lrAVl3w(+l0>>h ztTO4u{zIl{+_3W&5B~|KDmxr(+(pORBxrCUN#v8Pr;JoOK!xvxYG_cMyI#6P$ z7Z}Gc*#@J2yuZZu+oy;VR3Lv$Mk`jOl5!R|`75mDKRj{onmjSy#!vRSJfQ1lr}1T> z%OItaazEWB%3x)DO?6;dhwDavEPwzcFW0thkwX_Ol+*F&foYpT*lW$=-hgs zv011jTu{%+DGo6OA38${$?7x|j|1qJxFIL|+NlBUgyVlJ!d0cP9+CNOBgm z#g-K-6J8p=n(_n>%4$j+%$9e}f@zFY4L@GuES_hw`Bi?0rOG#&;zYX5yg;0MQMfj2 zed!F1V4DBsPh|SzyBpu7e=;okIE&kZkg|d5$=mT?ua|Zp)D;m|nTdp=iM};+i zkNq#CCQla(xt?+N?EKL3 zTTCDWF9qW?q!h(|&^BOZ=AVJamH*OCZ3QQZUP|2Hp8s2hVtK~uUwih*WMJ;>&O;T8 zdM6Ll1hW!Kmr^Y@$@f`p`9O=LWLyX`@L!?_jbZ6^-9Kyz^pt|Sldf%&C=aU=U~ zhB0!86W!$TIkD-Tgx|hYp)N~?Ds_B({N?fSb~zp0f&0YATH^Q2g5B&}BqCiYu2Q)Z zQ149TqK4cHy>#)Z$>&z083I+}($SVXovLxG*Z*M(QSC{71k!dL7t(IbjYa-4H_^P6 z`V*h*r;o&b^;Cx&Y0Uy7nS%ZPbFtUxnfx~`V~p_wbLtY68(*xND&7wT3da0o3WA9= zUz44od5nPI1_{l{AlWyO=Op7!!XRmdepE-*J)oCX9r9Bv4@TK(tZm+E83MT;KJZ^?_gOpNuM=SpG@#%dN`)LM~n}3cjWi#5P zL%1RJzXYnkV`umdI#^aghLpXxt=Pg*n2uqVyk@w4Y|H0r(zZjy8LWz*B*)Li=smO( zGQ@dMTtBl0jVcez;mHH9)Hf-gl1P@-IzrVh3Z@u@>A&l^QImu7cm|JNXiZ_>_&wn% z^!W#WlFPL*{mk;ksH@;@mVx2>O>Fn0Q&Cv7=^MNRZ4regUI-nlKLFdMwaif6T^l412&2Sm+{r+&&TrIb6(w9MS9hJ!}?~E?G@m z*SXwwM;v5|UkTQ^__Q9tJ-R2y#>N1A$tYSH+AMhk(IdiqV4k&ZcK@9;L2=7O%nbbX z)e;hBOeRW_H!#un@em*53Hax>!&t4oWe=_2c*vm1g5mAwM+$@1<&CR31H?=0)5VSl zesBAIqE1!n$1l0KW6AhxT;)W)Nn&Albk5R|7B+dQKv|}3WP{|+@DTpa2e^Fr#8{X6 zQCzUVr87VJ@#Dr%4NB(q&t)(pn@sH~ZtK;?HrsZi&$lB-iE~?a!eR!JBTd}40(yhyEPBXnyYCooxzBoaG#_*KUu)5}yF6G5F-}@M zOj^vUTU>N(X-U2Ir>;z^OG*uEu+0A$$r!0PSJ$z&HY$0&{G-M10@3vci;kZD;Kb|H zzr1FiEl)L!r{`027x`S$JdZ_5a?pICOS#(27?cLUmnb=$*e2V;-q_|&5RRtzp=~4? z!(hgIu9eib9_6QE3uOws=&%aCau^3@lDx$ZCd-F$v3?jGGOEz;eMbf*j$Ae}>M(l1|s|Mz0I zyE;32K2IIw7J*ArjRn4T2-Zh$0++Qs#Y?}8U@hqaIm$4FUFm_aeN)$m=)h(2NT8+{ z!|ZFWn%89w&))Hg+04#U+043^u~?LnPX7|xui$kOM|-fH}Rv#QsR_wYQch^EY& z=;CV1?j!g0^lka>uqQ|tbl%jOhy({@rU5yU3br^SO8W22IGrl{Dh{ai zYk&sXE^(AxFWiFq)g6_50D+UfLf}eA{pAY@D|o^!QVUBlCnATdbM**ia9PcFwW;1A z9p$I)B<3f|!(Z_iDBm4*$*~E;zVU+gLUY@hfEvDFH4UM;*6$9Tf3e33{iKw>tlJ30DuUdsU8|x1>h<|`y*k6@kBLh_`xXZkwqc)m zaw}rmbq|01$f>TjQTWUG`pxP~Y&C1Y^hOb1z3i!K^CyWZ4>!5TW9d6G|DE7G@27VA z!H0j~LF#X>*!`Zu*w0LkP7!!#=ko=3$z36Wn_ZGWUsr|%6H{eZ5NEbz!>G?xH$4K=X}4eg*r-O68dMUYgT4 z$BAiUZ4R1m7QbZe@uaC4>Y1%JFXjvQ8Z2K2X1Vns(3~07>WmJlEKnOw69L_HCN-t8 zhNzmEV7|>2382rc$h-Dw)9GNya{oICf1%z~OWA<5LgX3+ZI;m%fq$?;|1Akev25Au$~+_FDjFd7$rPwv2nw zlzlBg2w>N{pc)*(MMV~{-k#0vJxdN|~z`hNbfE*loB0pB+sB^ICf5sZv$ z&}RC`U+1ThyPNh$mgeO9YU2NG+&;XAS~%ZO>f$X~G)JCxTE9g*VqKU+sg-DxpjT$w-P50tue(HNS4_(cKcl$xzIg=LzH6R`-;xuRG=G>JbT(QQgiC8 zmVNcUJk%2G6c3EAVH8wy+4m6koGPvRHgPieYee#-tz+#JgPG_^&KVym9}fJfbRVK9xP+} zoir>h;u9+X*^o zYJuo}BM*{ilK?xF#fPMv^B6t)bCT@5@3Ycz+TUHD?SC{&v>{P&P8hWOq4_Afe*N(1G3pAq7!U#7x4^Ie9wuz{ z7m5jso}V4|QczOdZ#r)MX<7cmPvY%SQuIYq_0gWLmjTW*!hni7f&pI5Ut;h?ATUyY zaz$U%nnt}0&hVR3yrNrwgL^bu2dhoJ@PWK_-umldyn<25*TGf<1ddGh6b4%1kx?`5 zc{=yM(@|owQ9!!GyjHwh3z+lLXjmsUw1i~{{cab6(tbqgnQ-J8s*~Zf;t_Q<*|Y2b z&T4ej5tCmV9k&M&rXRLP51KG}`Okd06c~G#bgXLd&Rg|O501sGPU5_Ta~hV@=+Vt0 zc|4I6^M&R=$Re9NrNw zIn9Q_)#IsgfeMyNz7myR-WorAurgt!Inr<^LXUS+t4tu`em)ks&?pio#dH zT`8X`^u77MOcy?wJU603;2rPKOd>ffRLvl_-@eQGAu3#pnTSpt^kMRq{C@G;#2({2 z(ut7Ftnzb4S4CUj8;hGd`X8l?Rb|vNyLZ{|O*fcch5#ktE|uT6yE6O-+5DHNZKuZ7 zwEwrh{awMQ|6~yB!1j!GS9hHNo(a524lFyi+BH`2u?N)CNBGZ~!}(A+5gs0+kZAV( zAIIlutgB_@nnn2H(?;a;Or~+4VW)LEOx^MV4=PzyyQ{Frpjv|OzeRNB@C_cNbT(5o zJSo~^cXE*9x>t<7g??Rn)w{;)v|?7X=ylh`dN>cEa!}4J(=B@d^>7K85do9I8}Y3K zB|S(PiE|Rt9XGmm8Xb89BZ9kE#vx?WnUFiH{ftky@v!$Xdh1>Ev-I!Xyr?;%D(YQe6=U+cE8 zj^nrUk8?YE>GwD8iNfZz($l-?@~TkYK(z7lifr{kNA~Wk!|mVUKa0Fd)gsyYoo-O2 zsU|MyCtPAJ=?89-(rPF^;%m+o$OHV!{=(sIj zdfDU5l9=o@{@2=W}tSC8;h>@iiz=&S|;WI(~`w~M|zo|o_Cp5 zGi2f)3L^Y9bfB+1=2{lGX2v(n7dnXi4j^2=|lgz620a-J-eKByc;>S_m|YAL1WvjziVMvk47hb~6& zm4jqHVjWBWeg#Z0f|JlnTu7Lq#amL~l<~}8@%VTkk*f9mEc?7;ExWF~lD?DHBpIf4 z7bLZ~{+^$OUd-y0BB5n@c2!Ji*WV`Q`X`cx*4Fqj$t&bF)ytLGD z!@W=Bw{ix44H~YvbM{-NV`L=b9CAhhJ9M4-CW4MB0 z3JMD;(fsL`cwk@c6EJk zwYG7&S+oqCjSQ?qtYbfy@c@6MImw*ZU?>Qe=H|ag@3EXDnQRgdvGkphXBT{_OUFAd zT7~Y*K6L?BgR5$H--bm-y9l!M#e6b2Ey&0(`9k@1)+d&Y$VtvtgmXw#mbp`{?*0RY zZ@aj2XZ6cTh1I<4F*9{;_p)C>?IvL`($LMNqn zLvyt!CiW43+FOnIb7i$r)$%$(=wgBjn(pWO*P_7KyfyN=4;L;jLCU`H2b& zw^8zQ;$rXg^b-M`a22>+;)Z0sUwV*}pd0@KOlg{IdITp1n| zo}8-317yZ=ut>4OU>sq->aWF%QZX&__>%&4^bdyJcn`tFbPC~pS}iHU2?^NRMCr~* zpKD7nIbW70yRTr1h*5HK(yieXmWX$s6mSoJ7F8xp57{YNIp(FAQb7+T+HU0|`(a^e zXWaAYXBa?V0xt79mMs{Q880D_DEu7vuccRm z>@ntP!QXNhHgU{uq}XvndpA6T5MObB1{yZc)btncr{HJ!L4NYLr8ck6qzG`EaO_=Y zn~!sW4v~8`#e)8B&&qLm`+iN^L@&nG6*qjcjn`{##{TG?iIM8`GMrs5fW zu#%|lO29Ej){193f`z*H#$81_5lRNHp>@BjCY*jI867~MqnnB-$RkQ%AVMHOL8^X2 zvrVZ{Ah)4`gL$n$FLrnh;WTW)6X}v?)!_{cs&tH1&nojFMW~f1)AFM1!bHEzwj>(x z-Z}TnQ5d)xcMF%qAeTpW3^OSRs<6nHS#$+oc`YB$l74az8>RBr*)og|T@wP#9eXBo`>$WOO>Td+HgMs; zoTmHr>h0_{=X5%|Evgfp=|P`c?Zy}Q598jiqVuMP9&{33W#~q4T=p75#ajp-ixpuT z8c2NokLXXup_I2K>-LMu(z}ZlJUU)S_G{HsqVC=E;uPG@DHA%2ym zSXpc~!G&UH+5tnbS1QVelAOQk!VYWVVkc`;rc;pclX6SScr2r52WZe&nv6)~n@8(W z9B537N&__>Mz-5;%nkyWZF*K4{6q-(3LBN`r5kc=lMwklIrE}Z&aXZ^JJq-2;)4ja zY!*H++;X2P8tkpdmLbW8xX?rxl>QPjy2JV|3PQ|}RAEuH}LgNGx zMO*nyz1~f%dB;4_KmLQMR~)@7VY4WdPG408PDKLw%AMHIW2I4@k<8P`TiccFO9F@q z?trKicHFo1guc9R4{#`iwg#1Q&$WQA9>a|!GmWN5eU5@25Ht^O67R8};AsYbGuE%~ zCuA%BCvE=-Zr5_w$-L`q6&u^OGo`pDcxbTj_8@tPhIgJL*8R^A2BOdd$BSAFuG#CY z4G+>|ZxBk}%&l)XOc?$Hyv17hUb+gRqxr_-AO;p=mXOe0mD7F~YId;tR{a!?C+zJw zWy6tM&&pDH-Ls6yQ7BBQ7ga;AY!34t^5&$GsUIEHvFuFBA8#qTMBbi$Gdig2wB*fV z;USPQS1fO8k}`_?y?gOiz$ts82I^Ye$e z)6X=b#TY~#wpv$k@oBqpQS8fGA!+ zc-v)nVOq^Z_z0r!b?j}23URmGBnFb)0~txCI?%a z@9)chT6Q=0nS}r4-K3p{^U&Iaj=MX2;-Tj9DyO}FGYjvietmbh+ZFNverBGf2U?<6 z;jt@Q7aFB$h`6DlCOBgp`8gI6#g1(bBtF16h^m*nH7z~6CC;dgx2Hkp!Bs8=TNyYI zk&*$F+k;YX)>(~GNfSy;ou=3=Wz}JPoF{NfKr8z!teSh@wCK)34aTwZ?U2>IvW3CFUYdgnLq#`X^}7xls8yL5SdVJC>aP6;9zP$dmrA?@*V$4 z7&p~Ym$npn_*K}#|7<5nx2Eh?;PEms(ZIWt(P`eLIKj4jKK*` zHJXanB_ezXxMt83?tn6U`{_u`_a-!L{pxgbz=>g}EnXhP#y;U(k*R z=?OO6f4b`o#`3hWFw!LAQ}h}c?tSh-`jxSGD~=#>gg}xhi~XIj;Lq~y+hdKTC{31g zsJE11R((ZIdwb|zd$3!ZnB_!gLbg&VOO80YFAb_n`vPOpj7H&AC`^zSotBu|EvbV{ z%L}E9$hs*8xRzHptS5A6Qgaea;-u{{SKB72RJ|}OaKH*hHptpn5yTF-gZxd)ZtVNX zk6oy`GA!v$oNUAQR=b_>1dt!` zL!WVf_?LGy@z{tu_rp9Mcp`@jc4MQcWDD<2sArlAqB(+IoE>g0e^EcWlE zHTl`|=ZV?H;oiV(@678d2Jf(kRzN3YWf)lyv$bZBfO??$|!p{IH=?zkqu%g;_(Q4dv z*)tJ|UyU1S3Bkq!eCVqm&*G<_AI>%5v2KodJ(%dh$ajO2-@;R|O#!RcORMq8xgW2% zg#t#n2()H`lU0#GZD1nzQcshRbYGho#V%Y<&)VK$fWrb8cs3}5fiWB_fG9LvMGaI; zD68`5^rTIg0X1LDenmv5y-Cw5nWiAcj~TyQ-Qe|J<%l5tWWe$eUkcDrUROXy)QncK zPy8AJ$Q<#U1NByYq{>v_-*RV9Y3U#h8Wf5=mk-Kig9Lbqa=6^gHdR|^$w^UDQy&BqXu4lm)GF}&EvbEEpL zChsCLep;gyKIz}IrUNW545S~Va)n=jYenm$roCn}V_h%MeH|AieAV|HnjPHzHykvz zmO?$NI)y;{?McYH?}w+?!+FP65F3UYdeVki((E=>M0`WS!}%4#bX)+Nu*TNSs;w%f z?$&xZwLlgK)&Vq+dF>REb`pgOO-Fpd0vEb-+^~KbRdAh}mrKdXlOHA|2fpLO$2klq zXTH#3qxZ5Cy^w^gJa;ay+sT#Zc_T^gFIz!=BnbFlkuf2M*?dnYo9JzOsqMU(i1G#z#F}2NL zAMSQOlMuW0HQ!aZSXbyt3~(uBRR3>t1~>FIqPc zvK{KT^0vJ5J5MP5`D+Bw*B3-5TN)yxUbL2gB+DSt)b=iHd+FJbLgDE}$ z+cJzT#;rM#s|SMPdBlgJ9&Ap|7C@zITa4jtM?QPT%_%d-^=>ydC5YhX@N@3@u8DRJ zwMBk@qIO&%wBub?3B3#_6aD1bVlMl183lMjma~;|T zj<6lEn{tlz75}k|C9#l^e{aqEdT};yXXkEr#M1b^RtXzzA0-9ix)&qvWM|86C0DeM zbv7FQn>L2akgVopL{u(z+eJyp{GuqyiaK&G5JEZPX6ZV4uWRs(P`X^a%mzff-KN&o z{nHCJ%oG{r2;NxoGrkN9A7*d-tqI*T}eVeyu6?qsgC)_-iv z?S6a9&&PHp4kJ5^K7&zgC!tqbQxnva_%%|%F8Aj!q~TVQi$^tR62QqySOIDHU8GIv z`g8BFi#$oXJo#Pm$rqiuX|U&}&Jn+U-y6D@rjmz3Go%9EH1reSZcOh>TE5e-@Gn+f z_WDhdSZ+9w3we5>1+%$_$y@z0;WW0u^E}St&=#^&wNzDoOQ_9|l{ml^tYlb1>#*zL zJUbji4&rIdkJFs!f@?C^;Z)bMHF3^ut?3<&F=sBE6<1g-{ng@?HpERh_xWgvGQq$` zpFN(4S!ugek8b_JH#@W@9|zT_3yVrBeEeKM!&*%BYteC8=YdN?fwAGJA17(#E{S1P zwQ{zkt(i5hxLxVk${F!Ik#5YHE@+G~klhuVd*1VAdjzlfoPNp=YaAwjll_w&V~{*@ zWGm^^4^EI5GY%&oS(mNMVaW>v{X@Z4^cOJ<}rxtL|^lXORhl9lK6 zae(KR3-njG=}s3sF$+t5?7{Tc5IqfU016SwY=%Oy_^h55W+$=^(2=N;g<6&7^Utu$ z@`|I|@w-oP`Xb;L^IBo*TvGm@$P(T#1}+!t7wvNXcB0G`6%wNxr9m54Xz_YjJh|{e z?1IL@$R@X>4B4pY3K*ftAA0oKepZ05FdqWU%9P4>qbY#Q4?i-yDEhMt!Sjl21Z*8F z-kY~K%hDxPw1Ij`F`iEyrpCV|ue79=);?@ne^xfnnAMr`Jy0k#K@$@S@+Us~8So%W z%l9|xpLMAl|5-7+^>yQQSYvUmYFxaXy*u|g8T**p<n z7XDi;C-%>VCjIQeGB{TQXc;oz8!?gi+cXtaM04M9y=wZtls5LWE;E5e77F=xB{BG2 zVT!Sm!7fzI3IQU);R70m<;1wuhfT9p-dK$>l-m@*MBfU-7si@pxHh$4F!~OP( z4W*U5V7FL_{L>Vg+>ml2w^@qhu9l})l*oL~UnzL{Zdf_>1mow@Q-hS1v>V}2FFxkX zbk9Q`RB$w=jrrQdx*n^)yy@c=vKZpY_X>8MmDl-L90B_uvw|dchVjHaLzbm%Y#%@jgwn&`*ROlaV(V9$46~OOKaK?8If}9r4#_d_73R#H zn$x=c)`+O%m9OR;(xtR* z+Do_D^HB)P*)g1d%X#t*v>pslGTzYM8 zigG-3*4#1bimo#vzBGr$V*&AVAu4rx)!Dh-=;aLaUBTPkDxnv-)*t(7wn;{&;x-sR z{!;#U7T>*Zy1t=-@*jE9{o@SdF~?s|1k8R2E*;-;7IN2Sn&3@u{vtEF%VnO zzAI|HE=%|mY1rYtO0n*Fb#{1_P&-{=PhdN>c@TNU9ZiQx;~o^)2n{d?Q<~J+GdiJZ z8rr3#vWYsqHq0h`4yG%>p)gsE5#%Kff$=XehL;+n- zA0133PPR0j%ukCoKFZ`)`O_&pBF2{Q+Sg>D$Ggz8aIeqM(C*kQJ`Qts=VnNe;O?`W zsCi;hKq%yHk#yqi$#&{78Zfx_;8~L8k4d?698x{H3-zmuixF|dEL{G;R&5Bu8LMCl z)%*mZ?x^5$`&pNQQg-ucG}D3hRZ2vbcN51+y~09>cIGK~n0q{QW+(6c`VMyu5`?;r zGbIq4uFV;FVyNRaA(pbp-IqcbthADtdCy+R|Fe4^ofI>6Zbm{z%X0{5;5@Ybsf5DE zozPzhg4g1?|DW#Tlk(pCPeXA=H*D2l=y)0Pwy9K1IQII`(Z2MpQhRLO%E!8ops-0> zu@j+EMJJ~a-uhQZgx$ebKRoD3>H0=d-{E1mZQHkg0Wcb#RL zt2Hc`n6uXnL?@i#l}|0r9XV9i!u(3b4d4(ZN)Vp4B4hv8{{hSNQ`^>=AE>D7wEEQhf^eD;&^qv3(U z9b}C7moC&HWfL~(Vzfo&Id|$us7`#xUnCzdDXxhU?my7o`9EAVD_(Sw{?mDQ!YS`( z;9!J#CC_vJYU62TqpMabAKt@RLci1B`L>EYZJ!%Wo0GNO6I+{;$}^9>mbdG^tCafB z^x?zSfulf7(u>Uub0b+QWcost2Vl#lj5Z3I$$A6y^)@G-8AbRKsS`wsmAO61xJd<2+2VmmvxS%n)6 z#^du2yVS92PMJ~}Rn#u7DnFyd457`ude$gh)7MH)q9otQ+R`$-cq>Ef&l_et)b(a+ zxl*J7Go^?0^O&wuq*m+}DmgYxX7gY4N6*~mVUAqN>XaV?NiEz ztaMO@7B)Zk-_QMBHa-5UHU9TY6fp0b97MIhfaHJkzPgb|>NoXtKb4tvwRr4#^q7jc zmi~RjtEn$~d^DzUcYcO{;vu)*)G(I{A?UIV_Fdt(ZCBD|?k{iQp2gahiDe20|BgCM zM%4wCT^Z_GkovuKT{={=7|7ByZGbpAfNO|}cn+{(r1AzN5+65$0+~0aJ8LVj6Qs>; z2M-w}C{Xzvoti-v^6s23gov3_0iz1WfM=1b#3m!V{W4i)@s@RtS~H8ZuVQ~>=}NS8!O5az<# z4Ln5FVq(|qYsLqo#azEUu;zlSgEHtUSGdfWlurWDd5xOsQg6K{{Pi>L8{O)ITr7TM z0f10!1V`+!KYvgjq$Z8|>KNVN#XoI6vp4Sk&$ z>a_VeNwu%l&)4g84xMQ^#2oPM^vjkPt-%Xl%$lElQpstWiLG^MDI zkVKzeW>(SFV2TPfFA1^Mp9eUfq(|`pd(l?-xsMfy<$s;J1^yrEOyy_9fr0|VsEM`0}!g#qXwG8s^Ce5 zO--?v`;FzZ!=5A=Q03hlBC{c@uo%o=3Ase{m`bHFW?I9^y3xp`NvY*La*L_>TwrZf z_r`+^NQgtDZzuQEb9Xv^KKFI{wX6PNU|ag27ek942&-d0>;_kuz*?qpw(+HnriR1A zkrSJMa2exUd3Xpp?O4Iv`w7G2!LAo3n0d^>d*0!COy~p?cnC0K! zF$fqhd9%AV>yWc1mxK}B5B*>w8n|6@~=Rt!g;~MgmzuvvgYkvZ1u5GXc z{zu4Ezq_CAzNpr+pCC?wS2nwKUtU!{@B6>AX>ko*9W!_5GsSFq(GWN}#69-zPvi5U z;$R*&U&)4qnQL-hkWbv&_3DnIt#QQSnzu8nHCxNrFTO+)L$+n`Nd5#gldmFBMSlR$ z#1@&s;QPYvcaeJEw)O@o!!93?uH-sCFp|1gU2MSP?R5Q|K)f#6+E)w-TgLamhoqH6 z3u$Il7rWWiW7>wMCv6&JBYZR?EF;Z#itD~Fh`(GX6XstNc^>VN-o=~b(`hmE&6s}6 z;&TE7(a~6PS$3+9S#u__6V?TK1J4^D;@fAI*fS*q=o2dUnLhR*Vbu!^r4EqrxJOkf zKuxcbQlSpHEL$Q(bDut;Nn8pl_hxgr>PxlpMs=xQF{ys%+MRt#Ll?FIELS(RtS;>Y*zkk)AXC zwfM4 z#i&*~`O{JhZ`^vI=z{k)jW|{$BdoBZ81oRz$P9eE3ep(@YcZ#w#m)tlT1Do+W3%sU zI~T_|@Cu6GTlM_x7ip4${{N<~k> z{2=-KOMFr4o8-3>7M`Hx_Wc0-g^aJ9yk>d-CWzZI!y-7RBUS!O>Erl$MH_)(uBHqI z|59c2`>nPx0I_Kq;&;EVFUe$j8;s3NiDa)3_oQy`y`TqJ0Q5m5UAeRHQAt>hdlZkF z(_eon8m;=4GE5*5>|3x8|8gA-IMaQ$fp13C5Ab@j-Cx~YEm2g=MT6jv}$BiMSLCneglSl zz`wT&MlZ|>8$dM7C9g>c`QI=w3d>woeXI9-GkfI-=;lX9QXQlTgT|okLHa{3mXFnG z6}T)gi|fV?Q)-6aH`1Acl8km*9MbBkadxt0v1Y!9%#pj>W5Zm~zRgFml2Ui@&~2WA zChIMU^IdLaiGc00NJir6b?@d45?+SLFIFLBnS~Rb&@XolcQ)~)4rv>3RZ~nkS@fPe z6f)9Z#Y`o#PC4@*m}Z6)JcOg|4t)B8^zo(g3|sXeHBI(V1+8%qgpQRHj|N8>c)2$- zg;<6Fo$#X~6GC@(wCl4qNwpI06#mX8-ya?M%YFYi3DHFQjd+O6A7jNG*3D%6Kb@!=pzVCI*w%PG-q{(6a1XkknR~8g z+gNzK9ouU0zalyLL)?{<$Ynmz`u8N`Ri3~jkZ=TjA)y0o&x*SivpelWdMVd$Z%bjY z^vt6_N8fWr+AS)1uK)8PKIhx!@E0d92_mnPXGophf%la>gS@{6tLQBje+^M>e!Y}B z_JGr~0c@KXZ>YCKdr4EFbPnqn-hiGzC69@MUo6(GDr>7^%&gLbo3>OqsRR3=p4Szd zID@z==B`or)<<%5W^&SqMI@7zZOLT>^F=A(voDf@bK$u3gra(i)p6RdpVKl^aT+(- zE6zX#`3D~kq9VEPlpKGAs}2?OroOV%UXCQ*C<_LaXCf7AFmW20r)OEJUI^3t;p`an z0S-yF!KS`%ycaEAk~AvFfAo-3b}@*Bj8%q|c?IZIf%hib_{Jv1E{7^y-hUd>NGZ`z zDY&KRHIaTs@%L*4_n+zFnCbV>4e0+N8H+IgE#>o$BP$mn z9}!>1S8AMk`FVj~z$POrh;KM%UBM-A4j*6~!4kQtRM>;gEjfFnSQu48){|%Op&?V(IE83jq|uwEGs}b(ZWECtkhNa{ zmWo#KDc-!HX6N(6>thZ}ZDLr-!%R}&Azs`D0aY`96<>Thc`bmZrZX%o_9A{EcGrE9 zOH;)1y|HF)R#>w33!X3l)+}ZwFlxIrx4e~WshxA3NSqK&|MZPWeru9vj@fEnxlL~1 zSkIvo?tUH$yGe&nRm{!NR7k=3t4C>79HaPrkBHenbK~9lQum7v&+x^TsPjJ!$pGl{ z6nC!$Ht1;dYi1o2vegnZhKadBFNomX&~;z*+rOO5kLiR;ebcht z%*Y`kz36N)GbrH7(6l*`u{+E*WtH-%#2jd}3 z6#GW!xjBa~_m=_o;99PZ_peynxHX#o6!h1x%Z6J?0t3GoF706P)z|-F82mEG7saY< zzNMJp2$vo-T<5#)Oz_5UYL#!1uH7d^2-ydi5Yv<=jJ@omqe5R z&Dr601%h)e7D2hTm8V;hhpV3MA5|QNWH^WM!5otFeZ^cfsMy8RW(-#1nF{imw;1ek zIw*vRcB=1pV;^mKvpL=2)qzaEMSB#E@M+z!8c7D2?#Ck5-QSA*(j_=ekOfN}F|u(Z z7^MNL>{bE#eGFmOqLzEf9|VlAeJ$4AI~i~#3Gb$H?_Zc_A7seH_Ywz4Y2X}voy$8= z+i`7v>1s8yfazkdB!!Z_jx!mgrkY-mu(j7(9y@M5d19?kKWsM4C=Nn+adI~+-#*~8 z8&Fu^Q?loN!i!c-yY8$iopkl}#YuCku95kq9!NxBXNSxU_O8$Hx10K#Zu0cETFi&j zZ;Q>^|G&qq2GTl0!XLVtr;jy^8yOW=)OKoSRwn&Z3 zRFmc&`~~++ugYJJIw}Ghsva}J!Pj=o_sFUQ8@`n3c)KN*-oRNd+H;ko!_LheItG*+ zRTIh2)3ipEBfl&KU#pMqpi(tVf$cF)Ka_eu zl-)f9#=LR~2;5}5OqL^+D1A0Kl|7G zvuEJ=PVs{x^O?MmCOn!lwXu3^^TZ;2FVEW%@w@#LcdF}WmcQ{z^VBmxFX~Eu7oAgy zN7nUI|7bTn5RyvA)&CPX+EUA0!%hhlmD?iBbIf%2YURiAOvqv(r7&?&i0~a6AI2Pv zSLt2|6W~HuVfM_3Y;7@y9MN5|qBgbA#v{jWs+-4s%Dex>DR5LA&{{iwe^Pa|t!|`I ze4_^u!}?*p_oHm&JLAVMUTrCq1tGEGm3TcWZB*mt+eMrlnP0rfzp*wdJbz*AFkm;f zmtX`PUkhcBs&b#PZTTxBdaStoVAqA_MJ+q_+M5Z*#z^M29AKm0r=xqGmr?+8(?{cq zG$a7CI?Zx+dk``E&M8x&P%Ex`R>q;q){Kc41CeTM;Uei`<}FWW(;Mf<)$GS@;*x@9 z)AVG)x`DR>l;63q5_{rl_`9Qj>^bTlzMPu=*{X1cR?qQbj`ATd$l!FupyGHe1$)bj zay9Uh8!y6}@6HFi%a-3iuYtC?@%mp=+Kc$pjZRPalo#Ay`^bJKRrzcCLm0v!R=ESw z>#_BaX5uRxX5T-Ytd+!+3BjwYpmr80i9s(UkmR!O7xXxw&<-p1RW%(ZJ2gyg(UF3? z`aN9iAy&oOw`!{BO~gOu^EUbRyY-W=zKU7@Xhvk7$bjl~JgcmobUz%w2_vP4M>%HA zUMXgcabD+~G=Np5n{8 zPe3kZ8&d)GhQgC;tA#?i2Gzvt=K4j;4Cl9DsS3&I(n~de zT4oJz>$+uQ_Tq9X2G2{Sd{pdKU7ryOzKx%$#3M1k9xxIsJXCvwJo2Q~%u~phBl->J z^{Y(K2CbXnJx`SI$B>& zW>1T33+e)}MG}Xp`keTMCAY<(82;Wx4`1n4y3bm58Xn7W{*m}h_tTV5OYBb*YvU7E zu!=k5PFI~`2OQ|*dXw$F!xgm4E5G{~VDg*55 zGVUhGb-0S)`Vi(ogB}%fEt5{5&ZXg5Gg5)s%wqo|{pvE;8gQ%h+5aWv#<@-|Wuui~Nsq#~0#XL8EwMP8kLSukp=jk_e){LPpVhOb6PR zItag2U0E^=HcDVl=rDLJ;B?Ao411b{W$>!|pk&eosQxH9TT~i?3EjnWD+Xs!=W|bH z=Jzqv%BV2}$I1Y#ExNU2`4jgnc)Z1_Fx2q*D@UK(Yeb~5NRkO`(aSt@Bx*ijT+*fG z=ky*!c%0EFA9dHW9DGGKb>W{PL&?7#JirBDD*{r_8v~iSN=mx z-NHWWlz-=TI~!puz6Q5hzFII_+nZljdvhFdTS@S4QhQMf=e6)=nPG)AdR7wx)Pn5@ zU=*8-sJ16@bqp4ET9` zrt`KdZoJmYLqw5|ns^HRnn$hF&n;3h{cAZc)I`$hZqYv?s^KNZsAwtfzXv)nwFiBxr)4(IW6DY0wJ6 zuDk6XUUU9(rCJwm#FKB0cUo z*C$B{&%wy%s}{-?N3o_Yk4q7E=`b90*QyqIeF07!R^R9Uh_vvPi2>G8vQwCr*O0@X zj24oM)2R7&p`k6>QpK|0CM(NIabNES-Jtw$mC55i4#vxW{@7-9pJWtig`o+G5-4Y) z`nft0)Z3${g(BT^JeL1U9bmS12WZM(B*HUha5E_5%`o! zXI86iR#riL6)8scw@S`MxH67brwy=?PxBku?=*i!tH^J(j+AGYa92hI?p%`R(M{1< zR$X}Sb#U8f#?AlnFaZos3yR_^nybH;L^}Ueu2kq6gS{P*-u^o;pJ8f^K7>$)nT_}a zr7AvclcbWVN*+XureS2gEFY9*;)EvB6wjgZ?~d4_AV-pYKQ{a^^| zLqQ<~+48jF2pJK^_i+rfNJ9Zu6#=qn%2n$!O=Qrcp&?QK>mpD=^wuEDf%h!ZP;kSf zhihlwEqFCCLES4D-~|5Rdxe8fy(K0usyHM^*GNri%5*}>bbIuOxdsjwA+%-s?ucTo zY_P-M8q~%omD459Q0TU&kCmj)V>-xmf4KSH>6sEhdWj~B&Dm}$7PSaP`a{?dFU(g` zwRd%DSucf}LhHpH>>%;m$q+qvqY6(3FBC0_edxH@5-w!|{-W0Ez@yfh?>HYn8EWTL zB_sCx9w1!oT);cY9r#WbFgrmwCX$39?`J%9f9L&cih=wo)V}qtBck!2g$;b4|J09% zIDNQ*F7bIExre34#qOLft~hBz&!KIrosRoQ|5+k@4vtFK?z5U}{pb3x&n78M-kSVn zRyrZh$~oU3`UM~)&*UL7#wJW3F_qnwt2DU%V3TwDwo(I+6WDD7uNc$bkv$HE?Sa!G zcHIOCXh~KEfAKy?<$-sRTYmz#{-}INivE*{WRA&2=bQs35(8fdo5-W1jS5@BFbSou zSX|r4kTX`N0O_VU1|+(n0jHzx(AKh(Eqa1f|me0hu?iEWU{8ulj?$CyG0| z^^f*BnO~eLvYe~$lB&>}_#5JuApWBu4vXw0FC>+X%uVk)R3pgE()kVr51*e90oP6d}b zkyI*14uL~EefKE`5`TxxpFV_zSi08cD4H@oC3WF2e<7!g$pf`NdtgPvZ91j{klQ+OO*o6j(-^w|PO7XSc{?b;sLw!&dzo4a}37s}~>>^Nb5 zkU6qD{#WbTCsc4$moP_l@pluh3%^U4+}x`zU-Sd ztQ+R4v-Cxq(3rDrJ7G!sQr>RP-LSrtFOf zrTRyLx#5*s=nGhyvpIRvMejTFZ5+) zSr&R<2n##u=j*K7vyUfre+ihi&+iBI|A+)kie5&&?|>Oj zl4*pQnenXQ-?bS3Vh}$W*x&i<5AQ$z#{1VUP2b=KH@HE;@A+T+``(xJ?r^t$^#1-!aV%c3SCg2lIwb2#i3&Xp1avm6Ewnf#MT`$rl4T!tO*4*foZol-ErLSU8g==e#?uu+nUMi0(BFG5#7{u5)9v^vl z^}ze@zsLLUf02iW2lnmA7@L^&WLsB^?hM88X6ZDqbY(Jx&9JO!Y6SbX0S;M=I3Woz z%CJ?lfP@<|&cpP~g)U-^nTTuFwFHdt&gmp5#y-blfYQGVi;$sfR!T~FlMVW^p!Mrz z4rZ`#C)k~71e$3b7zX>;*-jgYj_Co-LuSalG#SBW4p{;PWdW>xVJ@dI0NcTgR?lS0 zXuXV~oDJnv(lQItdyGM35Lw6F)!gY^T-dV4KSD?Encgik!!W`E3(Dx$=L`w>QzgJ% zQToGjC_&uiXhQfWhL$5ZrkxPv7@_8ZIcUg`aqFgej6L*>4I&z5T9(k-fF}BZ6X%5> z#;87g&XHQK&+PH(x5{T0fap74#5sDa9|`C2U!I-65<_Oc+!L33HPS15L~lVn!9~x5 zn-Q56oUwPC`|s?L|6nKI5A%NnoT`Bv+~5W`;QN30&sy(`FNfvs?tcBq-QE2++&#Pd z?ET%{=hOU~Uq0-=;fpWFJI9S>WHSkfa8i8D+{gjqSH-8zzzwHk>|kB;q3>8W$VLn~ zD1&MT@h`2ppFCdexltR;X_L9ul<_EeqVEJbwL=crF#@G)BN-p!*UPeC*2Jzed3-#g zAc52S!m{4s-oVPhWy&?-Bb@?3>*uG@?iN_3eyizJ)H{=XQyP9GjGioMcn;iWdnP(& zl4(R#zb+X+cDbB$NEQZiG)!5mFF81RH{3MH}~G7ahV zUC*l`Dk!+RL>ScrkOsrZV*tQfU5Dy@GMh2X)^y}a#sIzuJ z-2i3ys-RVdf}859XED~9*A^L!eSl?sW^+a%erDM2h9bHpe9EZTrZvWt8m%?VD$TzB zsb|qy%K>H|j=7dZ%+z=Z0LNR$O%#bKkpdj#P-vZ{BIYt&8-|8~>6v{DS|pi)nc+>* zj^euxHh1iAvuu(Pz+II`y3W*J8B3+sBvVL7n$ zRYrZ+egT-$;2b%2oFtJ`W~Ok~8zg#|lpHBVDw^}7tOe~jZ0zjr+Sj(ZmRMkDmxr1T z^scKnpbY={f8psYQr||2+H>iIS!U=$M)#$!YshLP5e^e3Zs&H+eTHhAo&n96*S$0& z)ZOaX=N9Z=A@dd3|MhP?y!@$ezkj~XK5lS>8+?63Ulv~v>;2vR;p6xBcb~a`e*aC& zdiPmt{j-m!_~gq+d;9Uk{kAvTNAaly2waT5c8( ze0EEk8{TwnHUJr4W-`Ef@AR{*5Z?sQGA~EwREXbZAg+r71pBUtajO3P{R%kSY3G9v zUU57gabI}x+6$oMM~EB8bP@pC%++*M-3T%Ogrt^4Y250#bf+o3eU-&d;IG>_a+a(o8`K>3Z|oL6jA3 zrU1s${VL;QwxRDa)YrN$+}$w$@|2h2jP7FP8g9u4W!_l z31a9yceOR!p5U|W`dJcFqKv*X1K2b3iy8d=5&rig^1V>`4ZcQjGwg3b@7)jU;rZQq z|IxLtA6b|6zV-Gt$w&5myoKfSOz!bq_Z)rCSVo487;TT;Bg2C9^h5@}gy)Ds5GXJ& z^TROax^BZbtamJZsgyOP-uKp7mPLl0$*5Ed`b5T6+lE;Z86<;|)2M&Nt5@&wczh*; zUJM7LEUOelljqi$JBh0OGQtwDGD>EB=Ujf_=98Jq0}qo=CYU_+?k+)>##|>iX`&5q zOw2!n*3@>!RSMl0s^_M*P3@9AhPh}urzHoRQ~wdA0mu^7nG)P~rEoOORbLhk>w&c&SeKP$ z)$X-!?fgDCNg8x_Fek@O=9qenkT3~bFfs!Xe>6piSe^ z0HteFvio>EVIFwvn05ML#c)Ohr@bP)F4-|6Ii5;pduQ=lf;U63$bd@}9nMX%(wnl< zF8j@t97tpkH{n7WiFA)})t%#wDR<3~{-<`p)TTL+u>T_5-3;cYcFPJ&7oJffCq!O- zSA8w1NX9N)LEj^iC`Z6GoOKX0rjO$q^880|ZPY_zXkI=HQ`d4=#s-wrK_dVZ(f8J9 zU43h8NruMM9G0b%3B4P=X?zCs2EBKrV@t;i^ge11&>so$C(e#*8qDz}nwj%s0pU<9 z5&`so1`XFt?LJA%xBAH32c$2Ukp?GAex`Q9|EWwKm@m!^z9w)p>~BE#X1(>^dRtrX zubcbZn7uP{yuHWvnl(QJv5@qzSg^FP@Ily&x{XYWOc`iK*{`N`&;}7DV9Kan+W`#j z4l?YU$#8Oa){5erO|N8q0CALHt|jtfKDh;tj}M$qCr+ma-hclKyn1|}ZEPfB$Yx;f zFoJ2QkS1f?im3sXU?gXWl)9&DgK6BROrMF@WSkO;2KB8?QCtR5R+N4+|Er7y3Bx44 zcB93_G_j)HyoO8}!&9zg0506m^g1KW8J`Rt_qQJIxW9kK{rxkRWkt~ir#!R$P#K9Sf0nV6Bu*b~pWtFF^L#dY)$)36_#qU_U=I~@bPbsYmV zM(y0&fTk!#rs!34?!AskYz>cK8#~*!k=w>hrFS!RZi-yYxz*_boz^<*a-jR7$V;mo ziM?_Fi=>%Ja~b;fB)uLi^E?lL_H3Xg3eD?WjsjNo^o}wDAAx%SO3QZ&=ksWz{>rFV zx!$i?M{T3N>T33Vxt>>-_xMtG-uu!gqRLb*R|D0?1holD3ryrdyXv)G*h~mZH|<9C z%;2}LktDID@gM!z!v{b29rrJkrg4KC+~DgDe%~Mb^S&I``}_O5PrP_>|G8(+?!W19 zxckQR{^`eKeDZ_G@zIx$}fboYtXx6Ci&Z1u&j-{ySe|5VAfe6wiT})~MWJ(GdKtcqA6rD4Q&u5Ki(pn9O;uZBzm6s|(iOh5T z){Ld=JBp?Ta!8nL)^Oc1{;c}g% zHq15Sthbo(cDEXrVFq&2=qV_DrJO;A#+4$Y-WxaiBAIzU7Eq7UI`rX;0p_AHp>K1f z&xX1x)dEc8xu!3w!c6x!mkto2jDz$2Ih(Vcxn!|6&T)r1JU7vx9!-PcnIB}>PmJIv zM)HM({lj?N;HwKa!~W|W{;fatN36Bxtu5VPHRJ6dJ{iQDk>mB<;*k5^a9V;V(RK!D zX*BaBAg~z8$RI6A$LWTpn0UrzopA39OIu~U*ADng(~kB|L+iC=;AbWzj8wYvw(rF- z>w{sIY}?M`>4Ep&{~|A6y~h|k509_dhYV2zB6i$s6Ey%Ne8qH&7-?chz{N~?%J`>Z zAo<`J#ki4BBNKC_Xsf;$rn%v!{`HJfwX~zZoEYv#L=r=5$TO8*-g80GUkM^_#-=MDBv3iCxWydab6Y_L%STmjiV?g?GK>QWlET zR;tn&Mdq7-jfoThuiDrBUE`yaSk-qEZlV8(ZU*K&YxwspkzpCJ8UObmdwBonzvKS3 zUnI73gB#r7*DL(MANmihugm)4`Q67~y!Px{pFh9<*7b1s2J_|94;!C&bsTTM|7tw{ z;MKmqdJKCwr6rBTd`6rT$<=F~ona`#Y0OM3=@r^XC5MyaMDCq%C(k;E46WX4LpKXr zOYZI#*26+y8gP-}kx5JG8W9kdXhS%|tg&=0>*_t|eK1C{r<}aoHi)s2k*o(;mX-T^ zNRFINa$1`=T7yU#?152UWg=?qwF#YBayspdP}V@$G}aY4Hh21>>_U)i)~2$>w+%qL z!qhdU)Cod?iG-=kD78JS3^J|6py;vh(7TS#>s`NRO8qp9TZ8H3SMMcC8SA4H#MNf@t8*c{q`xVItauiOzEAoV$2Z zf3|Ia#l$CZlU_6_l_uOo)5I)C!UsYAOu)~OJZ2KV^ILE0>%W$8Gwi?4p|@_mt#_^W zXWsfcBJWP)@vR_U$Lwy5y<>Qew2{LjhT-NkWXM+bxm6nTHt@(KB`GmWh(=4Nx5l!p z+%0#keWklzKf`Irm|vDvh>0(dDSi#9*;Df);oP! zapNq^#~6xQAYr`Ml7J~J%#6gfT*94fp%VZ|2$_ii>K6lZ-H-Vmq}EBE$4JcqqJL|RbzRBS8h*nyS6S_w(|gA-wclFNxQJIRPA_#; zJNE@t|Mh%5N$Q%cch8NC(0g?C>;-};QZAX?3oZaHM-X0mM+Mit zrSQB0(Q1w+tE9%4`aMXdi%R!&?Ix_%Q~m!!Fpc{O*S#7r9WQXzm(|>wxf=}Uh0*@2 zJ!qNZu$%qge(d3cfBYTyFK%n@Z*YUJ6ZnBY{2$t3UDvz&!$)4c{_OLwz5eXm*7fj> zSpW1E?c=8r@4kE-Z#*2w-Ep_JhqrP_%TEnw*(k$G*X~B1g=A&&nd43A$Gt(Ef{~4M zqc_J|$1=!}v(??0yP7YHb2v2Cbpb2cmq|uSRcZ}0gOrh!yEdKe-ODgiW?QD6<(sAB zwb*%#U^@+#Zg@G~cMl?x(`myzn9B!1PK-qNGlJ7Lz)qMu`)QD9{EAgfeMTPu$z-tF zfHs>0>ch=w?##V!l=W6d?Tq$|pz42!UQ^GCNOS^@>SdN3xPk~cPftROlB1cI`t^_* z=t#J{q=tu{385xP=^2tYi8iqVgeo(VKQloIM4ytsXUK$1G8M=Wt~Gv>Y?RYRzs)GT z1AyMO%t0q088LJ}q~_pea%9x=*N~Y|G{e9fn!B3EEc$90is%?Q+gH6r<>z4zjnlnI zQ#dp00+uj}@aEDmid+}^f(CE~IWXL8BjOjv;3p&aCz*Eq&{H?~8oB%FKa zaL{h+lg*hK*_=iat~F>0LLwVbV@etLHZ3eYt$L>V5(>#V^~}`%S%7CU_MOw|L>mDq zT=&z7QJc?MN;w&sY-3~JrxQU98eRr#f;nM<-Ux$)AlYLht<_YBHfG3ifQ&;$wSzz= zs+RyB=9qWfm9`gS=M-A5FzOpLE`W$2%kkqhvL&r|BBfvn@ftrG8?JZH%y82_1DV2! zMkz~rP0Z%p>v|u%6gcdn@ZjuO?^z-#>greXtiCTFfKpg8^^Tfj`@p(-%alTgHw-1+ zOMR?4z|fj|M~1)pyTJAJQw%Pk_AXb6rRMNyP5u9HQ%zClDFia!h3lnF;hXhOWp0I! zDL>B*npwknX0-3_fmz109sa^!dwBmJX2$V1J$vIR>NmK-4Srq0@B2glfi3IW@17mr zdF}Q4&%gHi^WS*5zyF+h|MY3_vD3)69yVTk+_*pP^ayVlxSQ`K6DOz1EPj_M?qySo z>z?GaqNmy{46-$B46sJ)oyNkjEa$X3a0mA~+OC!kUU+XA+Re2z%*3ZN5)2}PZA-L= z&d%e*BilZtLxlLFxnXGv42%IF!!1IbG+~T@k<3g4v&(o#$f+G;XN-krj`t=*nc}rg zS!vT4m16;{beS3YHNY*;_0D=kq?{y0Lqi!@kuvNer29tnLJg39041}sWYoCIQ^dY4?@hobOq5Qg5RqJwCIBJS0`XbTaF z+FwSb>zH(}|5KhxVARTuF9R8RJaKFo`IyO1?P>q{Am0PVfAh8*{?{CChW*zm{9Awe ze`)J-XovOg_4~v9H{2bb{kGQHx9wy9$e!b{kA2zptwlsjOCrNiKp6{+CL=yb!c0ac zfIF5AOq;KHYdX5lYW;F;l-Foj8X4Lot#$2)ZzyFuGqHeSWeP+vBbX68kH-f^=wH6i ztB04Ij*sm7Mx@fS<%P6bJ8i-dwMC*2#l-R{Gdm0DghXD@dJ?#BMF|Ggwc?x+A@8P% ziBF+EH`Q}@+$Bs~QyPAzoFEbE!Cgv$1-K^?t`sCPf(H^b#ki3{`~PR}-=D2rlDj_e zlUenwwfFnJr|(j$TT<)VYDwKKkkk@{jbpe3!T1OM8N=8Nz90uS62=(j-*8OKgaHp? zxKGU35e9o02^e3;ghdP>1Fb%ncklH)Rhjd{H*2l^o^!+qNv%+~cAm4|wbyg0rz)$S z%=~6%Reg|5O5X%Lt$1u@Kxh?Sl>sO-A`6hEG6q(;?=N4D3rN%_Bs6cCtwbySIe=|U;U6?V))VMLnT$~cGrNpT^P|e5;NN^NY zS!*3+hQ?cj+T@G3rm|80g3=tV$tln*Fb+9`LdK8^td9x@{jYv|-$fAtR(sn=pmav< zF(wI=UYF2?lSqd#}S`+?-Fml_ZW8%JN+2V_YsVMxPnK>5Ma7F+ePMv z;R48RrISr_(=C;4DB*-z(zixyCx*lHWe>ngwbsQ^^4!1-YYsG+rW61SIc`%j-<q-+dH`%T@-;UY!SgNlxiBP}80>3aDN*&~>%1H8hC~2+qPr!(Q;cA~5r1aggRe&es zN%|{O_iGwy*`8HDccZn=oICrzD^sv9TSMvj5umksjb0A@#e?-&RYmo_^5a$wG6d=) z)U1pu7hNBb%uqRtRx=blNxYfLN|=GV{s|?rNtZqQeoCsY?vWWYBVR}IPiFGJl04=I zN_?iT2R#G(--7fX|GA&G({|cU+x^Ghy8p-zy*j`3yPNgjIWs>OW*?2r^T^qQ@UXPV z>5)OsGzoH(6iFw*aa$Sb5^_kuVM-Z4Z5!P;w$|vr(X8X?@+u1eSgiv>vws0c#mU$WK1c^C?Kjx^^$rLm`{PjQxe3u396^RvZU%8#(^Z4 zuB(5p3OzyF;22g4)6F1^bkkOAfVPgCB%RhbEQ36>`um)kv#zwl+jH04HwjNU0+yiH zKOYpfOKH1zw34pl=ByNY2Lb$}vYgGY%042QL#y#GfUNZM8!f;Kp|V>O5MFgIZW>;E z7Eg`kWKo$Bidn!s zP4m~+$cYRh15dTWQ6E>OzJPKep-=y^^vYxCg1wKYPM=HL76BC zW-^2pxTnf8Gg2X*sCzqRuguz)TgDw39~s79!2G}a`G>E){pI_Qe%R~$OwaU8-@x>5 z|IA-)=eyHeFJ9bz?!~M7AKcET@3Xdj$AN$AW#%Uy4}0sqOWZx|vyb$q$TZA}OTCtS zOUcxj(v?IA?3rVhgeBP8Pu(Tj3CO_AH19kbTXZ}^GCWGBHt4OV+-ff1loxqN~8qv@6^`vKD|67dyqyOwr*w)W?FU~JN^Xl#+UwmM53(}S8^*GQ`Fg9!q62p&V=-&)!G3v79_~6)xv%CSgm3^IBh3- za}uS&OR*$c3{Ew5a{)Ft7NB3iUy}8MvU0W2OyFG(2G{Nb?rg2I70_P_U}oa&_Pm&r zIR>q7*Nh6ywUPwCJtx7O)*a7Y^-*%dt0!1hwuTv|UceFiV z5UI?LwU6&=N0L{gqq%GGBX#OEGJoA?7-)UdHhQhgYmKeKhzOdO1HcuLSRXk_LT$8q zcIZ=0fK0U{z|yb`sE-Vo(6stZ`xTWAj&@m2-iVC2} zz7ZH2v!bf!6Vj3OmaOY;S6+{#+zF0`f`B_!BVDH&J$=9Qt>BE86HLxFN1$I>Ab662 zK|nLNd(ZZH56&%fOZY!0{Jo!hc>DE_+<)XL1E1-cp6MHy{^-yA6+hjbU);Yuf5*#L z=P#em+ZSo=yDyVZkI0WdUhLKD$GCg%G5UKC(Z+PfG_C8CDLIu=_X#!Ex+3M7U^=d} z=Y|`!t|+S!vP&|hyZc7BNgD$W2opd9r*Fn->$C<6KFAqh)&LfS2CC(y-ewBk*R&4J_9WESy!}X za*||Xn83IT)VFRhq|Fk@yqbCSTWvKfz0x3ZN}oT;C0|uow%4r$pazVx0R-%87$LyC zoH?=q6f}^%6&cKwoz`3DbkYL75kX{f><1CD^~9@AYs!9bSGSSV^TlL57t)VPdL zo!kqk=k0tVhsU*L>)eyyBVdLa)>A!gapQtJSQ^dcRG@-anaP@BfxhAi4=3<;WPUZm z-^vc{{Ix5kd z9Z^O&M5ae3<^kCujTzcvC1L=Mr;%Y;zj=o(TR8ea4MiZXDwQ2244J1p75}!3UfC|DRZTeX8~DVmL`B~ zuGsdtJYL&w24*XYt~r01$s7k@wYq)a9ysEW)+dm{ogoE!1=YT~z-V6ME2;8LW6_pj zBu{yBEs&(uWC5tmWJI$HN-DzhP{jG~OtgT!=_Bt3yB-l!a<`$LeJb=(5HVb+lI zX2D{yZ;n|;BxD59#0P=H+RI6BOw1_@dCq0W~MiDbq2J6JNNcE&-ndh{I7}q(=_`9Ksl_>^i0q6 z4NZUKr~k5Tcc;_c%kyVmygYyDe1HDYwr$^^cKYmP*rzTBuO2UXe%!NPF8Jdm$xPSQ zb`1pz=M{uS#1+_+DI35jT_gEzjuuigq)SYClT=i_Tf?Sg6KDl@Gi_6*?O-7y(Id*P zF=wsU5+T_=j)N!z;D{h{Xi+|gF(#MCgBhBFhN;XRFqbB-gARY#Qo=7t+;j~mi*Nm5xKWji$2;?ZVW3~|oMAh1xIGL><09Ie2;Y@#b@ zM(qIP+$d&dE{96Bv)XGZ{v|qB$&I?-R0b4JY_&;??lD2R4QjKQ94wB&ye}5jC!&s< zTHm|k5RiK&zZBS4lf0nQ&-5EW&%pk-5dG=D@H6dvy8rmg^IKndaeC`Zr|tf`tog?> z#+{|zP39?`mPwmhW7HEY4ZJyF4J^rew`VH4DWQ<0WeK`X>CIcsr(X-@;b8J;DjnQ8 z^?n6S5u*f^qV>n+!g1_6K7)vZV}IoF;Wdw!2afSbW-X$YNzB1G4h)k*pOWlWk}H=` zH?FmY_4oQ+3h{cZT9=8L->$22pcG(9KzAuDFc#2EOELuf09xy8Cq;?9IT5wJTRkUc zMY78f@UF~<%t?-eG0TDBQshhfn8_Hi*74SGmlGvs5M!e4ZKTKu89HV%d<2juF(FOx zkfhoSIfFFR&czeJOwV5+*&5`OK?A9@{NkpjTe!xA89sx3Owt8%wJ-3Ken9oe;&II2 z$b&=rnZ18Hh#mZD3&3%zd| zw}yMT=`S{MMv@%^YUQ_9%Ud)lj!-H* z0|p@VYP!nwJ5t{>%F&XgFRD$pt|Q5S$Qx)3E3g~_t?C~uK$}FG?x`|V!>U42RlA<3 zKV+wAoMbjYHp|UvFW&3;?M6e_EL-O(-F~I&5@m?;z@PWwekj7m75_wo>kVmMHf*H5FN@) z6u_z9>)I?^*=#~yGV>8^0Q|lmcwRW~H-esl{cjQalmFR&V7;I2?za1HJ)d8EXX~fW z(*0WlKAFv4Mdmpp+l<*JL7Mqot9u);ys_Yk(zXM@45fD^k%4cGZX2i5nclU9nlDhF zhPlyu=hU=^y@Xk!h_aN5yG!BiJLA}yaj@?fMeZ+3%YVGQX5TL*_--E0aqJicEHg{m z2qG@vmPmjZx)&ti*Oi8ZxRo?po?QT;TeTyB2qij;4=5UKiX^)^lS(sRx2F`_);rtj z#9A2c3J6(B4nQlfZ{BF9jWH)6gTUNqy~*>s+_wM)P`&DJq_nK;5_xjH_qcwECuVprewm9e9@x;z`ibGq&@_Phv_^M_(+N^Qe2k-@<^q$b zJd=S$iq~0XlCYgl;B~yT%TmBgS!+#$l*7rL^XbgiPt{-gC?!+<=C!B|DZsq6mOS|? zzqii$bYetc<_tfGLuu)%hawJ`((yn_-)5B3R9Trxw#2=W#nc-U{$K<&3h7VpuWbT)t~au;gj_Wf57#dPjtFn=L8hfv%fGkuAM7!ISHdp-) z=CaQxSzMW925Va~H&}q(faS54TneO8Lwb{m5txO}`HFT|#NQTJGstrC*5?=#qf)I) zKRQ-|Fqtzr4(&EGM=)nFMo8tPQoLJhv@U&+2{DsVi{rTmlx~jH1?IAa%w!*Ir;fSi zac7p~ZK^}&)4FlBDOyF+#{gxH3G{*VZvfc@=w>7lYJXCCvf6sJB~r(;>W7+FI#u>e z#ESkq?x5`mlQ@#roUJFVo{pZD3qH$wH zU6`qMzW?DFLBu3uD!5{@F@PG20H(g}vWe%EbH;3qsauI=(3VM3kJQw_ssrE+A`AxA z7s(oCi{9WteP7Q%X}_FOCOvHR3IOIBj|s9l5l_~=Z`2w2TwH2@&$P!(#u^UK^!2A_ zVEzjngOq80|^zB{|Wu-Ak1e*UQ@YM^H%{dt3V2lg<W<`dAl_~lMCr_sm~@V#%U`$#gEVpe(Xnulf0!GfS71v3aA@}Z1I>r#|<CYi7U#&KRUe-J`|d#9_5Pk@C=Xb%1FsbdvBS z=0N=7riki(_Xas3QVJ*%lNF$As$RW!T5oEB4~7}$in5=!Grema02v`wwz(8n8lZNp zcA8P+q4?N4y*GU2Eut)wm4!lxdvJ@NQ{zzaX9&}Fe}d8CP;2$IUqT;&l@ey?Mq#Pq28^EZM9+CIrnV#vHzQO3<`_un7Ki!@0U%tHi z+{;%le%tAM{?g3$oe}Mmmz|f7`?!1WA=-$o&A^TcbK(L@E&x9T;%5}7UykJrj0qV; zPKZ`=Q!-~sL_-dGHvuV$;E82mo>+sHl3`}L{+e0Ea$-6$gUe;d%%q=eV~)XEAlMA# zeD>1k^*1#Sz4Sz;0s|3}(e7>4kVv!xOelLzWg6y&rQ=;0d%ZV6deTiYc>&g#lf!o0 zoULo>n>n~8t-SxeL&UN-C{CeB`f)HBq=}1Z%94u!DWo7vUxIW)rnCTn9P}bZ(3kX& z(!qut8-_cwFB-TRB+N1~W+g*JLYYU!4;?E73n2a7e6>P)bv?VvO>}JOrUhPo**Cg^ zD=z@|r1y^NQns!geQx(~wR7Rt|IMnhF)?p=Gq$dFs&w%UG`=u>8~S@u#;wg)TOeVK zWQKSJ#SdW3;H;|YdgP?Z1R{0L#9MEWAzkkE9DmXus~K)kJ|icSOeSfsAueEnjFV^j z4WMUW|67E5+xoVhKib>*Tdeg@X7i6?_A;0+X6F5fd78{NGA$G;t?AK5O1cQtTZ!M) z8=O`OWl0+I0*?)&$(VNv80q6KAcYw#Ra%0fJlZHes4}HM_v4}n{@4|nAA@7;63Qi@ zf%;ntCJX#!QtG7Yc>POHx&5lAUhBGqnWWtH?xdXj67W~$P^EzClc`@(*LiQ(_UraQ za|4amoSS#tk>QZQMpV>4Gf1RF^cYjKsUV{@b=m`M6_9sp%g`_XcPR00v4;%WFB22^HnYInhe?fIDu)G_tn`)Q4Om3q5oJ>}`qH;yGsZWJ$*30S?`flR#HJxQjO z@u@N=Yiy@SYWimoj&U}#@AkAGGxG0P+E;)6;obQhwST5(`o^Mv_fP#z+fL`x{r%l% z-g@iBZ@<64`<-E@?>nY_%Q4%_$30Gud$h+ro4MIOk}<+(D8da0(9cQ4lhpgvhfIuQ zO^Lc4rv!~%0SP3YNm^)eHXM)C5?~E9I}sH5howLDZ6%+RGwHKt zY+Iu>W9FMSiJEJe!JI00JtmPI2jwuQvj18qQ}qt>HL;3_M0SMkU$woFboA*YVDF|j zU7LlKgAYqE#j z47mnW+Ed$NMdsbgZVdGWm>e<=ZfbMgzN&exVb(up8hV-FE{9Y{+tvZ9_ms`G#+R9F zzblVc8E|z9MCg+Vk>X)%H)qPaPdBM@#j4_Ju2*7aURNDje*b6s4WMUW|673m)Sv&8 z*8Ayv>UW^=6lzB&>i| zc|u#;Xx=evcpCOZm@L8X?pS#=S)NTZngbbJE{_;msK%SaVH~?wzrS2AJU%K7e;h{% zdkL*Y@{UR(pwXi765iLz>y#|7Bqt@>&devs0CSMTqGF~BQXo? zq=jmlOECz*O3+8#((Nv$m@(&I&VhAmb$f#wD7*fws=M~8j(ElK*r=R|{`u>-v+Y^oT zmRO`-kM+B*kh4U`)^UB`{+%eIw#sd!r+JWA8ZC{F81_RBUkKwL820$&@@IOcXZi-9 z?R;)`_jezC_3Hi$FYfPtXX0NxMt*iido{xQOlvdn#B5GDj_^^AVywVs>CwzYLbiZ? zjH}EsZnB7+kWX|;f?47OSddIkp7fshG>!qdF)gW^RH`1ne(C=N(ujcL&`S4``_NoV zlFia@=1Nyr#M-KsB@YwXUYT@c(_ot0Zs}Mi%dWyG9jR~hzxWc;3Cq@~i_wlg6+kJ$ zE*?3pHBP-Tb238h)U%QZJ*PFbQI2^7WJN?mM#whIB#O^hr)_|Aksd5PzVt9qbp>Nh zozS!gR@EtW$y&PLO~9%9S~Hlb`qarQe=vy3gv%rXTsf+0E3#kQRi~KcILfTLs<6Cv zI6z`9Cy~aUb`+8=v9cuXnyG3eb7)FkM4-9&TKfRh-w8CgTNEC(Q$dr}-{L_HgC}iN zTjpE~Aj_`B6`Z)TyXbZwfE-GTcW&CY(Fa_1mb0DKG+x*2McoM~Cm;Z`+qMso@R$GF z2mAd$_&m@4>rKzV{az1y~(PN(he)VoZYK(6j4%(O}@hBZa2r7uHX;0TT}*e^Q|53hOe^*h?y z?(xF0zvi+(vL8FMJjpkaroZJah6U6~4bax(^i@g)GnkWOXu&)Q>LDOaVmRi`R?+hXw%r_a z?a$s^DgJA9T0p?}5WvR@L|Vf)@B)0|tYIsfZ-)9>z*h=OSs5fulajIJ#dX6n=^YKA z>SuL$V6D+eDVus$nvp|`B~pBEE@Q*p8Ke4c-C>T`^X43o;H~-#TZ2`=-#fkQ{?^)c ztVq$WGC^ax79KJw@VOTGOU?Of-q?Dlx5f-3Vlt8|Uos&`JgufZ1T&Kiv2od0*M;=N z5@H74I;|U)8gl@dNm6qwapoK}Z_=KwG*q*|yck`Ds`iOGV1jxJLq=wevZBR-Uk$Bi z>Zw-W>#&}ww#yV;{dhaC&$@ECH+0WTAj2JtG~CR(;ot5VU$o5s2IH$duaN&t&-4vL z|NejSU)cG4x_^0p`rM2A^H<#4m-p$P8PQ(tqn$=r6L@R}Sx)H%)=I{QfUyD)Ay65b z>;H*_=yq$rg}! zPJ){=nUZ@E(zDlkhR#JKgD4wC08Btw(P64R$Dy5ZGGUgDpiDUh4=8;MDreay#tKO2 zxH1MMUjZz^n{<_cY7%pjX}IgkMD__GeUeqT+j9&Ev^}1&7V0HZ_Fnam)pG@)m7xbN z+o0?Nct6+_fX>vkg9!chdhEJxmA%Ls*u1gD+?0WVerF1#>XBA`l(_2~RCnAEWUXt9 z+|(vm&#rq&B1}6lnRIr>(6z1MIBCl4)ARzltXK9(5@<&tjaAk4ri;zM%b6iw-j4MS zV?ajnB2_oLGAGq9mV{~ji0e8+Meaa>b=^_VO2|y+RNq{x#Q>+1(KD~0-U4MWHZ;@a z+76YNT9NsgeuL;4*#8zFZ=Ke**0$}w_4W~K{tD*(oY7~5rvf5Ce1Tf6}cK%9lf>$erLkU@<1Xa})tM;0d zZl(a>1eS9ES1P==Q*))Rd)MN5UAqQIi3x;f$`~jai&<*b+{=X|m?_V3WL}jc7~8gS ze}7Nkdez_Xia3L|SW$TfwxZ&3ZL8KwfR*qph5|^bDk?2dD4vTa3lh5}Sq1`SG#SW4 z-5M5XX9J9!Qid%{E2IFXVX8+YauAf0#ar<(a5rKGs}IC~Q@^i!Y8?m5l)^LUedByO z15#jS&Wwp6qeP!FFfc%4X!U8Dy!fpt?Y?iF)>MBPl1j@gtbQb$(p{G{ZrCoJNvZB!SAeG%R7pfHd4DxMrqHi)NLSKtoVj12~x|a<8_& z`Tc7rjez%;r}jeXtF90@dycY*ss#*p}F0<4bFTjDO6?3P#tR=~$Ru^d?JWbTX^cq+Tho6+e^ zq477RTIq=hO~oQr&xnCpqqklFRW8j;m@`PS^t|p>8KraPWQ1aeq28S_@LFBmVwbj`590g$o)aMvrh2*aFSDk&? zSb1~GfFX4)J?p+euG%uIUcFZ~!<43iTZDM7`lu_UUk$A47jN)`Wqw}!EMh%hyr%9U zr7Im3C_X054Yp2(2B58SQGHbZAkxa_2+Wdg+t{|#^|>m>@umVYJ6bStV0Lq~w8pik z%x_L9;7MI8qt#Qa51n4)hb+Bmi{EuVfmx0cSDk9Okcc;nR2C!}CuT4Q46jy~4XAMh zS>|&Dq=twmxslu%c&dw@={JC$f&Fg*^4`6*erm0MG|fLXGe0phUe3%@y0wV(Nu}Et zKugl~ww8b^OI*+npn!={j)MaBsqf~UQ#;{EDoFsyJ4s3yLBwXgC^ zU;8TWyz@04A75+ny#0~m*qKvaY!zydiG;KS(^8J4gwhS5SN%-2F`+AYGpmLIh3n%$ zDM^#ShNXm(WC`9%19$BMn<*tJL8!K?9s>A%+vt_Xew!OlrAtA?tgUIpZ!CFyeB|-* z0c%zQ*)ZkgiSGujcV51F$*FG~LyPLTcig)wkSVZRieFh7s@HN3U{=5}04ZH_m!eza z03)XMrj_$T4j-~qWhMxgUfXbeMuLUX3nKzWMAUbS_gIIlXl;sz?oR6)T?2>7ATn`t zya}AT4`84ab)~c=^2VEKJT3sgdfcNjMy|%tO@n48iY}<$X@PrflV=(?X~8ik$8mt8 z?F)-XVC0$1HvR`S1 zPoJ>bEJ{?zeBa;em&*Sa(XEwFkH80?^ycrU&sjEv)!$BmdsZFRc+xR9876XF;6a`m z_B}20^TX|LVZ3v__?e#RnSRq!KW*)NclyN3m*+3vowt8&rhnlGK5;oXjj%Q*zVB)K z5$q!>?b<*sFw$BvO&VE8%U<-#Vr-6)GX07olUJk!^io`L;0 zIsKWx{AaB9)3$A=kGI}G8^*T;^Aj`Y{Uo+&vrWQAPEzkTktu;@)Qi7_po9q|Y2aB3 z&J|U4xIZBsc*vaWjs0>N0$f&#&Hd_{Kkyd_+3 zieSxA8e?4dfz^V5hvuEftmg_`&UrBBq*>G21kLegw9Q#jd-s~xPbxxg&S^W7sptU6 zBW$i{c1t6dMl@qNAuxkb|1K|nK5>Pct&t!lI$dR77s0bqAoXuVhzH!(9f*(u_XJY+ z8>X>@c$X1Z4JP(y^;I&f44X=ml;SpB7)e^7)p|=&W6T2JttBh1pQb+3SV<^{MyA+M z|ELc2%(e4^oCq>p#vE*$)|Tj%A<<06)QljHM-m4wUYf}PW`^N4vW!fVOFI+7NY`_h zZK3GD_ymYQF8)T8l@}9QL#`XcuH$a~t2XK*{)%*7*HPzh^z`aC&%B?Wo?U-Gy)&W4 zUN!3tQ15k5LOFgUkId8}*Y%!BnAt|=Cz|;Www&LVX8#Ph)We?XnV#u4A^q|H!++V& z=kv$kdUgKt{oU#J9Kn|_BfsVG$nywqmyv!MaExTs=NRd8!Wh9AlYJlT`+kkm&nuuG z0)v*&pqW-0KW$F)q#3v=qG~3YY4f0wbcfy&JlW@D%$-P=^O!feY9rIWC14GOJ#qcZ-IS*S~E>O(|JYO%>tW)k%@WG zd#6X+3{If)?URCfgsw%*v9Bl|IMgXRq_kPKr?v?!s` z-8l6VeN%v9Xg1-MH10~Z*JmA%fEmfYm+h6X4;^Fa(NG-{@lMvjs&`ZDAgJF)W)i77 zn1iQysD9Qn$ArxwX0q=ZkJ$z8BVh&>X)VcU5f*0;88=Z~LH_ut>P^LNqw6Gt2`_BhT*j+V@JY-hDXl{A&U4fM~=@Yj1T z@ZheJY~E=!3BZ|TY9Wzp#5qEWDJFAj|M|=1HE)0ItGx5}*Vy+5#@IQI zNA}A_USyIb^p_A?l&ODG(yPv?&R}R-zyebxrP8>fCeXS1T-%!f$t~hzr#Iy*%HU!I+a7O2<=5d!>SJ+Ml*<9dBxbxp8^CU_jqa zx~_L(N_8a&cy1f5m9npACtmF+MP}k-W-4V52Sce=7+dd{)jg3FWlh#xK8Vu6QX_U% zq_;=}z%`-*VmC4zd*^2KPe}=r{X-TsHSIaZyI1wKQ=hKP4 zomkQP$TD~W%oSC4*9!WXYGwu;ha4=oF><5qNxeRtwiCT?c<(?GueJBE88RwN2HN6~ zxnW_*7m<+SvjLW1Y2-}I6I}giRxH!NSHvmU%rg0y?izXs-50yNA+BHCyV(qHe_t+-dZW3h2=|wAN2GeBKZeD|M+lx z`R=~VpJ#feXZp=T|IVNM8+N`s_w)VvV{g4W|H!Ksr{8aGKY2Oqv#*bNKc=@M!uMeu zN7yl721KMQ5-UBaecvkuf7U04^l1TY%|qA1URzgs^8)p50{%vl7MRsu^++0;O`1*c zl|dvOB0cCx#T#SS6abLyHe52igxgxgRSxh8=2{-jB|T*e$ic6zeHZYS*pnnQQc=+B zM;T_+ap~zfHAg-o%X!_&o>yGDWFlJ>({mhp(>!?D4vSU^aLX!CK@oBig%xj7{ea#2 z#!PiySq7vr5f97^WnGF7mtEzr<9)l;V@&ZFz}&9($(p_pY1$zm0F0Qy3XrQVfU0(- zOo&ixRv>GAOvPNUuSY{BnZ^uA1JHDZshEPN6SAqSyXD7QN;Rb6q~)N5 zHBhgl-b;6FFXraBHMZ6{Z(S)!*bCQyS)4E+r0ft zU*+9*zsBo_cX@n#;Bt9njs@!1rvz11Ns6>+Nw4~t3DgU47dU?+vY%43N~^EM;>?U* zE1DWono)UP3!q47>%5y+y8L<`SAGc$E`=N=Bn7k-`BmE@WVj@G1^#Z1_fFqB+i9bp zI=w4u@9tPP%t5Q|O92Yx21;dLbI9AZEH@)kKwFBf_|=dx5J4ctLcGs2 z8$=2+Dt#T-ys@3m^u7_ucPx#=?|wGbi^z?}-L^k#X%$cgIa@6R5V3kpyw&W%CAR*Z$mVmj-W6Z;ku& znKACU%n4(c!^Dy>ML2Q-DgLJ?j{0g%CD0st)A+Wmah_0Vm*zSQsXi)4NoHNoEM7NV zLm~*>$TDOXq=v=iMah#MdV@av=%Ur>Pe~kHB_`Dz?0TsZJa6Zr>XQjL!Mc$(c0J63 zv{S>syIFk2$)BIbyF4$V_e{_9n~MJJpZV){K5eJF^XZdsy}JA1w_e`=esBJ-91Nw6-7VBLwL8q3G)zcuWDu2&FHN;|Zt_eJk~TQc{J&X7nxq*qh{|Thd(Lq(HqK zol|)Y~4sd}do07kh+0rfA=|*5o0KIg6 zfj$+t{?WMU!VFqZJdGK$5h6BP z3(TF2WE7CZ7Wl7cQ*}*&&C6xyI0l$D>x(tJ^Rf%bcaX$4JjI)9ITQ%C0>x=)og0W) z&uVf~AVAu>VNGf>L2V52UY|OFcumz;8Gl@PjUfjORK{sTiwnx}5Hm;=iBAOV#hb|( zXq?e#U3xb%rOQpWo}u83o)7LCUdNDwW&wLMh-jGNV_Yj=WCqRU0GKmShFd}=v-(L{ z6rgNQ07KI$0IP8a*T6y|Ua9;w*7W@9@;9oXDTy^s%CV$$eDj%k>Smv6#OF7+@7&Y= zzn1J~bbY7X z5U}E%L0~wJ(i6cb{w9Fl(Q-8|g1be>>nG{`}?Pm%e;{j@m!dGyP_uKl;;u)z0Vb?(Tm3^jmM8fArPM z)9=OdC->dI<1*u|V^W|Vj;YAx7|EQsIm2@#b0%{f9LLVF@654724rBw6ImzOVh+tx z0AIpI;3pIhp|U~xEV=42qoS%fYX_JNNJGcmln!l)QvPq?IymF}Yo$pqBtYq$wVsT22GD(LN}}|verIak9`>Dt%4UOAqB7nl83MaOvTbtq z_r75sU~1ExlW|PEHMULL7|S^T#*HUg{K=Hf5FtmxI0k7c{aUJF#t`tRcHt9G@ia3@ z#Ix2*?x&F{0PQKBJHP~v0?Y4LJJ@idLJst}US#0kQ%>+ncRueE}n{=yVF$zu`GIN86h0OlgE`Tx2HW7;*^pPNa4+Xzpy=#`*3{0Aa~K2UPKE!9*E|0{2hHs45L> z5k2#S;-f~FNlzDLW{rg)ZPvKf*oJ}L*sM<{FpL3g$b?+~{_?cWJ-tR%{gvGH^j86N zH15(=w^`?JcZl~18ndY}dL2oLwY0t&-{Z+wfd4wN=cxTNJ=1Rj`lEm1FWa{D)A`)L z<*ireAG^Qr|N4mh%Gl#GBaW9xc-sRzMsiGS1{?>(gc-O1z4SrMV2p!tTo}iW_Nh-@ zOrq`TfYi4#xedz+({KwcEA2j4lwS5o#sOYaxU$mv2?3du+#w}{jC=xarSsNhQaT__ z0vNg@L5mG9&6|uVM}kh8ob4(Ua4_j$lj4UeN6v?YR6SZ#iDt0$ctouQW6sHzev$iw zP-egwlQDzHWQ@t0s%I|SsW2eN&>Z)Oq;GGut^j8_L`rAQDE_4E#z7~6*M(F`e?1s9B zyp<)rDlnWWExOYGt!&;T0qO77ux_8+onXAwAaWk}4FXbFbBBKC% z;@;?m*v6VmZ)!_xMuh6zQZ^(sGUMtz%1qo1*}g%s8jUQcnlG~3-;0k~2h3_XBHoCj zqDW9yhtV9LX{T=aE#316n(^(^_(hT<&8{l^nSTB08Q6c5QtR94wB3FC`SjvB3emoM#!PpOu{ek!1dz<&(eVd2J_t^IbZD%*-jgL_J6Il;M3JXBd_^MH=p0=bm z;I@Fgt}#k*ngII(_9dS&Ou)G$eWLOb3FjG;F-Kiz;>T4YQ|Z?oa}%Il&nqD4ONyHK zYbFx`3b=xl|QO zz-RGr^Z)VA4mRg@na3J<~J&hSMMU z4}aFSQ`_$D`nSA%x&8Rvi~jr5>_?BozHOiJas+Ke`bD6gV=B^p9E#K*1I95Gv7f=1 z!LeT$$AQxC15MHijFdbiNEtNJ|2eT(T4!A=Q17naGY;n1F$?L~)NyhFdwt9xqjVbe zxOF<^yvC&eGIeZ$-E|$AOk@izJ)BiGl+|I#(di}~-DF!~YJo)%p$tejWipsar%7MJ z0^BW@6XK?4XD%I5&kX7A1zuyyD*pPv~7vbeh0@B0gx#J}1IxEoHwggDzJeNMA&?oocrk zcw4G<-J@sgXE~H26hKJX1Xky(JJg>cXM>sQy4Bh`$1c0g-8r96oX=bFQuoiPZ#gFP z_ZkZg7}JQMx@1a2J8C;AXUwdC2DY3x;)AA2YK%yqCROz+PalxInwD7Ts#2}uAs?iq z>iPZ?i;b8^W{e57+`~rpZ)oF`QLu|Icop)pl4wJO-TRIU-`4W zxAV82xBK5=-u{(`arxez@$o(Oa}bS|cryg-adXFn+TNrRWLl6*%EbW3@n&p(qMOqZ z$TzpzliP@60tM{Hh5ho#>xZ|wT;5|IJI8*oUmmzTzUHz&vhR;*_4l1Q4gvTKN{o=9 z_kYbh$04H>SxC?=kUF_;m!DQfLzkTQH?CTS2e zdGGZD+a{&bykXrjH{zPc7YHO<)m3fD1aRDg5t9)?mv)fCH%H(T);{s>25#!JUc8*u ze^qEkqLD%ISd=Ma;W$ElXHM@YoJQuXYsFh-5IBxw);MjQ-Y4ESA_g+90&Hb3OdwGt zANn?#D?=hf^+b*vGsj5Ge`Cy{-@T*$2RGxi zb#Q2hoIo@6OetsaQ4gSo;DW-&0`cOh{>-`tr2HcS&mbepeAK0y3mGI%l7Qyl+tpN% zF{cMF5+C$@ST*?|tqL!C^O_IbQ$NdBM^c7YwL`5{1FOZ?60}xiLdc+*ByMKR+?w&- zE%{0$|I>uW|JUX9!*4sksHZ&BGd z?%+Z9k|QZS<;Xc8a9i>)x!N69Ih2x`YeBo^l#i_FJCeyyDRW8EH)Y-WJ0nY^FNtlK z0ao8YQjUXEJu|c9lR7b#t34X2#WiENB2 z0|fZZOl?UWH?+uZ1eKW}ojWJss_-!;X$QU#Zb^NXePJpIouV~m*R>`f8>y)EvMfBs zCxD3JEjNmQC+1j;*^#MCk;qj$^%bZL1wizaI!weQrq-1*Gc9)9<-Ay# z0$KO3`;-A79d1>>Oqi}nycr<&L&_<%?>qZ3Xlp@H6}18 z2rNtnP1Py$P2N>8*E&CGcAYo9eqMZ>kY<*imSOkJ_^y-ZZ;zJ$ASYi-Y`AgUN_eJU zPkILS-(>VBe)dn9x9#P5yZgT8+fVFse&4YC_$Btc^l(~|mL?NlV8YD=EONd6?P=Zfy+{AQR((EH6Q$RIzv~xjxogJ*05CBV+U*|J^{JafBFI$34x|-km{Y*8d{_%!NJ_*pzwx!qqhz14R5qq<3jW8afgueB0}I0 z)3{jm^Z;sXXp9KBn@L$K?XBj=1BzHk$tyCVx;Gd9+?8oyh?mPCj0j{88Kj%oM{~Y1(RlN?gX5*lN`-uxf9mGuAeQnUp_3ZM#uLP6!Mc$l|=(^OWAW z?N>~G%{Oc`b_*dk~xhLFawWBW;k;$ zV3o{cF!tIG_RwndmZ6O$!yq$?5xBxjPux&=zlYMRj#IaU>2c1aqnomtij>8el3MFcEo1kw#4Ehe2{tTrce zNIxx(M5clhQ~Ekcfz;9&p!*gNpH?yek8(FS5VFZU#G6&eDgs0HRVHZezcTm~!8VS$ z7VlH-6D@>jr9+_#bgd=eZkWkA@4i64bak@YpejeI4y)Tk>a6Ob&+5)hT|X1rwX<$b zzdCnPHbmA9sUmOJi|O#>c+AO2Du58I#iEzfizr!Vg5b)JU)Ho z_~^lL^5*6SLEw7DxxM1`N4;W}OQ^V_qzepUbe!&rHah|oObL$b8=6uoW8WE<3$NdO zoA=)PCHDP2&5z58dvfeM$8o9eoly(o%sHe4Nd2GODu>D2daJpPnvNKfYyxt(l>DX4 zmO?cIZcR4}(pW;R-U@~_SG3j}tx~K27Eo%f=JC5c$=0>V%$So5c~!MYo;>F>&DVDWzaXR4?6ieEfQ0pbjluIF?=b9eWG7cXDXTjzW}(^@A}Y5F-U4c&~s z+T^l~vT5a4aslCb4hDJClFQ?(ZEONaX4S7XrO8v%rwkupxoyAjM&JQ_DuFe;)cY)dxaGLtZG+!|iIev?@$0kiHkoC&u(ytxr^sw`;xn?%nHEz(EW?PY^$`PGREE7w^QAEFcfT6|7W)gERSwHdhj0hmeki1`lMRb!$3)Dl& zCaY+5ozrawc>~PrjvJuX$D3iPh_;cKJLU$qY^l_?uL0N~mUGyhf^j8JlSsp+90cZN zGfe5P<nd=#{BQsMDo@)2iE_B0e^;MApsj;v17phJPV-yce_7J9i zfE!<_dqB@sKuPw3j@QGi93z>?VF3%=uXV6i*_pT7R(CwD@;V*Kl^2;@pB)L2L}tpN zWlm(a8QgD;@7Q{NWhVb9(tZgzENyLh^-RBx^bG93iRh>Q(tm7Q-(H@#`|sQO=}QTp z*~k9TVe^#QdfctKNs)zAi-Ewwk`Q{yB~)rrxB~VhG*&vaK$u0AP%6P@@+OWkna5z? zU-R(rE)TEY;q`lOv+u8gsB(?074zpjDn)+>o_I>Hb&>#IbyIDt&PY*R>s`QWrLn92 zPwus)v~-W6sQRq*a+PhGGqs&@7eE%6Ey`O8o40z78_@7fj#88>)gF`bbCdaT3@x~} zR=Ay0(S0*TthMi{>KGA>xeG{&AyozO%2Ms!wiBm*VmqC9@!|!oHRcR1`vrG_(ADvp z?}j3uy<_M(8ITsLGfQY^NpQHDE}5#k0TF8Z)s-v$WY+iqDK`wPs}5dH1l2;{wJU3uMFBh3_&8=oXr9k&D zaIYRP%*?0w^=dQw9b3j%3Em!-|Mma#^6tAodVclf#eJq{dZw=j{h>eh=dJgCKA-xh zUflQ3-<{f5X7K&T!N>L)=b7GSgwM1VApkQYiRsM5X9$>S<#!`PQQdLux4HFGz#W$? zaHO}DPG9@V}{yZe^#48O;efFn5na=x+is>`hEQ*YeZt#cfbNX zuomeb>pp+zezUI{{PWA;^-TWRU;Vr99KY{NZ`~^JOuuG&2KL`X)Y`Uf{rt((cK1W( z?fWP332U6(&9X0xz3khBoZ)%_7r-hZR|=wA!>w1kvEFD0B->&yo$(~aZYftO&-cIQ609NvyTK1BO{ZA_VP8>pJwr-Ex7|qh z-^$bvH+dcPQ_KYTGg@!7sTJxoL&iqlN-{GdleK_R%hZ@ghEPT_!|82PUnDHYP6G0RD?(xBkf|(< zlu^^Srp$y)W)8@zZv-JzM8?Y+gipqMUir5Ui`S$}(E>(db_3z-=;G%x0u#O4%F+p} zqVm^HscUi>#VDKL&3@1`R#{JveK@^&_nUO9*;86=e)>KpI`;H?{c9L9V{{}i21z$- z6F%Ose{GBS>V&s}|MtImeCOfE?%sMjTA%5ep6S<-{*8b4&)K&1?R4rNyT99h;Qp@v z1jLVAc0PMKxDR?85p4!U8plW*hn%m+4397(V2)sfz~XVt%H$KMCnmP$#V1%gYY%h* zt-x~PB$m{-LpiEvOmZH~If!{MV-iE_`UsdLnd=i;P^@Hgru2t?-s}!b!9PSLWrw(Hhn~~6X)D13>Ti(U^q1YsfP*17rS3Rj?kCm+TVR={N879|LaE2!2X+r{>0DzNo%d&ZEgEh@BQ1!{PeW(Q5voF zM%W|?w4Y}Z5pD^JGCQQPgsi#IXgE#ZrDNO-&!sHENDM*6CG2tzUcdJam;Hfb>>T?8 zkB{%L@2|-m61*9VeJ2AhkB^MwV2pz~)?#V@f8Ot_KsGP|tLv6?rpW6xf`1i3H;HqV zZR@<%RrQbdG1vJOAvT<0@`j3Eke&se8w-BM48~Lzf+F5hf|*hR%h`~T9ODpBEO40x z8q>6>T962iiz5=`hBv>a`fI8{<9t4|olanIj6rKV``+pOL}bnFU*(q|FAhSc=7gyW zuM)Xg)7-6+);eVZqq-C9mT|E5$DLC=YOeWZ;xiCnmUM60>(!0SU=Br4CeZq+YW1YQ zOnsEOj1lCC?;S(Di+iATb|haEH64>*P~rZWRZATU2Cb81`CIR@=VeT# z%xh|#G3Oy29RWxmMkW!uXMuACCI*>Sj&9JlcbW#*TE|H+yMkBQM;$W-Cl=5K$34I* zoj#;<1QLy2Deyz8Q&dfhD4u1I0TIra!7&2&#C!!$0?e6p4~e=3$VBU}sLA4GgUt+0 z_b@Vb-3-b;keyVzgb3Mi2GytHe}oojY;Lsbzs0`{ImX>xk^IVdSZV!m>u;-KWoNE> zt6uJ~?==>1aEM6ueQsUOFw(?LdKaGx`$b7?z<6K}rZI z5hEc3r6o&<%osdAJo5VW*Lb`~_cXz9q2N(=?~q1-42IO7R`Lv9>+IU_}n*oWzRqrW8W=M(dTjl~TU$rm`x9UBG^UQDfUq z0`}X6nWXWtA6)!GL}I2r-{+XjoX8Unt#9<+ArUB#z^dJuiU4eVBZ0NzFG$dXc#xSe z<>{8gM$QWB9lB#K1)C@u!A!gv?v+kIjX-IU+QQ5*Z`DsC=?T?Y$_iRnn%m4E_MJI* zB9oShr>o0BeHlrb2{;4GnH6I)VnPh&)WSui#)V;wnCxTJFY(1aaJ0g00$NN@{8@7u z%^SxUq*dg?P46C1&A67RW8z-|nBGD3e~rZ&Z#q!->*HwrX+9fdy(9X;6T0#9Dcz1H zc?I?pMfQzbAz8nlma~qnzZbpvtf!^CdEL{aw|mz0mXHRSRieoSvG^8s*Xrv`U9)Gl z&AId7yBhwllMxsA&kg$rfBW&B%UAB6BLmO$OuwG=hyU20x8A&Or~ZliyZ(jV?6=LC z-+MXoQDJL&^1@h@fPlShrm}O;7+a+N&?l*OSODs@2sygOoYkMIp;Z}j zh8S`_>A7aeIaGBFOYt*x$D+lJMB_csm;jB}bwOr*sH&O3{B>MaIqTX;*h=CG0Vl+AuRkovi>e(ASnORfo(VQCgQ4VvE`zR@>e+?`*x7bK{n&kf}Lw zW`pJ(Fx;FOadjrFMcrC!kjXVNk%?0D!A=DENrYByt%!~{O zZc&D4NupKlm!rtdm~-$jCcQOI+Zh!v11nR8j)mF^1iEEknY=O}xI=NbkcM&mTs{Vs9c)Z$PcT@btoK znNN>Cy=wja!86w1rs5Lk5ez$GyGuzg_aE$n#{?A z>)Vi4fB$iPE$Jli1k&?Lv)4IgwZRG?$l+SL$Ydw9rtCm7mv}dWA-x2KJD4!w^||KU zoVl5$9~?Ogg3GSe(%1P2h!k)&18`QRK$_MNlHF4EPQZ-o;=5&Am?<+aLUZt2Z}gtz zp)5LO8l>9iO&Jm(Szc}TsOPwo7!fd=$!^GmV_d<#+U(NdWv6LO2y8F&6eckt#4=hB211EN9KTtlcjVYgn)Ojx$hI-dz;ueev=pn9nvs!gq&A7+>bV4# zoe_Dxorvm^)xiLfWa!#Vv{umsYkH5sz|A5P$GW+_YQ*=R$lsadKg+ZSuwVS^fB)U% z_x$kldN{vUdIt921k_r$-uk)s)2H40_fE#Q!900OCQ2uYh})Z)ft%BsMQiRPI8qYb zjZ<&*)*)cd2_}%3nFNhyM$DmTWHjQKJU%?I?-!-c<){^GHK$&mgNOsAUJvGRFvh^R z2{VuoT1wPQfM$ZN|4hQp%^@kJCMl!y>zb$ED&K6CVOIsDdqJR9pi#WhVtFgAU(s-- z+ewKVy=f)+IfErI2Qn1Q3zWIap0Qze6SCeK8%ncVAT|NRpEwqz%*??0Efb+{ojy0V zIaqVn7r9q7x-?ysLDX8qo969jXiwjm!L*=xV{03Z?i-_~5&#)N+cvbCKO_>~RlV}W zD)Ydy`YsKpKBjuhYg_eMymn|f*0n1AX*)qChIqGHm5~Hd!;bqBVm-a|7$8tYI93%J-%>)j?5>;&lU7ea*!fb7lrPw1RWC zRUgU_Yv4wt9BPm{i2-W2#;wX!s^e0Skcq~osjpXbzRonN|wO5~f+x7SQ^#Mw5#&XqC-@0!i37`ucNINn&oL8j%P|NlQGvmDp zf5puH@!xuU_xOps=d}E1dZu41{o$Yb3+~$5?%VF}wl9Kz@v_hFeEm2-`nYG`hh|l0 zhRv9aA%He!y0Bb<{Go{biq1wR8Iufw^_)Xdc>*V~EO3t;-ev;+0{V%`n=Bce%0elp%>keM8Zvd{DzlBGkytkU{T`sZqkc%{p$crab-?)0_BkeU1{ znM8(=8z9p|)8N2rs-|J?*Fc8~)c49jn;{JES)g%7F-`VnR(ax!qTpsu281V3Nb|}g zWY;Le5zN8rxn%+oJt-E8*Qxek$cDYdKHHM$yv!Zem6@r?JL{ zkwo!veWU6Yt#Pd+3h_LmE-`3NABL`vnV#K3H8D%bnTcn5b0dv=+&;O%4`=dEGwqiw z@{;gNf9>zRbNt>fK0DrjE%XfRzX`~C^WOW*Q}5sD-M=F|UbfzvKkTKEV<+apF$YH`gp_B_!G76!e0gydEoK! zHQJlL($@_wjB^|uyN*kNz4;DHsTfv*$IPUpxhW#eE%s}~ehFMvJOP34l>|aWCY{TT)vp8i0Qg7WNWxdk(xDiO_3pB+$y!b zdAk}|xgt>kY~`%KEVLPwR0z z2Df_L?t1@~I`XvC+ZCBm4D!GNOABl>@+~*M+$QgA*n0#1i-dmy?AM#0>6xDCUz+~V zAN%v(wstz5+9&VtPe0f<|H|Xz_Qx4hM&dz5fmwhtBuF?8A zO^(^6&vIf}z&r+-ftx^m+9U(CUP^L{+y~8}d147#^?oO3!wt0hyB4+u7HSg6PXQNq z$q$k!Ovjnmi zuxgD=dHvl~uV#+Cn-YKq^wu#e@CzKr!M-2t`%b15;MVHp3#-+FxSt3Pq~yvO}BJ=3p-{?JeTg|=<|d^+`y-M=_}&;9-Odm$N1#s z7=6E_AK^A9%!I^=NFOs8BQ>Y~m|8HeBKEOXp-+HYgq28e!%}a*6KI8Z$z!QZ$t=k) z(UN1CK}^6v0S{%`nNG`Yn4w4%wS-kzT|~h8bi^ z|HzS$dUhSlOx9L!wnvPM|>e&e{owYLe zwl0SP30Az(wQ6I4oGjI#^^EoGM7CvXhBu?3=)1e-#~(8gKvw+|2v@e`ww;PEMyC4c zS{c-?OzA`H7$^9RgP>>jR$QByUKn7cCD_jdse&FwGpa+WNMMR z1S+UtsDD>|TSeb9rN3KKcEEBFByw8JaR9d+3oc)4OVyWpSYXiA4Rb+lWwBi}-V8g!(POW$IkdCurQ7EQ*;_Rcv#&x0>_48~G6M zwMgFXX%|{PRFTj0tDt9K{|!#vn|I&dI=A!pb@$JQ&sWLOG6xyM<{ajfg0U5a4OzS# zggfR<9#deym=?9$F96(~?>L<{=G20Bm&+qD23CNQ8I0u!NC~%?hd@mV+#iP)$kTP2 z3$4iPEjqh|I9Nf0`FdR%1risCn9iD9VDQuvet>YbJR9F?oP|)nbtE} z?=?4EN}%_SH)rOcnV|)2Cfk#A{s=iCqAA6GDVAo+P>_dO3U1prY1~K*qi-Ac?uNIdlotS| zI$Qk>8XsWSdu9aV2of1OnC{izOX;z6*j3pW?W&*@NpZY&wG{-UU1Q8pMhNbz6F`lb zIb|g-#RkfnF4a}<*HwEvmh>Dp$-ejnN>3>tkg~q3A zN=M(cjp0;g0b!);T>$ZzH$G1(S=Z={>a#w@{U=wh>x(Z>XqCQ(`kS=MeDlcD>ppnT zhtvD-ORU~TaoP+!w!e&X)s`_4~GoA>T_=TraW{fpD*UcNki1*H*jr zJ2AXfWZqpi$&>TccWXv7qvMR3_|&=zb2^{^N+h^9`l(|`hc4X+;&8FyO0wTTYt{s$ zW4<&M5HN;7>7t0>7|P&q7ysofC@)ZP?5TaK_UHo|77^k(Bv|9r%Z@XuPIcjmV5jN{ z$ru99p!I!7C!4ZUGRx5sT3k|r8;z?QH?A#wgKqUR%)!w;=BZ#_D2+d(G-s%ta=7T` z2$kUm7W$^?7;qa<>t`krCNnefF$r_ct(1?sCFnOC6+B?y-S1(xIxI9Z@xbF$qX0c|N6 zGs7^HO4o1`FmsbYb95}xGsZC>jka~R?L_k?;T%ctnp@`P;8m9dC7J=5WD1Vytbnzd zaXOuV`min zbM;3Y2ba7M9x|k2f~#K)^>+aCKn%aN94OUv?Y~@yxkk@JJ?Lm`ka=C0CD2%crFm}m zrK#Kqa8KN&^kpQOu1jAwT#XID713~-`kGa=o~b$hajiE=87E~>xr{hV8LYi+m@ADj z5b$55ev@Hjrtz_yQdh^7In;IQ+i;q@oGDGw{WP=+e+#fFU|;<%rs}>cgMr&S_Vnl) zng4S1v}9wI{4b_o*>hG&Pp`iHU2kPQ|28g20fHc#JEsWy7AJpaOZx|D{F5~PAs{d2 zGdza-Zcy@jU4JY4M!g)( z*8;NwCaH|L1wL!PV$7tgn(5l(7y`6ewpHmeO*4@G%QV#7L{r!tH^jpx+sbeH2RqTMmh`ZK~bo4q4f4UOKDVoTz^8&Z#wg%GNQPSkx1$of%*xX6hbLIbuyf z8d~s8GJn~Y1Mnab2AG?^4S1^Es!vrv6ls?^ zOQ3p+ce2&UBqQ0&At2{Zr@3)D89h&WM@CJLs5+>>%67gz{QB4Wwa%^j7sMV&)EVB#16qpHB{r0KTy5Y?~L-%`x#k5>VzV0*2Oag0eoU#0PZ+wZ& zwie*@AV|3CdZ=I-9``?H@ud*APWq+9!ZFg_A7 zPZ6VyacTSh!2bA}8MD+^3AD^>bH~@> zGZIV!L646QT=v&o9v|2rAGN6797wqWNTCBPCBRi!--Lf1EyXB-cvWgHz;5-ujxA-h z?gN8FO55{E`4T*4(AviNd`EY`O*JS03Q~4U$&h7agao32o?}uPX4*g2eF1ckBGG+v zs;K>$A>oRm@vU`w*DKkYAj+I&Tp;D?E?72GnFVHAxxcTi?h5Sn*4g?-c(7k~_TxfM z&CS2^zd9izAyqdsV{02P?_cm}^7NliXSUO+>aTkZBSR_hnSnQro#qXvlvyNkOf21kXhqLEEN>+flpH@X{b+rXU`les0^>5Q4`5UH_~CO#T9map}> zjd$wznuek3>bmC2EYZ6lC%^=nX}5$(#1C}ujnqys5{)DMt?~SRdjH+;zs4y3y^n6! z>531#=Kb{kvOkPgi}C|y-T=K(fdw;9%ZS9LWjEu_lh1VHCo}mU5BTT*)#K~qC+}V? z`~I1p>6xC;AO5MoXxnL{ZQZxldh6}2^IiXrw?1Z?6=;Fxl8W7&HBWx#Am@ObU=z0hOXLVmGG))0 zfmMor=7g9EB!r%)$ZE;=&?`T3Vj#Jki6h{&f(FtXDR~T12&Fe9o(&9^99{b0rmKwQ zd>2ZrV(O2jgXCzCthWk_N}|;@r3YJU*x6{Nedt$&-3-iSt6+u!-sNDHqd>IU^Hgdt zoo43bOf58rE?H|HjN@RGUT(e9N(aGO%r=-)Q~1_3iyv}8m-D&G9Fdr#;6dBSGVppQR%CzcN@p(>T1-W3ArvfwOps4=^(A_X( zOPJ|zLws3$%uLK=1NDCEQ@65*5+cC8#%ztjOo*B2D%oda1ebj$ZR3Q~o5{XrFpe9K zKU`yfkTe#>vzu)MP;FWK#JG(MjiL7+&Abl94^VPDul6QmfV&Y^2{*{nNHY&IENwHm z$MRF|e4#u4!wmaha9(HQv5I}Be+ha9_TNDC@BbhFh`GSGyS1}>`tasFmN13Cd`^|6?4cb zP^+qIn==8sZQIC59v)wFd3?>~@sVS{pzZCHru2R>WG0}u{=*D2Sc~Ne%okv^noI2E zQ7(lcP~_#9P_$bq^#+;pNEVob8=z}Vd%(YV@shV*zNEK)OCQfvIVqvuTBC1TXivgi zEx9VpL`tnB-qlEH4k*1YTf-vQkDW1<<)AeTRQ~BC=L#sLolJ%SA%kdLXXY>!sc?5r zrxROE8+gC5U>Fg>zVDF9cG_?&fVtX-#>6}ZxY1kZ<;#~C#(wPNRJ4EFPK=mnzhN0n z;yqY`rHruFn&$YYkux#VlmzwV0`?QSKxv}3Ns-I*uXgAd80pFo(RE;&R4JbHO^%n| z(e{Zl-qsjix=gE91m!%(+7%V+y0SWXr^Rmr>(J zWGBRAA_5XQLEKnrf-*;Bpe+TfZ}n3qILq(?Ob(LXlu@$!AR=XenA0qo<|KONjo$bH zXq+sj$fQ}^SGzu(-aP)ns}is`?tlL^@2|OzqueMYFmX|NipMUl8{M-Ba z{KYZi`@iS$_ju^;HCNQmF0T zT4e#~dqzSz3t~<%XWKfhZETy-$6(ZX1xXs2#u%N;zB9^!)7-%t$K^&42{D~*$Gw6CuG+HX0oxG>-wwxVTOhJV~oJ5@QA9IkAnyOhg!|fS2TJIF-J(Kf8btKXFPw`Ay56WIJmqP~7 zuvqPV!XxqTeQbL|>wE;b;SogYv81_E3OP+{Bz3Hr`5hLY+MFK<&;JSdYNn09@%P_7 ze)kVQr{w?3&@-_AO-w)apZ;4`g4mn2=HA@RTl03_+WC|B+siMU+v!JR#upwQUw`^x zJiK)|9`E;g*)ID-+mA=v_Xo%1F_S=c*5WY&zXFlb8eWQkT&Zyr05=n;FCis?JcyWR zb=IVXGv`js;PvbG7<()Z%v}t#!6-Lmu7$ zoTY%5v7l#5_)~4@zR_Lt+aiL;$IF#x?gH~}iteAbQ?+kJ`xX5MDJFqEwY9ZQZ|Xa> zr-NAuTc zx?7V{zea#G2GSq{NaTd5=Pe_Jgs>!LFbS;sbB=_Tcp72B48zSx3!=(t?lfzF(i>Nl z0dowlM!`%u%*^aMMPwNu1}p>d>3^7ECgTDVvkb1&DjXo?q@mO$b{qR;AJ<*FKkK6P zOQc^nTIbh&w_l5%{{3bt>(^?W-45vhkRNy=yuX|er%V<3VRXAc!C=iV3=K5P%q<~1 z_N_*K$+5o^@QeS|<@NZ<^K;bxnZB{;fA>>=-p#C;nPW+YrIk1ai3T7dQ?uYQ`7?j~ z55Dm>zMuZhKmM2Ov~8`Q`uTJ|y*h9Gt@B;~miznj_ub!}zI-~Lf2eKkyB;3n6Ysnp zFMsKs$NRV6-P_}3*kzxL5gw7(lzU~t73j*8>~;tAB752SnF*>SSrdBQz!*3KY!VDI zCP7>QzXL|;i4qQ$Q97mS--`!n@|z+Kw!~s^2E?Twpd*ErM{(?ZgvT# z+Fi?)7`p16Ww%JDE!#qT%B*gxXNiACBAcxD&bD=oB*tLs0y&7EtPcdTe=-yE+LCSC zFch^GFs^`s6}YE>-dtIQ;>F64%gdp5o3qw`ahJYJ#MT8&SF~OrUHu-t)xcC+BZA&R zEB9}joE?d~UF!pIjCR${tu?GUk%mpkT8Pe58G-8_b+POlQqL3#m_usYy^vj}ECii* zD}Fjy-Dd_G4?3nTb#6`e;7o{`QY**W;-1EuX}H!H1dUH!VfN%x_f*q9jI3_= z2m+(IhBlepHMdU@@q@kb3p4pgX8F1)5wTw2XZn@UGqC?nLVxT({Wndjp_#dR!`!{~ z?)|Q{_OkcwW%vHFwe3}J{iCPt{Mp|74@SlhJzgHa^WBHHKlQLb++U7|Hu7j=9yZ3s z_sfOIi8p~oOwm$#u_ta$_FxXjOkgvSr+bWvS$Rf*7?XOvS?O$ZEhY2E3Y91Z|V=UR$c z($g^RPIug$?{IU*Jh)tTF8jg%kG+3uwrxr7`>2H$EAN?A!wl zUtSnP0yU8^*!EopZ7fMp#`($RO{eW6*k!?NR7OOSkTQhNOau(`GFVx7lcW$w#f-${ zj0lJa5t2Y@uu!Nlr9CK$6oOHAr}bLjOftdK$tCs8fx0(>zTlsU-tv%`HTG>2o;2aI zhejhj3=+eegEu^qK`EJLD0N>rWG1}U_Kb%^A_MW5y505%1>A_s59$zy3e{UmYnjlQ+E?c3X@=j|&` zPy4r?pDsVS@BLf*zJJ%e{WEj&lSj0V-@mu#ckf64hrjdEzW;+`d-pQ!HsCh!S!wul zBr`5%1Nd;*F(u5G9N1=Zd&m@nhr8&-GtDo8nPf%*xO+ccWgPN1m-YBv|os zvk&A&Yh~P$kU`5vkXVGSsjIV?Np2{8e`TSG>A5$oRixGob0qubAX0KtqpmdiAvk*v zw$`CQQqx0@ouR;m%UG79!3kv5xtFzw4DvZA4TICT4$W6paEI1%>UbJMnj<+QLBIH~O&AtO9U z`c}?=0-Yz3m^oG|<(zAqNP-z|>gyO<#F#1IY8bV+iSSi*epFfXCk6bDXYNjK(vb?% zXZvQFzZYz=bxqf;z>+nr$ImLOKFD{X`(|O8Zsu8O5ETADq3^RIQ{XNK8NPUAQ5 zy#BBMPd|u1^ZNR`AG^F7_Wvc8zxFr(Eo;`Bo401(-CH;FOSk@}d4Jnm|72_X*L&N) z+FSo}Z~cqr{snLT3Gj{U?d6--@$!{-yHm)Xbce*0#H)c$HnwX6% ztqVl#kvgD5LZv*UX6RJ?Vs+t*I1z=5k%&(wfQrYF216F5-_U>s>Gn1 z8049H-xRUmno#xRWoD3Kq${O~fFL-%=l)@Pd*9i1rQW}J^OmQlC-!ZpZ#$VfOmDO^ zPfJX%cL}k@I6sHA7)#hX?#b;okTXDnCoMI$NJ!Isx{O_SXU$J zu1Gir=1Pt4eZx_DR+NVvVBC~azV_{Jo8GZ{yPaAMzO zn9qpH^avoqr98>RHXNgS8TNqQ6+CI)=$jlfnaNBEx)#CAz`fDC95|?F;S~}bkAF2T zkfIa>Fmp;;kem*USZ!#rG9)nPl=s}sF_%zVs3f@cGT5bXxj8dJ*j`R1^QQJ7-(J$Qs|2r+&`B+-Yf|0ag(nEqc7;mS|+vT~B1;8OQ;UCP*!M66`*| z2+I2R!?J#V`nrl*{&e~56#z8k8dF`U?<-iW{I-qEI(S49phIu09pzJouk8Z){;3RH=5x6CZf(MY;GWs2~|Ja#h zFpzv&hRoV)pP57q@%+*o%#gz~flPE#y{?^%(^$5U+Q@`VJOf+%;EONg{$O~k4>eF6 zY4wwcZ@c!JtE>saMvq=Gm}JXA!kIv7Do~7Ry;b10I8vdH_72S z<+OQpYMW`!S-*RCk`1qI2z>+0I0iIN0Oo{g1;q%#)vV^3jD$K97c&DCyn)1A&J-gt zgIEm$u4w^@n~Zv8je;Q=3|f108N@b&dAl((@h*o|rc(8_ZsmB&WX$=X!!6lu97iyx zONR-q^*Xmf&Z-3cPa#>2MR=3BekG(STM}?@cyl?@Tso0OVw4_X=$fXbvi`1;TE_^% zN9(O(fLHxYh{Pj_IrF^d2!{j14I`qP^Rb!zWV8G!H~YV**>AhQ%I4osc{S|+fXjbh z`{dney?cA^zJGD=+qZh#zutWNsCoaWS^Glw{#DGsYVeiJ`~-NL5zoiCJj3kS)r8;1FiIXO09+r+e-BcSVg2G5I_nUEIdhb|mSEO||P@ z(f;1iiS0Z4wzFR@JU_kR>FJrvexbP&V={(}@$2m>*dSOumM8;J9ctb(pj01B^AAO3 zW#A>mecI!wGYLuuXp%99Kp#LT5g{Iv%S;C8z) zjv=Q)-?SeL$T?ATNbB6X950y=@u5PfbVGT$YmoXkr4mNUNw6aH)+Cg5pr6K*nP5w~ zF=33El$UDL%;_DVGA58?C7}#`u;%n~j$}fYMuEGc`ilAsFCwQDA~zbHX3ivVQyZQ& zkNRkKrNsD3SA?Rfbywpy!zi3jO2CU&-Hb593E{OSP?3lQ!v)2K!S_+zYpn9&bJVZT z)?00@a{mUY|3B{`s;$DA$EVCFnt8aIP?{B=9z}uv{HyZNt{(Hu2**6q+%rEm_+CrC zH7)0r$wFJNDC=O^6wN?87ex!vG3 z9skEIuZH~}K>4eG<5#WW*1R`2zie&$(%$!P?Az0KE^Yr_Z~HIh_Huh^x8v&9ac$Sz)o#a?h~Y`<;Mh#k#2~{YtdVKIJ>lF>oxOV&vCwZ)6kDIn&|a@8VJgGEnods7@ajihFBV`Jjt{40(jt`ReFm(XqA*jlI8-uTP@#AUy*UoJdd6sf;lp4eLFc2g7^#0Y2H z4ML?1KaA0qfgC#EB~l01nHVu-&C!wNt?Rnqh?%^+OfrIIO4VQQkG<>{bogIX8vi|| zFf(W-qVF(*_VfEh++a?Hug%L`)+`qcRXQf3ScdYu>#$az$FC4sMlV`YYAovD{mQ^(1_1aBAtKqx-G|07H^}^sVNd_N>&y55<;&BDlX@+$ z<-erz>;L1w>-*N8o}b#cKY6?V3vZscKh>K5@re0Tx9j{$W?qiTHX|(($Gh2tV;oQY z#wUH>!aZ{9?eHGMlB4x@HTRdj+k3E=<2bk;$J2=Uc1%7V5pN?~H|x!A#t1wxGIvHM zk=Pi)yO+Vcm%;TqToFZS=ORhb`dxMv4Hv&Q#Lr35e0P()cG$bq%_QSOGF?v72^qSM zq${YsIi}+HQThq`t8SN!C?03)n(CP)83CW-y>POx^NJ$bE_t!)Td^d4)ib8Qy8mG# z>zYL2;`xrE(&F8%+CQcdb8;Lvdh1-aGMiM8aVPwcgTE4IK^$kVJAu?sF;=#0=>Q)u6C- z;qS!Vw4IKEbz$Ga;UG9h;>Re5hLbMi{kRQo_1fd*1Ubg!Hk8qrnSvX4y)#1X^j3P^ zspFvg`5@18;j;7>%n>Fn8Zfk7MDUt3iHiL9NJ<5vnimKRS}TLSrn+!lKXk9T*2W5S zg5z1`EO`zV;2|a73WR2m(n0`l#_qG`O`D)KXv#auZI1PU0x0Qe}d(&{f)n1 z&BWrG`%`cI3zxQk>(ZZp;j-<2%)Nat$#36|>o<;Z{e;Zj-0JMha4@j6V~&=FH+Ryp z5jUT4wU^_aUvDoq<{)yo42M!&aS5jfGPE*qFw9Cg7URGmN%ViJ zt@;lja|w7ctR*N{dymwvTMpa}8aEmCW{TD;QZEKi+6TLn-aLQAzHjulVXfgMxNgWZ4xB0LiatCTMg@b`blR*A7u3Oe8rkxo*TIB~8K=g% zj50Gj4GcpHP48XNYnKy4`_c5?`qdXeYmT`SL@6U6PxsW=y!LuoW9!bG1}Q;l&BV|X zata^1clQ0FeefpFuo?7T@Ncu)GZYC|M1HN;aU6`fgqixj-E=tMm{Z>SuKnWXGKc~6 zmV|Lez~_`RNRb}F4r-0b^8|bnGKFtvgna$gRU&k5z)~(uh$2t-seB4!%}R;zhPmdb z$VMY_l55R!DKqzVGdH!3&<}yS`j%3q2#XXa31rcU)%s(mN$TRg{UuFNdr)gwm8Asg z`#FZFOa)84wZco(*6IV!=hiP_ug3Lw{r=GXdqM4?{$pF9x>aobw)NwK+w0O}FYEWG zNAtO**6`CsGt!+^A20m`LK7tNbv*2r|5lRVxXJs?~2-QA;iPj6kjdlS+W z)xC|`GBF(#vX$ZB7AgK??tplBM(}cd;fL>Dc>i+qn-0t4%uY*0V*wE|5*H84oJ0mz zeA_bFdSkon`rDj+Yi!N19E@W!0+f+8$()!cZi%b_^%o>m|0`+g(POA>c zurn*;4#@$~#l?@;XUTsM4_-E-_`WGBT=yy1orZs1Uwqss`BVH}!>T^ru&Fk;-qE3Q ziU?;S9RiU2gUo=+cymX=0-8>(N4i6+HZoI@<_xWMwGneNjzKV?=IXsGM3LhA-WnTd zUZ}WBFEJN7*7V3sonRkHn$y<VV`lzSG3U45-`;)gHm;xC#_f6L?3uJ}+lV=w47@e0xkUs)U}kQv^q-N#j^oOl zhtHTqD2ggF1u^YP!u29711N!Db`qQZKB)H(l$iu%5q3&YFQfH?PZ?#8Dd;CtqWb!P zBuiMQ)pL1r1qs{x=WI8jdZW7zrrY)l&reT${P8Dz{PrWUj426y*JFf;E^Rrl}awh#(JB8=A4-XiA8{EbiH@TV$39)Z}h$q zk({T;o3mA#x-~_E`*wfNeWXmZAh}*|$N?e{9k)ZUEn(GKQwq2lV-EIh=X$$h2A9i) z%f5pda~#0LZKpLI4Cmg6OpfCwrOcbs(A~*#5H+tQ&?U%jWWuFi{(q|}JkRCI6QpCR06 z%~{(fGGP?$Ns09P+Xmc$T+L{_XIUfgb(_Tns@J;uSU!Et&_b-XJ}l?V?18_mOP~6_ z?%$t*#2~YvC-|)ztKND}FuRZcyuM&TVgg8{nP+B8^2v=a89aYDqSx|T{@}~6{`$XX zd$YDRK6?AyzW2%7_Gh*h|JwEC`U^AKmm|3xBR6O!rt2hWBp6PnAtxm^B8kLi1m?7v zo;IUJN{$DRX*N@G)@Wq92Zrh(9VE22D=`%WPPyF@+LO)COwRnL;!;6Q4jQlDl zt3vWZk0^QzX8JC9@3=2HR@lM4GOZWRm$tDwLlM%KICBu;6x%JN8 zJD}xuHweK*pEZy~yfIh@49k#rTHiFc>O2#a^$e#>MY_kBl4NF${aMEAn!f?ojcD2{ zuPHZ{k-y|_0%J~&8GzHeVRJH5>(ZOf)d9&aWe^7Lovk(MEa1W&=~?dJu1?L?Ts5Dl zr7rX$v&QC>tWQWItqkZ)B%{@TR2x<*p8@FxB$DNL1xh0$Y{7}7-mLBayt%I z)P7E7biJR%H?g`cbbTE|2VeZj+7YoNI|T|xK|L>P(Y zpEV8{`bLCkKC^lVs3Row+eB}P)}c4`p}F7dt>-@|5BDF}X$H7rccm&B=C~^1nC(Ws zapT#H_SnyB`Q6K_VgHY*{QBQ0gTA$=&9_gswtb;_|9JEM#l7v{-faIR3;SosxP5!( z{OESPeDrd>|L8hj_G2Cj9|K$Hb!#!FwI-u(DW;fVo?=jQ`i#MdK_c&~Qjdyoi$j?u zlz~@GkQDQvJ|9qwK_(}CraYW7!68CMF_bV$^(O;O-be{m#0BnyS9huJhT~{lW}!+5_KvXU4>vPK>?Psr8r3Mf02Gu!zupw$|wT zhL6si18TkzdiHiZa5J6OU+5KUl3oY$HRpPLIivn7(<9Jayp)9iJOW$_10c8-!0y*{ zy}8%#AVP4{wh+O`knnR?M4~rkN(4a~r{TUcL2q2{5xFC8lUUl=C4K zopQ>x{ZJO2LJ8u+<2AN5pAXP56CUa%jY0>dM52*pR{IF{`scBsd(lkpAC;(I3u5c9 zN+QK*Np{^?>v8XA-C1KayN_bEw*Ef$^x1On`?0T2kLlCjEg`GV$F|KXD(7Zy{$v?n zcjJ>V98LbUyp})E^5_22zh_%B@15L&4J`2t@!MI^-E< z&7jt65*W=lyfwUaMar8T>V`wSVi?j1~W5`#$C*QsYs<_SnIlzt*b z1t957XY@$sD&>CPH|eaX+c~B-_M7ImdQc0RU!t>>D7l`CrY*6;A$|08hTyj5qhOEf zc5j$3T9&-i9BZDbxy77Bu5%C`CQps2VDtcD;0|Ze;-^a0tuF4DlO>N`aLkwv7FYu> zwq(t{5z*6lYt9#$yv4FxEyKOV*Ycyvt6~3-SpLdi{}pq0cUs@Py}k6O?>zPApWWN` zC3nAUZTp&;|4c^y|@`C1^5Xqc_>k&$YYVKwR z?pR9b&X@#&1Q|$+O-|$9IGL_alohj+ph>`r@E^(pS4*h&#H>KXy$n*wyFt6!OnLQw zB=xDv$(SVU#H`$9K&>dV{?jvRQNP#q4;Wp2PgnhWDtSfzUEJh26k*n(B`{;snw$Wa z%LN&f3r6?yD3n)P{0DVv!iuDBY+J!CC9u!e3t~isQl>+x?U@NzW7~F~pPn_lbIwYY z%uKdT<5H@>PWRpS3+oJl2su@T%h7PV-N=i^n3f#l;Q9HP=jUg(O@jV73T`z{H^Xsa zPHw66v8`*aQradK#@hcT;nf&(5+TE1-veAH$}96>;2s5^N)NP^x~4TL3?d7+Sa^0E zgbi>xQ65Vs+_kk@lT@0aTGKWKv#MJ#b$6X%P!SC?Wr+k*2v-D0PblJ{l)EK1O-P(* z9jDe4H{4-n(Pt)ZkO7X1yiCaQA&M0aqqPuj8FC^>nRqOjNrVKe>L4ctCPk?FARqeC zbRNDM;PrRi4CJOy?kbf=mq@AB$mDd(61kI4Lp54En>@>>2t%AftW|F-R&{j%})vild`KJ}k|^Tz*WWB%!v zm*eMOuH!4m;1Xe*bz|GH9V1PKRwxHw^yq*zgQ8-{1dDV#4O1OWmw;rbi@H;lmlHh+ zlHi!NSNJ-3d3WXI<;v}LaNG{&c#O{1;dxUAzM1G(^4)0GX&&_EJnfx*>vUhnHITBF z=D0C$SM5o*V_48V8`k6en2YT4NM<&?iFGy(yz> zMd=lpmJDd6t1K8Qc|!NWSPq7ma)!%DF5iiR9L9HkpII`b1?ya&6Lx4F$50T!TTOqh za)M;vT6M{bH{+TvK2$y(xew6I3%YW z$JD>F*pp-E6n0E-h*XMxpmU9uQ4QcO+%!Wn&IJPuX595l4D~sa4B@hxNgyy=_@~88 zDZ~ZqfMmU20kD$IVCZcCnL5wGPouhGZ>f87HVw>_d9d`xn1Pwj9f}Zs&WPHs0_KS? zT_!c=bpWtoq&Mh~IBYda&Bx7HS$In~6alH8fCrh&rN}j2Y$zVe&O#Vj`h5BQqf8V`ZQIa(K{*TFzkg2<>a#1` z;C8zrWuZ>zjbQUeb9uwH1`g;jm@x(^E0!Rb8QkVUOTBi-yPAeBSCb|al)5P)=`N?j8F_KRRQLm|QAI)tF-(d`Zw;L$ zEG5!flcA1qEs;lF^mCtE8n~@g|GS}l$K(2o6a&#HL`=YItW7wV)SQK%M1niLJK(ft zWc3{eQkJT{tnVjI7XZ)iNm2?BiP1o+{yAo=`GS$_-09Ts1w%nl<(zAkvun<&e5O41 z_nF_HzIm24s@3kNT1e#Ne7Fj@k)=l9m_2*u8(X2G*YaBafXbi!i+|g;X4~HFqo<31 z^UbCGyU8c%!U zvN<{=E=y;Tu{6t&pX1=T-G~?%S$rF|- zgOy_L?XIK92&`IWk|9|CJix(B@=hPECm|iMo1(LE$oVp69RiHeO<8QqIFkVzOrP91NOO8O&CBdu_tqWn z4pV^$Ike?in6a)YNVRPn`+mVpuudfRbOu1vctg@C<|JIOKZ|J|NlM0@cvqPvGl)89 zQK*t6iCG|JS@4Std^rSw)(qoeO@T!7)9auEp(&(_d4@O8O*TKPefZ`DV^F&Z*57YXj}9y z7_D%60#-v#Dj zT7J*+YS{l5D8K$c`&Bph-e}Le?O(g}%gW-*x<(nfc}G_2oVz6J*^NQ!HkiV%ktdTHjBPYl0CKuJrR6=M!z*gv z!5d1&@1&WcC@E1i=0xW_toP<>t<9{ifm;(!#=_ZBnwt8{)cjhy7PdZj!$0Lva+mVD zW{|<0gHh2PGsj#J1Yxh{NUT&!J-hy@os=LmgA_b5{q9QvMgm`SsCjFSj(ZXof(t1e zbwxeo0MTHDpY@v+sYq;-1EDoVGZsxR7%nOVtcwi1>|xU1I^ zsw^p~e$<1a1}ZY{AIrM8{xt+6JFngULe01SRk=U^SnshIA3pK>Dfc#43w1?P{GbT( z>1Nh4@)_&`j~e7_c`g5B%fI;-|9$I?ZQK0KzWFClyMN{B(!ST7KR%B5?#p$4_2oLB z=VUW)=4OEVoQa(KG6=kN+~sU-ElG?-M#n53D*QJv18c0vp;0H@lWwteeSx*%5YfnjGEtvTtanpTRc~=)Ac2D z%w)i7U8Dn;3C4>XnUy?^BxeHR-+4h0#(K!?iK00p0d zjpR$|5W35h)k&Md^Z+I{4!}+$Q;vLaSK7Ci+?D<*iK4z_)JleGdw^uA^bBQpC{SW{ zkN!sl-4{#+FK=3dG4Fp5NczeS90Y%gm!)k6VkJ

c!)>&q08A@c4GPY`-dXqjyJ*## zzz(TuFcwNBm%9TQFsHA_1}kbH>!B-61ljdp_4qT>pG=o!O2q66s8T{fh${A?_A>c? zPJhny*|7g4d0zHQ>^eGjqxO8 zmXYA{E@Qz%!1v1oan0aL&1@40I#1Zc8bz>#Msm*6UgCzU%FNK~!Gmqv*=6|VbeMRR z+6iC*7{IpO`0(LN8>V4Hr>ZE-6jun78v&VSay|ppo7*UgZQOWyc_rtGcYZxM-`?<1 zG=*Y#fx&ozC|+t+?Y{+b_R<+djU{Q5DK!%p~S4ovrW|g0cj)kGd{? z0^lLMcrH*j3jL7gmCXgRm`5)QJF^YeW%yaHKQ@i?$I)odpY3vL+acb7l=(5zb#IL- z36vfjYeHd-j0M~E$N#AUKM7)NjBP{1hB+i&M$|fpT(&C!E#qIZP8D|Ij}Wtsx>aRS z)J*P~aND`<8=~+jJH<>N|3}N2aOqb8Lj#8E8q*PTk`1E!-8uyXNQ@yO(ne3~3lEvt zMfN1jv-2hs8`B7C8EESrA-Q}hNE|*7mW^}fwU3fzm>{7BEM3Mk$ChTBh5N*PEXr%$NZg)6D3;U1lL4#0{e}p?;&yd;fuQRvmFcaMZ?!t!EZQG{lno)J581Fx+1P!k_~X z5$t<#>wT8bGay~>0-1hCBiM#%Sn@sO->%u81?Kvx=)7R_0@IQE3v3fSz0hA*K0vu} z{^Ow%0ATuR`%H?@F z*Cnu!artvP)I2K*iSxLd;Y}M?umo1RJ=%Jve{fE3*0z{fm1oV*Ho9jE&N0H9swK?h zVBSwg4Th2+7_|2`ix54leuFHII$I%Gec*H{IBA)-?>646irekRzTc?kYE{MC+Z*S3 za6j+(4AB;5GJ^-uurQl58N*8xZZ9{^^W^?^=bLXo@{-AZ+j)KY0C?&F@%$_lD9TCCo=#6427D-l8>0|di>z-tq zh6>}tj-JJ7tpwOuUeCI2`FT~7XcZ**2pcN^l8t+*6^)rp+IUx=n6Pa`cxL^W)3Zlc z8;$dA`26}hy=D?%ufoa(w3bX}mmMzuf(_HROMIk7H>P1b1Zv@;X?x{~G0=$KyvSps zk#?20Xl21}2v?sQXOG;zp@!>`)SvbH{nPJD4PqzfUl6Ra-e0dWA1^-F_&yb_D)sfJ z@II2by5f4{)4bm;AK=2&yL8RCd~*N!`hDA1TD5*!`y)NK2)O9_`_p^uNrEZ@<&b7o zeGB!i^m+2(FMBedf~u@yRz%e{H1|XEIOcqNJ2;QyLuUTuxSv0Hdz&xc-jA2Jw>duE z(;-a?oipRiWM*+rm`PAJVxcItqTR`|!NhE%!?I@1jyRGiI^29_M^sHav5z!wPQSMd zNia_v5yS|#eQ>+AjNS$@#$_Nap1=5!>D<>5Vj#e3ov@s@o0o_liKwvMf?K znrm$4>E0A&jW1bXS3&DBB4}IJLw?=32SXyB{$nx5Hk!8K*)Ch0%nvHKtEd3RNGn3;yIq!~M=-#5h z#;ki6JFkr*t4p0D!x?d%!q3+PgJozT1%tTqxO)TPwjIZT^=03ubpubxcrxcWPR{9w zl%iUH0q>CnlZ_H8f*?7PGC0a|Tlp|HRu3cv( z&)nZ`H`Xliv*NJdc5+URIZ==J<#ZSr_I=yUm=j{gWe`@uJS|kmumFU$cFmiyt!KyK zwdxTscvik=htspNnaSJRN8XM%96~70X#;x+d2m17ZZEheisL-5O$=`@H!_otA3t)x zccg;s5LiYi!m~i_B(Wl7r^XnD3yinIYxyOy?;EeLABga5y8^OlVU;T^RI991Wm*v4 zPk&2hs#R%v5@cFwInTrN)KX#flfMNR-#I5a9DZNrikDL3_twXB4vE5bNEUo6zlEp; z?ep4t&qkfCl&*3u%&i#uw;e^EJvU9sZ7d6S)8BITT%*u+cE9u;q?Tfx9_=eKA8$*I z=&lQlYq!FWWFY9N0{4y4>Ri|Fr~GmqhRx5fj6ax+AD8iI?yk7MAAG}f`~0k-`jyfH zL+k2?-&{5P*kp(r-%o#kY+7$Uzx`w2x%&J&^*{Q%azzvfs*Zx6m-IEQ?tV^xdDDOJ z2meO>cmDqWUgo7)K1aSbNnc9(z0C7pIo^(+zTM{+=j3H3x8tbscAw*%rSmlJbVOZh zruj4Vpu>W9JQJ)pfUoVC_GcL#U}NJr`%L&Y`p>g2o^(LCESs0*rs@{G3OddLex#26$+O|OZ!;b|UStCIdG zR-MMjtVyMBp2xxc?T%;iqxG|s1&cP z{N8#;DJqJkhh;i~;?k?8^{~~bb56YPjb}&q-I0VN0`!-*F_}1(oxaW&fh*g$c`BmuV*w zNX~C~-JWf;p}wB^+t&hWl~tzK5vB#}!)?^-AxB-VpHqH+P39<8p{?s=p`p%~6z$-z z9!Gw_+K5jy{u{_SZS;Z|0kwNgJ&mRiXoC?pxcA-9a(2<;k{kUQe2l`I=dD@#73TNM_aud8C$0U*}+t*c(vER&q$N=@7Eldtpo<$J4qUwvO%z*x|KU#{=o z`6M;Yibs3?qSJFN#@qL&Dojs5kRHALNXh&AizF6?u6uga`&@;h4FbP$QuRkAzGf{n z{ha>NC(9QQ#0Y)4Z~ALv)PFT+{*4r0jcwaYA*FO2Zvivz_dCZ-ss?68LG>8#Kfq%g zEg4$XBeWJDwt;q~f-3XY^E@wJJttK5(QOus4RfI|-;c0izdbpT&4+FDM>N031~7Q$ zavK{-ah<@@umYGrIe8SovyoI)9zfl;=TTJUQKsQ|JUhD8)82LI5Z#FNl^-kK^V#h~gx^cGJ zWy288(~g&Y_Xc~Jo^;rEJ22?Bi1JA?+s^Cj2e!?VCm-M5xZkZi2)EU8!?;xAGUrLw zKyfm*jko)q+rATk!8IdCS)Os2wR{~%=2WP-dtH_I?MElN8i?9+uG<(I1Wd-j_s-41?TBH8|{pM zZ4*-Kx6`mft^deP=<(Xuoh8ew1p3l#l$iGmWh_>ru5WZ-FIc(CZlInVLksSF5}E=7 z(Z2Twg+qOsQE<_06Sknl+76;HBT+$CQUVLBW^-E1x;L*W3)<04<0?f0 z%n;yF=Ng1p)d&izlA1n?d<+{y8iVNBY}7{M`_itFhiowKw;P3!e7wq9lkC~=L8XmD z$4DrprutgDUSd3-HD37a;if_R&V&c!a_MtaXUn75?^K@rnpuKfDm(Fup1~ z8SeKx_cxy*5AZT>D1!OX#($PQ_R+HsK390N!y$~P6wpiZwb8Az{a|bVbjnOKC9fSY9~aY@-l=ggRI~-!8~rq8i)P}JE<}! zGmD{sDo3rT1z}agXSgJx&EFy6^<$<9hkUwktCl+Cx+BymET~p}R))ebVVIU$_G!9s zf0ew_RnybGNAB;Y_xT=b*yHzl`!6DWA4DrHR6N)JJ!tw)`aXE8KcC+Fvy$t0s>!rn z<*Bi668^ZPuZ#MuoctQ3fARu3o=d4?03^byu zP*}chw-@I9q%tT1MH1Cc!KLAr$5TfHFtd%7vSBpWGPP>mp_zh}{$<2Be=Xl9v-w?J zXLxTTK;|in-|U->%1|MSO7Gv2RXB1G94hZ9tATmtGHk9H>*jq$H7s`e&Y3ohdQgRE z*Z}NY2BENikyWsH9lXY1>^{DYf~rJHB9?L0*N72eLfsvGF_#Q z6W0Ci=v2w{my`2ta=$;q@GA?(uuf7?>3XYN769q6{4sj$No>O~kASI#3w6FO2N9b+~Nm4|Fwmo9|LZvUph}Q~Ul)7crhBOqCcNATI z>%d2xn8{FPc$Z==3)1IxR{mR1kMX=1niY2We~75Tz82tsg}8GdnW;k$_ReFcwg?Sk z1UZv)T3H~=3_QX+&PUh~lrDy!GqH&bAS!eXPS*@$8*o|?k%HT8Ko)sE&s_SwZ440D z6Kf^poF}zyuniP}cf~)coDM6zA4I}d>#W&6TCS|5IHCZg7F1;e)$I;)29;*=kIjHa z<2jAH{@iXiVhrBi-uU?O+b(|zAumnX+{=b8&&*?8b2^i9N+2Xfv`}k`k^ph%0QWN5wZ~$A1p)qo7yY`Ba4CYBx ziLoWK#BxsBvkwl{FY~_XO-XZFUV7Hp{Qcs?RZzVzOWN20diL2oR{*l|9xW>*SUcX^ zr~z$B7+Fn zx53_L&8r^z$QX6CNwN{-&sYdBPtGK>m!9?eS<9?|h{4pPNOBgHg_KC%FK5I?rsb{W z{tfFJMU@ThlCH^#IUh!*6o7h@RvrvQHm2t+-&>Xv&s@YtQk9oD9=Pu+6BMoUHS*mf zNG;F$o@I#JofGcIN$e+k+*q=x3XGP*bP{ZMc^#FUWnD9?sF@%yA6()6fIGF}b+v|P zfndDZm|t>!(V_DWLjCfh;m+sZ_jDcxPrj{dv2DYVEtO0U;5?aGmK%n^kW5C9?dX=zWWvXC};PJnX{;{T6l{P<2A)zSz9@lPKx29IgX7v!`>|d3uc$I1T=tT18F@2Vb8NXI9d{4qzKQ5raG@XSkdpGjo8wjox#5vzmEM?)N+MIH;Ew#t3E`msTD;OHtF_&Jkvo zAV{}6Gf~+P-P#L!H1k@@k^7*yjhh)d_Ou^|&zT?5-q&y$=kSJY0N;N5tqtZ7FE1~b z=QhH|@_C+o{CKdu&-=Es@4G{?POt5E_ar$TM)vmc&T)9Q{+uV26_Dt5LnX0CtQdGRR$E({NoifLajCig4znC@LHYU`4Lq z3!xDx1`0vJtdqpTbJ6_uS9;V}7_SA@w*+1qA}b=7*BuL}Dm=!jctj&u*!t~<0`O3T z`&wEccr2^E;p@52?`xQwA1s{kDF6Mv=d|wY`u9Gq7CyL!zx{VT^PNxMeU!d(U&TE= z`-@CZ)xEoZ{-*rhr10*Y3+_%!pL@RlX`W}yJSRau@LLJYqW(Cm{+PnyKcCaDMN*)# z>-F}s{r-&5$NppXtC=Fpg#nv!O0p*B=}?!!z*PHV`((MfkV8 zgl!CPM4M%yWJ7Mr{mhf|^z6Q25LIFx31grRi8k(S98v`cM5D+gMeN>!m9! z*$ZID%>&aiT;cxQHlKR5zxY%n?^h9^V1)NgurtW??J?|006~}2RRNS$-1989rf+Ce z2}sB^UCk3JdwdUchKe;{|H>S3}dbO8@3RXoCi$H z>y!_)U|qD}x+%!%KAc_Zh!q7;R2Bn@(xBK1^dJ2vAN8;Q*Ipa?&*@i9pAGv@QpAW6 z<8{RNQZa5qgJjHehCe5nGYSIrKn?JEcThl06Z2AtivlgS(D|-`zNj8E)e)H4J8#uG zztcv2&NU>~AODam?5o1VQP@abq1eGTYBRw{OiYtV#25tbGtZnjpJ6q;#&;{ebbqMF zxvbRrvIGKPIi(;ZMiR^Zn;{uD14%_dW1PKUD6!R0U1NRJ}?3QNhp3dhzGh^LgiInCj&YJg$q>32kQYFZ=GG5-t<2+B+2{GB4 z@NWBV2t&`ejbm5-3S*Td?ik^j2!;Ct`$WBW*kx z4ls|7o;Wy9^IWMN+gF~JJ@Tw`R^p9*Eo)Z3f6fU6QALc! z`vqzP%SD20Kq;2NyB<97RaHIX?>+~&bK5q~w9l~cyK}a#DC5hU$r|=CY?x-Iqu$aH z4-JUnqxm>?kT_B?(bBuU+HTP+RbwD41?1yf)bG!MEHeL7J+)iS(bDk&2v)mbK ztaKkYz2r2m7tS4WZwHXa$ikWN^Uiqgdye8*5itdl$4#Yax{48a$*OGZucPTAM2z5e z+jx0>VcU1~M6(ePu`#BjGL0)dT#bARw{0|R@9@jxxAEs2SvH`(@uHuPA@&UvFdC^P zK=>SbZ?!~bx&DIVEQjZ(4fqm-#I5U#fM=8iE|2i@qBE+muLu->+4}0@R-eB!q>)j5~usC zu;B{yT7AR2W-E&Ru4L9pgczGQzbUMsyxrdnb1MuMh)ow+X!l*J$XQgG@uLAGGKrCM zavr9^BAGL|pI&cvdwF52jWHZfS!Knk%F8O;@!~N?8t1rQ){IffcM&Ko)Uu{=g(XA+ zGaIfdW+t1=zLHuy=JdzASX*Jz5Ym9N%iY{hg~y47y`wEgSP_6$ zmSVLFN_eae`2poH(`ueUU~%U$T|hQ|x|h1nmYV$x47IBchmQ^ z%YD&zrG>XC_$G`0tfW6d`aEO*YnHNVX7N^474Smkmr_Vlsx*;J7fFoR&`o5DH>O2C zLTcmtBC5j1hz*rx(1Y5zG?iu+RGLTE!?0g;O^-|@9tM|{>7p$&%)=Cz zhjpG6!YkQm7|}ep2TMeNAQ0Nb5nc}WK6wxtW``%w^CZuw{dmH$CR`txLkImBOMB?m-ag#>jWL`XpfEaZXu$_gmuOsWGB=%9OZD~ z1k0ylwb2-h(fV9(idO}#!XY_AV$R0XklR{~t1hqby7}`cGW}kJKk83}K=9(3G7@;B zV8WU}$%Hu}6LJ>Ykad(WzE)a47rY2>2Hr45JX)Q|x*5(FqhSHYc)+=m@qV?h6iUIY zNn+ddvtj?|OrH(==cG`?_PWLPQ)&D*)K>{#lz3I>79mxopaf+`){Mic$ZY1|;t(x7 zS_%pvw4$lsrOKoRc<1)b2CoDZA%|0+V>n;e`AqjqP(%cx=P?UVnQ>(`a|y;6%x1VN zOe%)gXkCHKFu@zK zR1p#6oE-O)^L{{?F;^z@Og_GSWFH%(@Nsw!Gn?~{_YgSQ!pG&j@M<9zMb@BB<7cgv z+O~~--`Mw^F$VW}=Q!U0xb^J(GLX;nAU_(n7Tjj`Zf|fLcd9-T&9#p6z#A)0yq3;q z){il~iQZmh`AEH)C--}ixsfDe+ZaGr&)8(5u;|M<&4|nQEIup{+}Ad_YQbKUSrebr zn~c#oD{ta=o~I4?uu|Ze5-~KqWV9fsXXSJCod${`@KOQq?(Fv~y&e!1B{8Ru72NlY zZGXXg5CDWj_RB3Wy$NW=f&z-@U3ihlR3Wn4lI4*6Ng)d4cV|x4&iU0eg#-b#;1L$m z3Wvqf1F=QFugfryh6X%)fbY5-HEdN7v{P@D?K0OGw;(LC6?(V#(QYW@VbOK_Wkb=0 z(9cSbN-i zKaOA`zr#CyDVl=OnOmU>gI0*Aly_ z4R=1;)Hqp!EUr-2w@~w)tIzuJg&UXSWe#+D;7zjLBy6N+T8D7NW#da? zU|fVmm8gWwVh`(Qv2CCt3nGnU*JN0-u2WDgt)=Jc`VJW%RsN{Pa53SyhUzHh*Uk~ zmjcs$7{YTxO^7JAUbWiIfLeHZe75aTeq})jN0`v~cG>-tIUjT@9xz7u<|emS1%>O5 za9K9;x%y|7S6t_` zi3cO2%-rn-^?*E&KGtjuJamh(`6!#Jf;K=_J%wins;XxzH`Jl*U}orWdwb+n#mntR z?Ou0&fBTm6G;_F&!c0`2jn2~{dFTCL-VZn(J5=fLL}qbtz$`+8q0Pc$1bG%`PUby1 zB*qwgeEVqT5)S4F#MugLM82I=!JMAa-?q)4*m-?@C1yvUP&>q~#h(9_ z`^*l8$#JYFuCEIB!&z*@Mz;mEXV){U6(cJ)5##Y5$=)~}+lEx89Sloh_>bexoG0U) zyu7>uLJHnK7Gv}AI~G13OS2`iXKA`$0C1mVVHyuCIVikDqL}F=8XkKOBik`)?oyB0 zzW9OkjMGvu0_gD`fE_I!>!y`}YCa%66jG0JB7#}j0=ZCC`xyjsU##}|SjxVp$1=E{ zPm)V_T5r5hE}4deD$r6>-oMeH^)siH^Z90hb?2v4ZpOcq^xURDEj{O1zkjuN-veJy zpYKl(#Rjg#WqJM_?nm?`R&*?8^%Hlka`o%f(>zR3uj0&of{9&MCzvu)`6|f4uzYWS(}K&ejd=K<&}_%!6uCXkJFwHL_)zlsv;7V;Oc3VHxF( zW1A;6Z#40?qK;VlOpJ%lky(t<4&ShIpd^Yi)rUuc1ic6a5Lt!SE5n+_Q|m0&iSnA5 zaOitMJ@`1Nd1x0&fh-HWCyouTF;?5lJUIey259_98_Oi}(l0xxmu__NRLM9NUZS9u zJ!O7w@Txxz5{5l9S*HrQ?;K&UQk1C?cM(==S9YO6@gf6*m#`(i)R? zM67#DM+DPdlOP_CE+d-evOLk?{c@c#doLjh3gbMh$Q;bA*fztEY4i&Si8=gRf-0B^ z_dW_wRymx1_xo~<%%VL~fZ*uR`*ZqxCBHAW&CWD%Jt24*;^o$LcR3*#L!761L4ozr zH0%;6AP3;NAad1d)8JiqtmQNXl;=mOgc7Q%C>Z6I0=eFPYQg99tEA6{eW(BVfBe5t zC`M>}F=G22p)W<=irQu#9`{iiBf^3*tk0(jl_uWBJgQ8R9?XjwSx}>8aM&0M)}Vjn z8^ebD@>W)PaF5}m+E%Di#PBTdwlU`k=gF+ugI*V0AcyxA%yYKT3SM4bai~=iSx`%9 zD9RwZuJd4K8}t$Q7#TrX$Y(mVZcZEZ`?hnt-I`&+d3YVV)B-XmYo@(2$@Ap69~^IQ zFq7WI053n7b^siwH`NINCsjdp8|Q542INeBnP2mEzq7T#88PgQ>~(_xS;_r)L$tCY zGxl$KSNs?Q8;M>!=e3U~udlBb%;}KsecQO*cA&%JwayfteEj&4w>L)u0A0r9et+XQ zeeS*2Y?+tE6^YQV+LcRrDF0cCR)J|kuD|ej zFiilGX<^$?N6{=AvPb)&ye$Q~s>gN}mQ#V9Gw#>K(hTG}!pe!Iv+VU=T|rT0DJd{+ zuH<_j>-A{c_0(wx zpUS-PdV5e|b z1cY`Q26K`T)}g|i-@r~uVrWFVcrjq z@oXn}kLc#<5#S?N3wY>fc4By=yi7bx&Y;S8UpNFIwF5p|4ptG{PISA$`jY{6CohM> zk}++_nMP z8)HU<>kB)gZaa3!4cJzh-NZ~!VXx-MNOYl3pJzwQ!2D(=%vn(VdcPL|iPpyS0BnMN z7!IjX2t5|N3p;OOe5`8;Z@38U+;B4dre$aJCxSKC!lLU!RFwx3-j!*6KBpg_J{$I( zB4R|0FGAz@M{IwC&{tG#Nsg+FV;-7wh6&Sy_d&2S0SYsR>e*~KQ$h@Z1}wLkkvo-Al#z74N4j_^iz$KjCdObY`Kcr&@0ZIsSrp3_c; z^CU_HP&27B8D&rLc|t{b7x@e-^__R9BqgpR%rao%L^|z?~*U64db!_ zjH3pKAVzY#xxHYc-0fJ3S7P~KMt8rz@$usu3JX*yA8U8q0f=~|$~)2D?|0tbKDs|% zify+tHP%|SX&ixR!^#hgr6`p9`aDl&hy7QTXF__$qA-kA^J3uYKazMHAJi$!%QMP- zzHli#Gf$X;C^L7{xRujwY$!H@q?)#CSlLm}E(k|>SV52#giIm|%H_FU3)rNtk3$CS zY^j1mP^LS3`>n8CyWTdOH14`(RDoon>K?*laE(K(w4`gWV2f6u8XtuP>GSxN93mRw z$eGo5DK8g!PD!CGXzw*VOYR`xsUQ5P8lG~?{?ueBoqi~9x#ds4{rBkZ>@6(^&n&+B+sMdEaYmLG!exKI$b9v9#@4ih)kDe1HNWsqw{;x>? z1>S7laK+)hc4!Lr&`)n(aH>slAj^sIKS4+RCQnVu7IDW=`71+tK z`V+?LMA3a{;1>#4Th{kXRPFB9EQ6vY+;#bD0#GP-jA*swRPXf(}Wsa8*YxoBAtL?vjjHO)GTV6~0b zW5P&~fR;K>$ccrMT4h)7f8;Vm>tXf41J!-eu)EJ(Z%CBA1W<)%|9j?Mtq(l)*ZOw- z)|WRJq`*5Lr0pUIfLEG@u4X`RDZK zNS_UR;D7cX{!ca7_AU0`-N*hnCH>V>eVNpD%zK=9*S8tK&+p+2PpE7f8$N=UL$L!tZ61c*gZO8RJA6FdRlynbat6npPHU=lyUfa|CAaN#%ru zZQr~ho_zlJ+BnWL&|Vi`S#0|YuP?8T0+_usylluOHiZ`BSR*#8sChC^M+MC3_?u8G zGPIEFhLwuUX(q`M%58+sZJyAaw3)*tr=9wp2B93WD&B0 z67ev)-|ioIJ3jK&Pkzc6!M^YAhxD%VtFMY;9tW?xLm8K0zdX?vs{T|Z_v6mn$2Y$D z=48jTEQY^fY<4o^U zU@qPGS7D>KT#c-71ayBuC?NcJ&cwQ?pMl$&r1yRpgV+XJSV^)1mw3&jckEwl_z);W z&SJD;R9VbpGImEesPMayL{m&vku|CGvzbYTX?JWJ6}p@o4`EY)JYk(lR-$Q}>I6aq zF({Huu$;C+1GHl4-)nqTHSJR#3pG)}tV!nNoTuvn>_~He(`8vGTG6QOWnwVItvzVf}R({_E$DkDr(>u^tWl zSv%tYD(TbrpKFBG;vc?V_uz-`uiwv~=lk&8cRxkxTEs+E54)Nae>98#M}>YahhKb7 zzeedF|GR&u{(Jwt-_-Q7;1)4%sRCpl|Dm<_f9`&tN)_`uW<>Ym8xA2s`(yuw%TOZy6{QWPu_X3}W=`a@gUi z=t#9#y0xG@`&XqlG@Acs^M&=hiYgoPx0~gJs2nCpdXBw?trEMEB=zQ*GiYctb;VF$>|&F8qEb3*5nzS3i+S$1DW@q)j4=Df`HR|{9Ftm{(YC`3;#7~e6%x?hKp z&&+mC;5wdQaf?g`QGV{6k0e@#$vF11jveW=u3GM!Yva78!6lb2dX?L|K1$QO_dv20 zxv*1QUE=GqLq*{SF7v{qT`aO=EFy@sM2ZM#Jg9a=K`3Erh&hpZo& z?(76v{iZPfz_@i?rU!}EH9RS!6@p*JFIXROJG)sJ2MZ0Am>vo;9md~iBNI#%&TX9( zW)(A?KhyPHN!BtF9)>&4Gqc!AC|XaF%W&O(-8g&{=X(52iHL&46FhJ=O(~nJ`4SPTlp@^5E?RP`lUl;l-S^4ETkK37t&Uue>-gVAH=XvOy zN7#G2)*s^$fQYdMxtW7xAq#7uSO|j!o&oSXW+48I@LDe+=yyVXW5i&;-LBcohm%1> zSTMO9EB`if#TdJp|FH96+jhDJY@Fb_WWf#cXly2CA#y^>UfZx&cSMK#r9;uHl6h{_ zzOy`;tBoV9m?(lf^k_FDSZj}GVIj7jmE6X~6iQTrYM?Bf`4}OL6vuOj|fJHw>R&)zd|cdiXAg`H_^uG z+x;W<{68EcU`1f&BxaD^vInJ{~@Ntv|rc95hRfhn>QdQn*xrM6p2*PIAC2VoOTzLC|RDfq}Ukx1mh+o8NP!LR^^9)oBN=}Gb({R-(X!|#s}!g8 zG_PNNr-v8-YVPnJOM=ejvVyu`gZH)k>Ph|imz{p7e}CxyO3$r$hHJqYt3M&v&wx8s z|2g8H0U!VCx6fhtzmBO23N))~&N|MluZj3N(7jX>(c@h}aZaD5exAvB*swp&lcg{h znCH^GNljk?NuZq9h>OMi3;IpK&iHMQmT^Kf&u@6OzQb^tWTQWxK_8=MClOU}rgayU zP?%pO4!fOY{iez=SCyRzX@m84^CW~B5>zIkNwyP$OhQ1*=SoiyWZ5Y{!Z@rdJP}}d zW3&hx_kh~S3gb=DWtN?7is+4g1?AI)xbRXPr6@a&7Y^hZ{i0zR18ChKj9>Q!*ZJs9 z)$k_ZHRKRiKg)z+T$S6m9KczgHQ)E0Oh+y{kMn_zF40Z|f^7_D3MnCqwS>ZTbo;VM zs-2Jtryvqqe={r(coc$kBm#J%$8fsewrzlbc1&%XPgJ6xFI<>5p6j?s!F|>`DNl5o zRn}h`CQ$1J3FT^C&XQ7o&)6}X+ctnT4xHA$at5hKRyHsYrt{gqkuyT`nLdFHWY<;a@K zIiu=~s)=_ePZfm~d_rmlC{e>krWsK7C@_7R?*^XSSyXHK4T-R4fF*D};KYax@3fhW zVc}V21HcB8OOxp9*+!O`&+<+V1sVebk%83 zHd^f^w7{mnD_w`e9`uaCejMbPRGpx;48X?!RKLHNL$+aGgCbt)d=+9~6+Uw!(UUo1&Tf3Yy7G(0Q^YoE@ zF@}{C>=Xc+MvC)vNd8h9mLM(QJP(Q_rkx5FYL{*;P>1cZ&- z=O>k9ij$MUps=C@3(b$h3hWpt)6jA<0NqD}*Oyli9MfwT6>#QBmWU2vTc4TsyhD5b zTbUsXX1f0H7+NsF8XrzoP?_YE+c?T=*gJwi2(pX=CCKeFHTOpW6-|$6TzC0Pfzm4N zo$}Fr(*1G)DZjVg%`CP7Bg|SI1(A4(g-c#VECt3h|8@dMPw@2TxffR|k`;wOiRe5J zSl)lCf0bVbj6z?of6sO6y1U9=xmS5BIcNVaff`pBp8sE^XBfXPt@f^b@7we~Elhrz zBx@i|Aa7Om|19Z02OK8#IsICtzxNORsj7%dwoJx3InP;NOZ6uNzbAN8aVk_g$;_F_V`?r2C@>u zHI56igenMvQjlsMDWL0=Y*<#5WqmFqvw1)k6nGh4!-9E1WwMv^Q$^+MC3}KO<|!&q zI}y|dQ>@=m%_A2KE05WW>-ENgLWmG3yxx0+^?~OB9P-h+mPo#amdz@xw;6UjgX@xI zOD(zdz0P;x{Wy`{*lypx11Q^KF{u3$xAOI=%a>Lb~_sEFjz3r6ySa@z^5O0 zvd8kaIH#2XM-wC}NJMe64Z~InvgnC`?#*sfRXYsm_71Vf=K2d_Z8q5N8D625z1`g? zn)Wa)h<422zI9}x^+qtgnS>l+nr)$~8-7g~A?)mG`j`9PZ7}?m>3%Ly8{%8*=qrV2 ze3xmd``S^RmT*<=DCvH%QwG*Xj{9ck(3y#q)nqyRMX@$EBt(_zA)atV8I6s?Hn8+nZ9T4A)!58;0`0)CHN*kA%hS6u*yA9_&eBI@_`7NkvWkOaIwirx7 z;q&V$tVmJhblEHKq8BjptaGB6F85ud`?`{xb~HFNam|Exe^*gdJ9Mgrxcl}wRV^bs z=@xW*hO;gjt)jZkfCXcTvkWiTz=t4Xk~N{0V7143-v;|_Z=6pGD+&mnLl>j*xQ(!K zf~cI#c#H$U!oN;Rc#nk`7O)XSc*7sJ#R}}284xW<3&1p=)1LgQf-b}FhzQRRjp5yk zr6y$wg@|&W3VZ)0u@vDIHDia;#L+DU)z}Vq$Wk6ca(i%+JAo=ucnsSG;rmW~-Cxbe z{QK$ObEbOt%YRJ)PR}y5TK)5{!1b;Vfcb*w@S@)_*YlkAfr6z3LJ=Nn-<0^zO8OUkKEM9gGZj=3MUA3HX3ja|n^65CLO)0PHsPqO zIWudfBfjo$Cuh%m*{HW+k3{9t8EouCYtBkb-)z1j_1Nxlb;%%^U(@7heW3h&QLH?g zCG)0FL!gl(Z)SlC>jhmFfOoYo%cp*3)uEugTm6V2D1!HVkm@B>(@W{B4<*DP_MLgV zaY$4`MWIY0y!7kkHrTd7)yZ`f7b0SnA4C*m6JvyDO~b~qL+}Shd5@rGaG_w^3fPRD z5Nr0p zJPwNvJV8)pCjaa%Q@1voOC(3hP%@lQA|ZIL@R+ERuCJg(o;@ zT$|2tpUU*$t@5pRda`Oon+iow$+irRXuQsYW#t*K#@9v9_4vJLJ@d^v?r=Y47ArcW z!ut0z?5kF{2x)bOD~bM8nevxxw+s_i(_(hHg{CBE+c77fHVr;-@8UxCNink4(Su zhJ9$n(DpJketRhXx{BW~@(V?7Va`I*ObHWzR%sbhlEQ|74GPntg-tc1?jh3y>XXq# z4}b_ft2dxzBLOpjQ1A%<8iWc2xBZ0(*DAjfKbmMr|XO`gSH`OVOcrJJn;-$;OVAA~W+PtT3kfugj~%1~P7Hb|ab;7s(hdJd?hR)2i}p zLuV?veJ-Fseqz`QM3|l;TBxi_1l5LbI?QY3t;XRz-LF0Z$v7FY94w}>ZQHo*H-tD_ zAZC{<7QDq0@I$=;9Wa$d3@ZvTE~!@n_3yxn#p54XiL!#RoK5aKVLI)+GE#DBd;nG5 z*QTWr!_uw*8fUW5N9DG5e`Z<16&_1bR;o(becw)p{%xMI_(qox1cQ=k$G8Ct#7CaT zy`sf$r>m2JEBCuQ>#8XWQ=oX{6Oeu1`K{K_d5UGi7Xh8qPu&MUKK;;J&#*u4e46{a zx&G|*={uiZyB61UbrJ6WXN=QGk@yDq=TP7Dz0c{_ELA~5&aC_Ws9)ap`evW`RYlAy zzJdBi=wnrWQI+#NX3jI~I8M%lb5@*ZR%VKJ+=0h{ucFGFKiGXP1NE&cj zFDZ(gvqy)o#~9?CRE0NO6$sa{?>qZGI8Vz9(KFj{27(z(!aX}Ky`o8j;Ke*yZ{8#a6gkjg{UeO+67+en%CXkg$8z%mRb^vE zUX6Gre(~0LcRNxZk_xiZMX#^7PqgoZ2=ciPG_QVJeFNEbFG?=nmttxtdIsXkWn2T@23RmG zJeeW|RMUhT-mUCk+3)#{N3s(0{V@GddgOVJ2mf6)!=prh|0-pFe_ACzL%!1YLfzvu zBuG1)s-E&yCB-)h|Dw~UK#jyTl zUDo>w&`uvIE*+@=g{aBZCd)+OB_gy@=%oc?Y)A*^xe;LpdzJf4(HWbzs!ZQY|6S#- zu_MgCJ?YcqEx2T{QQ3{Ff=Xz-l1YW-y(mV22x5fSl&i2zRR43|Em+6!J`W*xS%l$# zrn&wJ@NOJsxn%bn*6U<2&x!fT<5k19kPXmvq8?X`t1BNknjm~{H9hzy0QJ0jqPt% z^4C)5Pm}XDnW{>X84l|{ne&X}ezyTvWyabm0acl)_h2z8uR-C#Z}rf(*Nox_Z$M`T zWP@W3>Sf@CMEEA21)sd#?`Fg@V-hV`hmF$0Glr6&J&9YdiL$Vr*T@2>gyVjAbmR7E zjNaM1XNR+Z7B=-zc0+<%%sV-cJIC9dJPragwte5R2i?cyRhn_C$_PwQmk|WD)(~H8 zfM$fj#r;`ExWl|FMC>=l7*rPXEV9?izrFc5x=bI>w%=|X$BDju(h$J#Iye! z9qiC3G9!+QAqtQclT2z_s757HD=cL}Q)vgo`*1|}uOzm8?JVn7Sz#zBE&*T|jE7m- zJLfypdzSIEgd>GidII9g{+Gz(qUTbd1QPVpj&xtmOa$OO_3SX`9WZcx8@PtDO zO|#)sBRuXPJ0EGN9KyS0^binVdF>=QnV4dWJ!@_xhVh@qR2FDN}!9^t}*=>6Rs0N&hHTJepZGr zDZn%NGyQ>aSJTN{@bQ zo^iE#eXC_bcvD#5I138*YwLDXGF@ag?pL|R(tWCMM}qZ=wBAuwWW%|12Ze|T3Zb#; zwvn!xtciRRvLyZUdNZE`4V>qEo$_!qTNZa_pRn2s}!%``7rcHtfOWRRvmj zkjKrowQ(QDvEfShOFkS78p+Ux_iC`=zV8DBlzUfjiCEL2X?)R9fd^QbqQ1(ieO4-!k#&+a zGjop23~#7*k4(F*%t)G47j;*UB592)z>L7dZwc{2VFquHp$AihcU;#w8Lt+&Ph-@B zZYIb5L?hvLGn4K?dkJfaY{t15@wSYj7HkV@GsgS3BJh`E0s&Lj6jrkyG0X+;YeLz$DAXYWxkfudCGb8SL{Loq3WVL0SS1|c%R z0_cHTMYzs0$w(__WkDXpeVmzYS{9r9X4NFq&WD1let@imZmMhY_d{nX;4xOgQ6>h+ zS*jrVnX{FZb#;GrVQW*$h%n;)hUt#t!6_bfnU>w>$gsc9V@3aQkIwHZ7XF^orF2T} zuPWY!#dSH4Myl^Uf7bKwPk!Pytz3`XYb39`&hta1Jwx_<{VBwcGJiPzS$V#%b*|?D z^E)`LX90^%)&zc8(l@})XK_w=81avZ0m+8Zh(b!s&I!>5+?rO2=l`WdCl*Zk+_la@y3|~l$ZLn7n)29KQr`rk--Jy8k)YS%_r7jvURu2?@AtX=iWV!ATlx4@# z&z2GFx_rN?(0tN8vEyYe{gcG3rU!Xu-+Ja+(iR}QYh7|1--}AtZwauzl$nfr>|vAb z@b?}E?vaPV4G~^O@o--Gk8$5}DxxQ~pjxl2MpulM?X#m1t6C38DAUlw1-Q-N$*8gP z;l^QSxo{KVz5yGP{*`39y;aZBvsk#$RR*T}<$xGowkHWY#DFqgOYKzZwoBH{$L>j^ z5w0Oynl#F(^8IjAsD{ft!{vAL*fxkEOgqN6SbzMraPW)^lYyR`0(I$jSGa!`XW{!@ zpVa+{zh~L-Uj-M9^Ku(HtMSL+VUny*!JPtM^T@pDwwC`y%6YpqrB5CYYNiST_|ICPSL5JF~j z)!x5;e+eZ?s0W+MjNird(C9%W%&e<$zOK)V%uJ{7Og2?yP8-&kIW5MDe8+-JK;dWr zK>#UgCbJCx2ydn`PtS7h`_65@;a%~A+rG1njq|uOy3B3Z-QH*haE#?k6yAw{2XT(g+)^7HX^gJcP(~z52^e z7bo?n1(kDRj#XU7fXYT*73VxH#77WggLC2Cup!el?-NmidG zFb^av0B>&}InRSJ20rsvhAluXxgvs`Zhz+L4iOrRu~Ta0gb2}55RDFZ^ z2+Du;^HF!d*6Ba^gTGV%-GBQJ^E~VAe$1cUkNDXb@h?WyON9PJ(pTFUUyZT9!u>Y0 zW>t!ktsn$di$w#ljOQwlz`QnE?ufO%+DDOzjyZ{zhi9H_Ww|T?=>hs|Bl{koJh;~47BElfGkRZFzuM;?69d!8>$kF zf%~Yaa`eEOVfQ{bEyY@f=UnxghLE6&s);n%hTmVw{n9;CtxtpqmV6QWW_-@+{SMCK z4h7@&)&0`tjDU>CHF&IM8Ncg$wo1@yglp-7By2lKtcjd%0uSdJSmRJSO8H>97)HtGWVbNUt2 zZ=_-W@BeTAT}8y$Vth4X`>za*zg6V#B=tqsyv;ne)KpPHWn@lro-yZ1Wy-sMXH3Y|xl_OLD<-3p^Oj=q5!~kH%*5b55uv)*9w*^NhS(44J&_H+X&Jczbh` zt61yN7Te32-qdDJ3%6=U+pHnbwaE+$Di)_O&PHquhC`Fm9$Z5q&S}Bxez9Q}V;PKt z+kU%*U{N3oI5S^+jTe3wqck99kjC?xu|BVU#Gr!QmP{ME#Zpj;vH1v|TRAdgh2Pm* zZQKCHmE=C0Nv3BoJX38&$*{w<**YkzaqOX=3RVZ{tU(DWMhhh4xDl0N2)D92N zG>a8lXopfU(=g2(jGU+i|CuM}bYFO#|_9t>jNM~3C3vW$}+H6_eC!X>SqfT3Hu7 zjeEq}JD{-g>D2A+{DpC2k!yu&-RYj`Z1x<_?!x;gPw2ev ze_y_J{b@~))MMt8w?2jKJw`B2pRd33J_HYBwaNlq zr{&?&GF(ne0u~>Mi?@10z~vN_XQRz$og~9-hxx{~nO`qs8^8v$^KP5VJkM!^fx?_4RM1@e}wEBI8KOpO*A@^ep6m|w>6*ZfNz|Vo2MW}kh$9Mxg5HY=4ck(mu z3t{@&w_w|L>kgMw-g=yMtwKSU0fi$ZH^I=3PiI)~xkc7tM5cA|)h_?<@nsO9*1lMV zGiTYj2Gb~y_DGhZRc+9xX@A>*r`_MJ-t}I8uX^DcWdKoCk<<(D+X}vvxK;ZgKc`p9TfX*>fa5qo5HY-if>Cdn!{b1hzU?#%J3X)hG8AkvNMN3mu_b$W zX-DRyR-5Je-8aTfUbwlcy!v0V@LSOYl4)l)9dwsAuInLHDZqUN)(SEw%P}HZ=+E9+ z-_C+?_!$u4d+$;KRjVs|?7Yu#IeDs}u!$`zTzz%5d^tuItkwS>sbPP*ekg^{?Oacv zjrWP)UAaxGNiuqM=1Nyd<#F++rB9(->2d!ZLV)Mqet++~R}XCbP+B?Fg+9t@4rEjU zRdO#(N#8)-%MAE)`ZZ5k#jMKnto!|_Uu+|PHpGX3FJkCVr1+he{q_|f#x2Hei}+S= z_fzLNCELNK*;>TZ-vxzv4geuk5EPk~Cyz~Nn>Wck)rN`reE~_KO7r_U5k6ubLIM36tbT$r(SVwBCsfoWXI6jG^6as+!hKHvR`@q=NmnI2+wF;*r8gGtUm+BB zGF9O+U8&0r5h*Hw5?grxqjR2|=gBsL7_Kow%rd;$eF0eCeZtX@9pa{Ps7w;$A)XLq zyc99~UI_PxTwj*UCOl@02RnK~F2M*+O!H4AXZB`riI=Wi&_KaC4=6ha0A5~R`0(Mw zMenO0s{D#V$ldO~amihuXZG1d1RM$T?q?oiMUCz+b^F~cLgMtwiFKO@|EN`bH}lGK zJu5O@hnKe+ca`u-H&gv?!2?zGl)?WWbvi{ANpw~um2QGps(vE$QX>BF|M;!`&VS?c z&iKD-`i(Q}|KNY~Ka|8aBEH&V``t0dZzFz^m9J+Ww`rqZa~{g_?EIOB&g0N|96hs| zu{?8`4)eK~875paa7@e+OV|o4+7T9ni%E{Ld4_)TW*@Xt>^0DXL0ra)hkP?6@Y-WM z=+q-DhP}U8#mA2yEr7$Yj2P`1_ROZBg=%r+$vh9vbg&m857_c(u5MG#aqmr=Nw!tywef_*r= zyELiu6#S>ME`U zvzqBGnkcIK)!teQEuV?H6c;mpuOahW(fzblF=C*wk$Atq*|1~rOf_=293BzDU@*3T zS`LAx&6#Knwz0W?%Su&cX8@{-`~7Y}x*mW7@BF`n6JVxJVJ*S}Ywf3C#6nIR{obEJ zyneV*c+)+A7=t}LyA)wXVMNbdlm&}Ma2q?Z4es|h=5$CU5=5}=H)0#!h)|AJsS^~v zcCYCOJcc5|hUV5X~70$f$F3xdNzP->`St+M+_BX_ymj0q-NuzS|M=9 zx!)3&lxz&TFVd=tY106>4-?9c!OVno*$&xt8!n<$5fxZV>3gg;KBofNG4TFb0om9o zT*m7AqSan>8TVFlO6>rWpIoIaLh=>xtU!J@xt2$I--`FoK5f&2^2elAwg3vMAgtjz zmD_BJaq;CwACSK+bjNPi&*|4Z{jdJv->tv*5B@OEnaBN@UvGn-N9YSheszoS^RdOB zi28|Qyb#(mYrtEar=8&u8lH_N!K!UFpGMXxq?YO6jbR6D*huj+kExcHEZJrw;W3tN zM3`?VKxqR(vGkWR*@kHz^cZYQW0#GPHHOb~qR}H?4wKHbj^+K~)mg!LzYq8tQCazBbSA+m3F0=wSTUd(?+JBa6G9!JmUr)3S6vrAVv z=ZS!^4ML7ad&|ZhwA0=7WQj~MhA?XF6amW?z`Qxy4J!Y+STlVc4?Pg9Qf^9kHBcgHRMp$nVF@p0f zmLYo4ty&IjK-x$I8|BAo-LNW&gso+i`kkDU<9?9oI)+?NQjVfnh^&@ORgihj=3hvW zM}=<}-g~D2%cn7{?^Rk4f?h(}UAWp(WieX7TAJW-Bs^{tWi*|eradNn+Q0};EJ>cw zsVWx+Y@66N(?(`peb~X62-ltR4E{V#-_xW5!Z;k*Ng~TF0c@~GkBe1qxyxIMVFBj`4pUTeaY_?b~E`Tj1n*;x)WB3~43S1lvqpf?7hwbzMqq zKT|WU#lWQ=flEykM64NmL74#$4FVgXV5+BtSYA>K%g{17L0AB-jqeu2f_~nS0#q@} z!eZv+JiS&KEci>{*})|!X~CP!!$L4KDT!~s{v|`=O@rIEF%Wr9=be+BCudIMY4-Z@ zvS-_~_JV5R5oy86Gfs`qGEi=Nl$npLJd6mh-&bdsnOl`Z-f#xISX2wq=b zd3kvuqGyZyU9cdVbM`U>M++F=fGl8wM_*T2cu;2Wi=kiM=rT?1yJr)SVXgAoL$p)X z-rr7=XCk&a@Ek$9O%$Fj_HXy6+qUYJEVx4=VnD(DesIncvJE(Ua!hYkCe0<~3<0_5 zf^xgHTfnV<ocoj(gPU^z_8jtI}l~zfAR$7oer{`8Yr%&^(^xeGA z5H);N9wRg!(`_hB_Z~(e!GpBbBsB6&6ywG&W!uLN^7UnDm;5vKw^Goo)NOVA|ZxIg~Mab3@m>Os=%T< z5NcjT4_*H#pfZt86bTxvsIZY@tqCt^o?jH^aZ7J;YMH60(Nu96M|0+b=i#;43r5jn ztJNkC)B;&%RFxk{)D!;%^TidKA1dZ~avZ^Z3)WhCpG*Rolgy0>^Wx*MgFfd3!H7U( zKvl1)7dk}^FPYnicgz>?c2Cw`11=l35lA-Fq##BTv7Ep`RbKkdw%KW2h$VO;L<}#h ze4Z#e?v@4K&uR5DSZDAuIFpRrhZwI#q4f?TfDPwnAmb`a;G`+Y!PkxAM`6FRNaSYer?^okdHK?+lb({xz+W8dQ&WJ(w zatG0cnP|+Ho0bf{b*o10s>!gWOISMN2rtPwjB8Y!UHg5Wg$*`#I}(t9T`9%bepp?{VZ>4_ln) z5yx@Fd7hD#Z9}x61s1#blha`qIC{_rT8`j=y=3lx&O^R3$1gv@tdx zJ95tH5OsNm{@P%qit|V_T!zb7Fi3;~N_fZilPoj#^E{a~ZA3^tSX)@MTvLfkv5r_H zJFg~*L#FER8R9A{9#p!VX~W(Q2@6fB8A6pq;mhoP8NX}881q=;Zo##Zuo5vw0rn^_ zfm>k*!*Lv(I81Nh%d@+7nn*r&Zol2ww_DHJdwuqK_$*?BS?#Ro{?k(%RE!$b2;k9< zC5*$|)TwD`8TM<9-+4M*eGDsTP^{w%mtrGDhty9iaB5HgD!OqwTIdgL6X}lYiOC`18tYXTuN+z%Fluk{d zR835C#!J!BAFK0aVMf*ehrPf1xo_F>`=HMlRdYSRy-&B@wmY$cz;W6kVC;w}NMLse zLR^3y{sQ10E4knV8ecBHqt<$UzjIEfW15?@f3^4eJ!{Qbvuf0+@m`~98h;_A$1O&BZ{5xskZh!x z2OdCST=O^tD}+~VmLO$A7aJ$Y6h?pocJOYbaZ0#J;d^_v$KwpVr}EJ)>c9Rbf2Vzl|MV2}~nM?$d;>X{N zP}i+!WC>nHd`A&)W}MIEn^1%($Npc>tnZ97ZzJm#5%VR+PZ0Wv9DHjiZZEgvLrEh- z8E-446;+ifMM0^QRW_F6L66p9n@^GOHa^=2d&P9~q-44!upHt^!{*4e^Ac*S+q$^4 ztk2SNp0JLLuwLDA%V4zJ!-VhRzV=FMl^y%{!C^2gd$qUZfTQgTu``(*c;KB33q~Xn zmPH#ERn7t&S5oUh5}A|Zm@Qwe)AniS>)JZp8E`qgiW)$*ERRf7Wj!*Vc2{+K*VVdG zID6tam~-OS4=>=vhrs$Zc55xhC_7nchfj|=?f#?Z32axC+J@_kU>)8ci}@%1A3904 zVeBCHgFFRP&}{&Oh-@0b{njd0TDN2*Ic)zpJ-_?n*wO==^S;XSP4^A{U42~v?Lssj-NvKN zZkH|3`qS5Tc~C~*h{SXS2h_J3{0-{o^6M<$7{~s9`oH@hMMh>u&WOBa=C@G(R8{>J z;3q|Ws8#d4&OFciAQ_^@b)E70_8Rx|&CZA{JfjJ%BxyT>v4D$bFE@5bF~lUu(ChTJLlyTCnCJ3J1}er1hqtj zf3H=nx>zc%@=ChW@Tsj^%Pm=$)jI)NhCjm!MQsdtU$Lcx*7EN%Oqtw6 zvNP%`T_-Gbw*yDOep+ft!gf{?1gm=gx5T-whDS)x)G~?3eC9Ol`@pq1ebzzMqL!8W zLoo%$quL0;xD-9V?byLn@d&7LS{At9RZg3qZCIS!(OxzpB8+RVzB`4`rHA-pQUP4J%Es;c{Jf8#&QiJHkrXsaO|; z>Dz{s$7wv$DQ~^Sp#v!q?k^e^TQVSljV#Z+S3EqA%R@AL5;@Y&ZyBe}TAnu(&vQPZ z)A!QK3S6;`heBwzVF4)I4?v{*dGfs8Y-DSGi*@zgZ_h`ZzMstR21Qn14$5l4b-Mk@Z^9%EChqxoZBYgm5};+}_he|Pz`?)&@Vhu`1VKE3y&O3-M~w%?5J02`y}mLye(1^SBM zyYTrP_TQxPFa6K{fd276@+WFVocB{-W!85_#!C*pjGR8%9JjJG%)$X+5x(S4DxAKZQslvU%=Fj1lj6s-1q{mt{e` zlO3(ccaU|AL@m1mK*?UsHg||CtAmh5iFOX!xd*qsJpwF$**1bY&{>P^88rKWz=ya( zMgfJLLk~{n^Iq0k9EbOU+g5X?8omG;*Rwf5_JgdOlEsCm>wFYbXtvDbeocav`;jw#|mdOtXzGutMl&_l}jP#oZtv_n2~g|S>HYM_ahN{XFgPR7v>9x55dqnHZtKKd z44I!-6-#ZqAnV}Oj_+C^(|}4?7baq{mbmNWXdGq+oPyi3>aecd_}l^VB2YnlStYc+zstIK+yg15nK_$ zINaXqKvtDewU&W0iEmozHv8EY0mglRX)Hq6K8~u98DHk$7E1$9)4S1rF27d!#yIu> zAu`}d;w6bW;HJ_SSFJA<+}_T&+jX7Cd0jy$3FZBM&$qYNyw*LcmX!%scoMA3dw?9_ zGv#jqW~MV?kLIFP9bUr%NLv^ZSdj+DapQ|GzU2OPXGJl?`-~S!gkRZq95=>r6ghM9 z^74VqbVQIO(;1=LX>vr~&goj)>26^tu?_#V3a>WWp{Zp7_fYt~hiJcgM-p~_0x8U? zz2~e1tc&wHS?jVe4Iu3J*SeaWgJ3&HcAo5f1WKoCjT{d+?Z^Z%r?2tEA6UWM?{{>{ zc*tJmMIZ}B@T&1X^*uB2!9@PO$L971$8B<5TX{4t5YEadk0Zkd0X?_vx zWB63vT0W8WI1U>M!v@n{ZLlxoIjXvR9V>IB_n`P|*zr=RR~syJ5qKp&2pQLVe_IfJ zzwx8()b|(^R@9B(Jzq8i%Rz^AkrTF2Ntm8OUB7XfZ6vPheP{Dv4Ab-+lZaj+z=o%) zINweiFF;*hQ5nMlF24%T2&nX`4Cy_WIR~LZVOR`%2Pp)!!DMpsc*4Z(y0|EOO^q8c z%`H6*TeX(8!I}MVA%c;IjTX1&=l8R_ll@f!f+U%dIHMrR3LC-!^s2=U0ub<^|1jQY zno+kc_FU>Q7Mh0xkb)iP3v9gfo&J};y6bE#6p)W6p7%X=uV3t8?l#|--SQ7FqEYhx zT0C3%v^DTE|4GWHZ3M38{xp2Dj@6IgGwJC_J}KSLRQ5d$GTWiXh7>?mP;*${m&knD6)McEZ21TXqP&7A zS)N+lw$52CN2P|VK(>KAes}DB^~oHTdsTk@>RR=Y15)L{yLS7s>~hNTV0PtPuA5Ph zZ4On|8&Z+OughKQ;#!@JwxF_QDKKZUmdDp(7O7av_RpvTBD_)^V7xS-a@~kMb;8*O zVz1zXovpyv)^b3@I8xg(>3PC$e90}f1d)NaJA!GUulHPfdi)~-a@ckh&J5i+8Epd_ zB;l23+fI+h+zJtv|3%NI1QL=16RY>xKfF}Q!5g`cy{K@ltLaIM?q>5rO4iZc(-VYh z8w=tk9PAG-rdS^vr=x8)_gOpw&;%pG_N*M#*!ERp$##9T#s~o8Xm61y$#_q174cKH zQ8NvX@w&L5#;IT12$^A9OdC?C=U)pu+Zb)I@!=t?tNXZhW+hGR#e5Y|GN$_|EjXckP9P4*Jo{=>4rugd({Q)nwsy+HA;>IgWb#Fd-!_8Zx+10z z3jbVwz2zI@*oPvd$RLl1{1A~J2)(RTFV{McOV{nZ?zyx=rHrg7DX!}bX_+bmBA(1_ zMGz1^QM}5j+CCJn?2H1L%@NHy59LBYi-{c>&;CA-34#?q;oZVJh_JAA+Onr_&dKfg zKtwWfGN<=tkKx0$uFI?C*RUWpEEiP{G#IKNb1)Ms<<5RcbgI zF84R)q`rRTJTEeZZ|UK5qirq0`e}-(K5jbH9P{eO-%Ervu`>fTU?k@EA)~ zwUBL^!$BYiPV{gzt*8f=F0RuKy2=LJoK7?J)&(o+J$64^J{+<7#NhB;y}UT}t+bqR zGLn$rA3SPre{h=p(W#8b;p_-#9H$kY1gkCtDD1c^V9tXNFJEvRHxzJRC#QVUt}bs= zI1c0eTqjF5>Ks@YQ26|ZWm-s2A;`1`MxCk4M&Y$C3XFpYZ!3xDlZWMfdkOn^S_zy& z@4g?aJrW?m%08Pew}GB52b6;uP%0D-TH9TYruAY>8}bqH2%hW!p+H{0fXx07uKO?! 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 z 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%0AL$_r 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 + + + diff --git a/deep-sea-stories/packages/web/src/assets/fishjam.svg b/deep-sea-stories/packages/web/src/assets/fishjam.svg new file mode 100644 index 0000000..50b09b2 --- /dev/null +++ b/deep-sea-stories/packages/web/src/assets/fishjam.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/deep-sea-stories/packages/web/src/assets/fonts/JuneExptCurious.otf b/deep-sea-stories/packages/web/src/assets/fonts/JuneExptCurious.otf new file mode 100644 index 0000000000000000000000000000000000000000..7ae074872b956c5ee3e8337a798e31560487612e GIT binary patch literal 131124 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%0DDNioi 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

on)Bd9yxc|H!EHVu;Q_@BZckDcd+su zta$Y74#oJ$dh~3kcW!(KD-*CX0V@-*G65?SurdKFdP`7y-KrAXCUl9tRb};*P-El@ zH43iK*B-a37Jn}M0qK4I^|;v^gtjLsbzDF`hN-^B*u05HtBbadRGe7<55_qt&^m@L+Da8Nt%s5`%jXdHsMHO ze4d&l2B-9O{v>i>l6+5ulkwdnLU$@`-#sGqD?+G_N5@*OC@gOYg%W#$h4yWK(A z@OaUQ&|^e*3Z27uV&zV(+=&&BwCs3WnSzxmSeb$qkFV=^myIb{nSvFKqbm(lurdWJ z9znM=^r*Q;`*Ign?!wAlSh));8naaUGG?jJzTAzKyRqVNM>`ec@_#p0JhEt8csEw2 zinAb`O8Tiv->I-`&{W!isq8ydd45hYZU?3+&yNXRH#OF%Y~6!*9z(=om$ZAt(=2oi zy@xCIdpOqjP{QvKXNTf_g>#Qeol;6kGjF}dh52HbCZ1NI|0PX>Z5nJImC-R)I8AI$ z<7)|x%_v*b#2E=)W~Nc9r|~aonyfgb|GiF=a)--H`~3&|if9BJ>xbzX<(BM0{0 zD8}`4Hn}&OdODkWIvb0#u{c|{>XpXzbhg-^hClj3u(35cD;5 z@wybROYyoCuS@Z|6t7G1x)iTV@wybROYyoCuS+QdrFdP6zoq#5C`ulclKSvbj(!PX}N^FIOq6YxI?!;>&PNt!2NcoK%E*!mP(pJMA%Y<-HY&#?6wjv((`htGJV z1);{l5Z(mp3RhuW0}3^+f>7fs2sN&PP~$2HeaHJ5kEHSR?CjP3^;HP(bsqf7`j zzJz+H``Y6<9nDsuOW<>qvFCJ5+Z6Ws>jl~ezfIhskqX`J`8`>OeWYF{uU=MOIsRH= zG*6Af-y_ZMiSuQ>yJY+ipxfA&Jyw|TkH9|x|188^Y=^&ra3kR+ z!p($tka8!u3v2;3s+ic`1NVaazyn|#co;kiwu2|YgfWbRZna+48z{y>pvHkwcoH}b zoB?XYFvS;xzP5ikd<6V6;auwVTh)ae^<3)pT||G@GtdF$G_)CcgVXET^(9F^|Y_hcg*!nRxN2)o1Urun?KsGIS9ni{c#xX z?wD^A=&G0fbv-=J1!?s7(t)-}Yu7P-_3PVwf}fUu%A3ko&(T%b$Mq8BO`gn8Gj}y7!!8@_ z<5HXYB#%O}OyGS-rh=4?`W`FdN~!4KNTsq8<$_sKF+En=x<2pHJ9OBQ_s$!YNXKU6 z_J#ZP{B~VSa%#VB)^v>5y<>a-VtdBX=-JQdGSljL{WrLJQuhv}_e-u}^0>ySm-EgW4n9{1#sgi4A2WG}ym`-dL zFlDArg;j$U`bJIYPMO>uxV1~CA{Q>bNB6E7fnr#QbSc@)N=J|<-2#KjAyj}saB}FjyqvDqwA>agxi-3 zKB+R^U6Yi`Ez3n)h@M@0Gs%NiwT%9z&ryNf%dUS?OD2svt0vUyDV$W{d{E1kQlqfP zlgjuct*5tpgTqqVOO<{l%Vs>tNvB~=ss4A=bdeHjJO6*5%o39sPP6v%-pB8PW7m^M znWZyTl6vJ+n$hb_mQ1Ue@jdB#$La{0HzPNCZ%^*0CQgPW8<#E;o)%X-&6gsT!Nvu! z&6!&@Anh;p{By-7wQ}C+*4%5?%vz96-77)rhtl^8E_6vgQ*cZW|K7Wz@b@s?$Q2eoA zP~K^$4xi6Eop(C>YjJ(uZ)t2;@JZf}wS9arsPCAtC2MamC}}4clyz@*NuO(CMS11g zH$NDpP=4Q^#EQ(4U6Ng*&_g*t5ATc>WxbO1iZ~i`?$6rWuTM^!66C{LCep-_CdC z97{T!)S1M-KM9|Y6@}0H$fOsiPad!2Ixk<|mZTSLDet#5cqqNZhUNS`bI}}BgMv@= zBxO)|XWoy+#iG5s!?B|H_^em@ZjLwh-5j>$+@D^OUMWAs=)E&_e!H-F(~I}WE62*1 zOYfb%E_+>{jr~68_dybqDK9J)$=GzM>0#^lquhlm>y#yzx!eZ=)f_!D2sHmp&*%FJ zUK8|T>51(f>O-3QgGri4Ca(YMH*1M0?q)4s`|Ui9A81xr-EIE96b7i*O27TN4(tgzMe<|C znIHEK>iJrET65<5X2mDJp6%$a)Hms4Unx(2)yJdz+gp1&UVR|sLGn9ZUX7P^-+@Rj z>Q5m4o+YMmpe1wdu$Rnq4#&jieDgZFSf9h0pKosKNuS=Pr`suhuf1fZ$<}N^nakCp zzgov7&~leNOD;an>F{@TyfwR@d>yW1etY+#UGy0XoA>^=f6SX+y!TkF43MQueXdby z85B&_H;Mj-&_~~keXhxfyfbjA9H|;INulI-WH3xw{Kr8U`x9;383gLbF)?fihQ?kA z#>C`N?4{t^SecIPXTi|$2bzc6_qsk%&)&ym^|ZnspX@WO-{|U$_0fIhFM_LM>aVQu z#Mqw){bHko>tmXCChQQ8dNw%h^z3t;?tA~9wq2)Xb1*LJ>Yy<8f|h%Oak1=RKo+UEgn*Hwku=>f6vO0UutyFVz1{VcgX>ocwO z#3ZICH|WV1&j+%buYRf<72Y8~R(1Vr_|N+NnYhceZy#;nt3^-AVwdUn1eL{eN}JR5 zTiJFG`ob*bm*Ydt{uAz3I9ux{^t(J58LrW9^=b_NHJF<9hr!gCY{oQmaoD0XZV!GX zuCWU1UUzricWL|oQ9em0+xKXH-K~#(t+eXB6IM!x>zY2{39Zj4@71>|bvz1uk2}z4 z(6Rrn{oK#TW3;T)_FIzsDz6K}dxINTZw>~M-_G+3maGcJ`4~9=GZymS$3Q)oHR8{| z#Qvb`x9scuzhKdGumZ(paSVJM(u;fxb=NZ1Up&t5i!51F6|ZAJ{`(lD7UzFzDG1JW zor~$NeRux*7-TLgqxzlaW6*2yG1w>jT2rQE{~K%hP8qn=+GSJx_^)!}JhH~$xpp~r zS-RBP$6-P+B&KH}u?b!0mCt?UZ-1>vXgyr(0jb~QgMPD)?b3dM@>6vq%+fJQ)(`54 z%c<*1dadUk{0^(U?mDCRejG!U<8Q2=7Vlui>)1MPFI;C!Pu4SvSDkaY|HfMN&~?G} z@uF+hQR+#rb=Uu;toXRO%zTTr>o;}G_1niaUC&k5bW93d=hADJZI>^XP0B}FTS|lT zFWp83zYXHSlUnpHz23)-E5GC6)vkT|{kxY-rc3L+aP2zLU4}A!ahd%h2(ms@y-%-y zDEhCptWq29_Wv_2YQr^_Cm(T*iFtOdw=_@RTS2JpL&Luda}cL=F-V}QOEtSl;{6Z z+JC4;=MtYsd=8;q|9!=+QaY9GtnaGK`5dFRMZ*zlD`npyX4$cd%(l<}n23Hs6>8v|i;d_F66z}V|ykJ@| zP4V9irYrn#@UY@%=$jYJ3}!06NZ-6*mcF@~=cHKS*_!PmN29!#DEwE!e-r+7@IMsu zKZBph`kdfz6!VzAS;5o6;|jm3Z=Oc=*cjx64=Ts=!v7ln@Y%fZZ^A!UDSR&csbZej z|A(CLh46*T^1>Ix7q7|-UkYE+G5%YfRdT}rrDth*;aokP$`1cN{CkCe9{yY@{~`Pb arTj(s3&pGqS3VnrtHagL23`6D!T$r$WAl*! literal 0 HcmV?d00001 diff --git a/deep-sea-stories/packages/web/src/assets/github.svg b/deep-sea-stories/packages/web/src/assets/github.svg new file mode 100644 index 0000000..e0810b6 --- /dev/null +++ b/deep-sea-stories/packages/web/src/assets/github.svg @@ -0,0 +1,4 @@ + + GitHub + + diff --git a/deep-sea-stories/packages/web/src/components/AgentPanel.tsx b/deep-sea-stories/packages/web/src/components/AgentPanel.tsx new file mode 100644 index 0000000..7f68896 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/AgentPanel.tsx @@ -0,0 +1,93 @@ +import { LogIn, type LucideIcon, MessageSquare } from 'lucide-react'; +import type { FC, PropsWithChildren } from 'react'; +import blob from '@/assets/blob.png'; +import { ScrollArea } from './ui/scroll-area'; + +interface BaseEvent { + type: string; + timestamp: number; +} + +interface JoinEvent extends BaseEvent { + type: 'join'; + name: string; +} + +interface TranscriptionEvent extends BaseEvent { + type: 'transcription'; + text: string; +} + +type AgentPanelEvent = JoinEvent | TranscriptionEvent; + +type PanelEventProps = { + icon: LucideIcon; + timestamp: number; +}; + +const PanelEvent: FC> = ({ + icon: Icon, + children, + timestamp, +}) => ( +

+); + +const renderEvent = (event: AgentPanelEvent) => { + switch (event.type) { + case 'join': + return ( + +
+ {event.name} + has joined the game +
+
+ ); + case 'transcription': + return ( + +
Storyteller
+
+

{event.text}

+
+
+ ); + } +}; + +const AgentPanel = () => { + const events: AgentPanelEvent[] = [ + { + type: 'join', + name: 'Gordon', + timestamp: Date.now(), + }, + { + type: 'transcription', + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed laoreet, dui quis tempus varius, ex ipsum suscipit ipsum, sed varius nunc arcu in lorem.', + timestamp: Date.now() + 1000 * 60 * 7, + }, + ]; + + return ( +
+ agent-visualizer + + {events.map(renderEvent)} + +
+ ); +}; + +export default AgentPanel; diff --git a/deep-sea-stories/packages/web/src/components/CopyButton.tsx b/deep-sea-stories/packages/web/src/components/CopyButton.tsx new file mode 100644 index 0000000..8953693 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/CopyButton.tsx @@ -0,0 +1,33 @@ +import { Copy } from 'lucide-react'; +import type React from 'react'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; + +export type CopyButtonProps = { + value: string; + onCopy: () => void; +} & React.ComponentProps; + +export default function CopyButton({ + value, + onCopy, + children, + className, + ...buttonProps +}: CopyButtonProps) { + const copyToClipboard = () => { + navigator.clipboard.writeText(value); + onCopy(); + }; + + return ( + + ); +} diff --git a/deep-sea-stories/packages/web/src/components/DeviceSelect.tsx b/deep-sea-stories/packages/web/src/components/DeviceSelect.tsx new file mode 100644 index 0000000..4fdfa52 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/DeviceSelect.tsx @@ -0,0 +1,54 @@ +import type { DeviceItem } from '@fishjam-cloud/react-client'; +import type { FC, PropsWithChildren } from 'react'; + +import { Label } from './ui/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from './ui/select'; + +type DeviceSelectProps = { + placeholder: string; + devices: DeviceItem[]; + onSelectDevice: (deviceId: string) => void; + defaultDevice: DeviceItem | null; +}; + +export const DeviceSelect: FC> = ({ + placeholder, + devices, + onSelectDevice, + defaultDevice, + children, +}) => { + const filteredDevices = devices.filter( + (device, idx) => + devices.findIndex(({ deviceId }) => deviceId === device.deviceId) === idx, + ); + + if (!filteredDevices.length) { + return ; + } + + return ( + + ); +}; diff --git a/deep-sea-stories/packages/web/src/components/Footer.tsx b/deep-sea-stories/packages/web/src/components/Footer.tsx new file mode 100644 index 0000000..bd06928 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/Footer.tsx @@ -0,0 +1,31 @@ +import type { FC } from 'react'; +import elevenlabs from '@/assets/elevenlabs.svg'; +import fishjam from '@/assets/fishjam.svg'; +import HowItWorks from './HowItWorks'; +import HowToPlay from './HowToPlay'; +import Icon from './Icon'; +import LinkButton from './LinkButton'; + +const Footer: FC = () => { + return ( +
+
+

Created with

+ + Fishjam + + + + ElevenLabs + + +
+
+ + +
+
+ ); +}; + +export default Footer; diff --git a/deep-sea-stories/packages/web/src/components/HowItWorks.tsx b/deep-sea-stories/packages/web/src/components/HowItWorks.tsx new file mode 100644 index 0000000..311b257 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/HowItWorks.tsx @@ -0,0 +1,47 @@ +import type { FC } from 'react'; +import { Button, type ButtonProps } from './ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTrigger, +} from './ui/dialog'; + +const HowItWorks: FC = ({ variant, ...props }) => ( + + + + + + + How to play Deep Sea Stories? + + +

+ “Deep Sea Stories” are a loose adaptation of the well-known game + called “Dark Stories”. With the help of an AI agent and room you can + play together with your friends fully online. +

+

+ Choose one of four predefined scenarios that will circle around sea + stories and listen the background of it, giving you some clues and + directions to find the real reason and perpetrator of the event. Then, + you can ask questions and get “yes” or “no” responses from the + Storyteller that will be your only way to gather more clues. +

+

+ If you are ready to guess the story and win the game, say out loud + “I’m guessing now...” and say your deduced reasons. If you are right, + Storyteller is going to stop the game and congratulate you. If you + missed something, Storyteller is going to continue the game and let + you ask more questions. +

+
+
+
+); + +export default HowItWorks; diff --git a/deep-sea-stories/packages/web/src/components/HowToPlay.tsx b/deep-sea-stories/packages/web/src/components/HowToPlay.tsx new file mode 100644 index 0000000..750145b --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/HowToPlay.tsx @@ -0,0 +1,47 @@ +import type { FC } from 'react'; +import { Button, type ButtonProps } from './ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTrigger, +} from './ui/dialog'; + +const HowToPlay: FC = ({ variant, ...props }) => ( + + + + + + + How to play Deep Sea Stories? + + +

+ “Deep Sea Stories” are a loose adaptation of the well-known game + called “Dark Stories”. With the help of an AI agent and room you can + play together with your friends fully online. +

+

+ Choose one of four predefined scenarios that will circle around sea + stories and listen the background of it, giving you some clues and + directions to find the real reason and perpetrator of the event. Then, + you can ask questions and get “yes” or “no” responses from the + Storyteller that will be your only way to gather more clues. +

+

+ If you are ready to guess the story and win the game, say out loud + “I’m guessing now...” and say your deduced reasons. If you are right, + Storyteller is going to stop the game and congratulate you. If you + missed something, Storyteller is going to continue the game and let + you ask more questions. +

+
+
+
+); + +export default HowToPlay; diff --git a/deep-sea-stories/packages/web/src/components/Icon.tsx b/deep-sea-stories/packages/web/src/components/Icon.tsx new file mode 100644 index 0000000..dac4f9d --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/Icon.tsx @@ -0,0 +1,12 @@ +import type { FC } from 'react'; + +export type IconProps = { + img: string; + alt: string; +}; + +const Icon: FC = ({ img, alt }) => ( + {alt} +); + +export default Icon; diff --git a/deep-sea-stories/packages/web/src/components/LinkButton.tsx b/deep-sea-stories/packages/web/src/components/LinkButton.tsx new file mode 100644 index 0000000..76d9d87 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/LinkButton.tsx @@ -0,0 +1,21 @@ +import type { FC, PropsWithChildren } from 'react'; +import { Link } from 'react-router'; +import { Button, type ButtonProps } from './ui/button'; + +type LinkButtonProps = { + to: string; + newTab?: boolean; +} & ButtonProps; + +const LinkButton: FC> = ({ + to, + newTab, + children, + ...props +}) => ( + + + +); + +export default LinkButton; diff --git a/deep-sea-stories/packages/web/src/components/PeerTile.tsx b/deep-sea-stories/packages/web/src/components/PeerTile.tsx new file mode 100644 index 0000000..e5537ed --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/PeerTile.tsx @@ -0,0 +1,44 @@ +import { type FC, type HTMLAttributes, useEffect, useRef } from 'react'; +import { cn } from '@/lib/utils'; + +export type PeerTileProps = { + stream?: MediaStream | null; + name: string; +} & HTMLAttributes; + +export const PeerTile: FC = ({ + stream, + name, + className, + ...props +}) => { + const videoRef = useRef(null); + + useEffect(() => { + if (!videoRef.current) return; + videoRef.current.srcObject = stream ?? null; + }, [stream]); + + return ( +
+ {stream ? ( + + ) : ( +
{name}
+ )} +
+ ); +}; diff --git a/deep-sea-stories/packages/web/src/components/RoomControls.tsx b/deep-sea-stories/packages/web/src/components/RoomControls.tsx new file mode 100644 index 0000000..0b6d0b9 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/RoomControls.tsx @@ -0,0 +1,41 @@ +import { Check } from 'lucide-react'; +import type { FC } from 'react'; +import CopyButton from './CopyButton'; +import HowItWorks from './HowItWorks'; +import HowToPlay from './HowToPlay'; +import { Button } from './ui/button'; +import { toast } from './ui/sonner'; + +export type RoomControlsProps = { + roomId: string; +}; + +const RoomControls: FC = ({ roomId }) => { + const url = `https://dss.fishjam.io/${roomId}`; + + return ( +
+
+ Deep Sea Stories +
+
+ +
+
+ + + toast('Gameroom link copied to clipboard', Check)} + value={url} + > + {url} + +
+
+ ); +}; + +export default RoomControls; diff --git a/deep-sea-stories/packages/web/src/components/TitleBar.tsx b/deep-sea-stories/packages/web/src/components/TitleBar.tsx new file mode 100644 index 0000000..31d3eee --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/TitleBar.tsx @@ -0,0 +1,14 @@ +import type { FC } from 'react'; + +const TitleBar: FC = () => { + return ( +
+
Deep Sea Stories
+
+ Hear the most mysterious stories and try to deduce how they happened. +
+
+ ); +}; + +export default TitleBar; diff --git a/deep-sea-stories/packages/web/src/components/ui/button.tsx b/deep-sea-stories/packages/web/src/components/ui/button.tsx index 754a1d0..e8f7c26 100644 --- a/deep-sea-stories/packages/web/src/components/ui/button.tsx +++ b/deep-sea-stories/packages/web/src/components/ui/button.tsx @@ -5,25 +5,18 @@ import * as React from 'react'; import { cn } from '@/lib/utils'; const buttonVariants = cva( - 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + 'inline-flex gap-2 items-center justify-center whitespace-nowrap rounded-full font-display transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive', { variants: { variant: { - default: 'bg-primary text-primary-foreground hover:bg-primary/90', - destructive: - 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + default: + 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90', outline: - 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', - secondary: - 'bg-secondary text-secondary-foreground hover:bg-secondary/80', - ghost: 'hover:bg-accent hover:text-accent-foreground', - link: 'text-primary underline-offset-4 hover:underline', + 'border-2 border-foreground bg-background shadow-xs hover:bg-accent', }, size: { - default: 'h-10 px-4 py-2', - sm: 'h-9 rounded-md px-3', - lg: 'h-11 rounded-md px-8', - icon: 'h-10 w-10', + default: 'px-6 h-12', + large: 'px-8 h-16 text-lg', }, }, defaultVariants: { diff --git a/deep-sea-stories/packages/web/src/components/ui/dialog.tsx b/deep-sea-stories/packages/web/src/components/ui/dialog.tsx new file mode 100644 index 0000000..aed27fa --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/dialog.tsx @@ -0,0 +1,120 @@ +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { X } from 'lucide-react'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = 'DialogHeader'; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = 'DialogFooter'; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/deep-sea-stories/packages/web/src/components/ui/input.tsx b/deep-sea-stories/packages/web/src/components/ui/input.tsx new file mode 100644 index 0000000..f7eeac5 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/input.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ); + }, +); +Input.displayName = 'Input'; + +export { Input }; diff --git a/deep-sea-stories/packages/web/src/components/ui/label.tsx b/deep-sea-stories/packages/web/src/components/ui/label.tsx new file mode 100644 index 0000000..617ff98 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as LabelPrimitive from '@radix-ui/react-label'; +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const labelVariants = cva( + 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', +); + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)); +Label.displayName = LabelPrimitive.Root.displayName; + +export { Label }; diff --git a/deep-sea-stories/packages/web/src/components/ui/scroll-area.tsx b/deep-sea-stories/packages/web/src/components/ui/scroll-area.tsx new file mode 100644 index 0000000..5d611a2 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/scroll-area.tsx @@ -0,0 +1,46 @@ +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = 'vertical', ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/deep-sea-stories/packages/web/src/components/ui/select.tsx b/deep-sea-stories/packages/web/src/components/ui/select.tsx new file mode 100644 index 0000000..e8fda90 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/select.tsx @@ -0,0 +1,158 @@ +import * as SelectPrimitive from '@radix-ui/react-select'; +import { Check, ChevronDown, ChevronUp } from 'lucide-react'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Select = SelectPrimitive.Root; + +const SelectGroup = SelectPrimitive.Group; + +const SelectValue = SelectPrimitive.Value; + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1', + className, + )} + {...props} + > + {children} + + + + +)); +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName; + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = 'popper', ...props }, ref) => ( + + + + + {children} + + + + +)); +SelectContent.displayName = SelectPrimitive.Content.displayName; + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectLabel.displayName = SelectPrimitive.Label.displayName; + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)); +SelectItem.displayName = SelectPrimitive.Item.displayName; + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectSeparator.displayName = SelectPrimitive.Separator.displayName; + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +}; diff --git a/deep-sea-stories/packages/web/src/components/ui/sonner.tsx b/deep-sea-stories/packages/web/src/components/ui/sonner.tsx new file mode 100644 index 0000000..58c871f --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/ui/sonner.tsx @@ -0,0 +1,49 @@ +import type { LucideIcon } from 'lucide-react'; +import { useTheme } from 'next-themes'; +import { Toaster as Sonner, toast as sonnerToast } from 'sonner'; + +type ToasterProps = React.ComponentProps; + +export function toast(title: string, icon: LucideIcon) { + return sonnerToast.custom(() => ); +} + +type ToastProps = { + icon: LucideIcon; + title: string; +}; + +function Toast({ title, icon: Icon }: ToastProps) { + return ( +
+ +

{title}

+
+ ); +} + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = 'system' } = useTheme(); + + return ( + + ); +}; + +export { Toaster }; diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css index 90d3dc9..a98e4e7 100644 --- a/deep-sea-stories/packages/web/src/index.css +++ b/deep-sea-stories/packages/web/src/index.css @@ -5,25 +5,38 @@ @custom-variant dark (&:is(.dark *)); +@theme { + --black: #221f1c; + --blacker: #090a0b; + --white: #f4f4f4; + --whiter: #ffffff; + --light-gray: #908f8d; + --dark-gray: #3e3d3c; + + --font-sans: aktiv-grotesk, sans-serif; + --font-display: june-expt, sans-serif; + --font-title: june-curious, sans-serif; +} + :root { --radius: 0.625rem; - --background: #fcf6e7; - --foreground: oklch(0.129 0.042 264.695); - --card: oklch(1 0 0); - --card-foreground: oklch(0.129 0.042 264.695); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.129 0.042 264.695); - --primary: oklch(0.208 0.042 265.755); - --primary-foreground: oklch(0.984 0.003 247.858); - --secondary: oklch(0.968 0.007 247.896); - --secondary-foreground: oklch(0.208 0.042 265.755); - --muted: oklch(0.968 0.007 247.896); - --muted-foreground: oklch(0.554 0.046 257.417); - --accent: #fad8d1; - --accent-foreground: oklch(0.208 0.042 265.755); + --background: var(--black); + --foreground: var(--white); + --card: var(--black); + --card-foreground: var(--white); + --popover: var(--black); + --popover-foreground: var(--black); + --primary: var(--white); + --primary-foreground: var(--black); + --secondary: var(--whiter); + --secondary-foreground: var(--blacker); + --muted: var(--dark-gray); + --muted-foreground: var(--light-gray); + --accent: var(--dark-gray); + --accent-foreground: var(--light-gray); --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.929 0.013 255.508); - --input: oklch(0.929 0.013 255.508); + --border: var(--dark-gray); + --input: var(--black); --ring: oklch(0.704 0.04 256.788); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); @@ -31,7 +44,7 @@ --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); --sidebar: oklch(0.984 0.003 247.858); - --sidebar-foreground: oklch(0.129 0.042 264.695); + --sidebar-foreground: var(--black); --sidebar-primary: oklch(0.208 0.042 265.755); --sidebar-primary-foreground: oklch(0.984 0.003 247.858); --sidebar-accent: oklch(0.968 0.007 247.896); @@ -55,6 +68,12 @@ font-display: auto; } +@font-face { + font-family: june-curious; + src: url("./assets/fonts/JuneExptCurious.otf") format("opentype"); + font-display: auto; +} + @theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); @@ -126,12 +145,6 @@ --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.551 0.027 264.364); } - -@theme { - --font-sans: aktiv-grotesk, sans-serif; - --font-display: june-expt, sans-serif; -} - @layer base { * { @apply border-border outline-ring/50; diff --git a/deep-sea-stories/packages/web/src/lib/utils.ts b/deep-sea-stories/packages/web/src/lib/utils.ts index 256f86f..d2b2633 100644 --- a/deep-sea-stories/packages/web/src/lib/utils.ts +++ b/deep-sea-stories/packages/web/src/lib/utils.ts @@ -4,3 +4,16 @@ import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } + +const ALPHANUM = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + +export function randomString(length: number = 10): string { + let result = ''; + + for (let i = 0; i < length; i++) { + result += ALPHANUM.charAt(Math.floor(Math.random() * ALPHANUM.length)); + } + + return result; +} diff --git a/deep-sea-stories/packages/web/src/main.tsx b/deep-sea-stories/packages/web/src/main.tsx index fd05ebd..1cebfbd 100644 --- a/deep-sea-stories/packages/web/src/main.tsx +++ b/deep-sea-stories/packages/web/src/main.tsx @@ -2,9 +2,12 @@ import { FishjamProvider } from '@fishjam-cloud/react-client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import App from './App.tsx'; import { TRPCClientProvider } from './contexts/trpc.tsx'; import './index.css'; +import { BrowserRouter, Route, Routes } from 'react-router'; +import Layout from './Layout.tsx'; +import HomeView from './views/HomeView.tsx'; +import RoomView from './views/RoomView.tsx'; const queryClient = new QueryClient({ defaultOptions: { @@ -20,7 +23,14 @@ createRoot(document.getElementById('root')!).render( - + + + + } /> + } /> + + + diff --git a/deep-sea-stories/packages/web/src/views/GameView.tsx b/deep-sea-stories/packages/web/src/views/GameView.tsx new file mode 100644 index 0000000..ec1bde5 --- /dev/null +++ b/deep-sea-stories/packages/web/src/views/GameView.tsx @@ -0,0 +1,42 @@ +import { usePeers } from '@fishjam-cloud/react-client'; +import type { FC } from 'react'; +import AgentPanel from '@/components/AgentPanel'; +import { PeerTile } from '@/components/PeerTile'; +import RoomControls from '@/components/RoomControls'; + +export type GameViewProps = { + roomId: string; +}; + +const GameView: FC = ({ roomId }) => { + const { remotePeers, localPeer } = usePeers<{ name: string }>(); + const peers = remotePeers.length + 1; + return ( + <> +
+ + +
+
+ + {remotePeers.map((peer) => ( + + ))} +
+ + ); +}; +export default GameView; diff --git a/deep-sea-stories/packages/web/src/views/HomeView.tsx b/deep-sea-stories/packages/web/src/views/HomeView.tsx new file mode 100644 index 0000000..f6aba8a --- /dev/null +++ b/deep-sea-stories/packages/web/src/views/HomeView.tsx @@ -0,0 +1,18 @@ +import Footer from '@/components/Footer'; +import LinkButton from '@/components/LinkButton'; +import TitleBar from '@/components/TitleBar'; +import { randomString } from '@/lib/utils'; + +export default function HomeView() { + return ( + <> + +
+ + Create a game room + +
+
+ + ); +} diff --git a/deep-sea-stories/packages/web/src/views/JoinView.tsx b/deep-sea-stories/packages/web/src/views/JoinView.tsx new file mode 100644 index 0000000..8e450dc --- /dev/null +++ b/deep-sea-stories/packages/web/src/views/JoinView.tsx @@ -0,0 +1,88 @@ +import { + useCamera, + useInitializeDevices, + useMicrophone, +} from '@fishjam-cloud/react-client'; +import { Camera, Mic } from 'lucide-react'; +import type { FC } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { DeviceSelect } from '@/components/DeviceSelect'; +import { PeerTile } from '@/components/PeerTile'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; + +const JoinView: FC = () => { + const { initializeDevices } = useInitializeDevices(); + const wasCameraTurnedOff = useRef(false); + const [name, setName] = useState(''); + + const { + isCameraOn, + toggleCamera, + cameraStream, + cameraDevices, + selectCamera, + currentCamera, + } = useCamera(); + const { microphoneDevices, selectMicrophone, currentMicrophone } = + useMicrophone(); + + const initAndTurnOnCamera = useCallback(async () => { + await initializeDevices(); + if (!isCameraOn && !wasCameraTurnedOff.current) { + await toggleCamera(); + } + }, [initializeDevices, isCameraOn, toggleCamera]); + + useEffect(() => { + initAndTurnOnCamera(); + }, [initAndTurnOnCamera]); + + return ( + <> +
+ Deep Sea Stories +
+
+
Finish a player setup
+
+ Enter your player’s name and test out your camera and microphone. +
+
+
+
+ setName(e.target.value)} + value={name} + placeholder="Enter your name" + /> + +
+ + + + + + +
+
+
+
+ +
+ + ); +}; + +export default JoinView; diff --git a/deep-sea-stories/packages/web/src/views/RoomView.tsx b/deep-sea-stories/packages/web/src/views/RoomView.tsx new file mode 100644 index 0000000..d97bce2 --- /dev/null +++ b/deep-sea-stories/packages/web/src/views/RoomView.tsx @@ -0,0 +1,12 @@ +import { useConnection } from '@fishjam-cloud/react-client'; +import { useParams } from 'react-router'; +import GameView from './GameView'; +import JoinView from './JoinView'; + +export default function RoomView() { + const { roomId } = useParams(); + const { peerStatus } = useConnection(); + const isConnected = peerStatus === 'connected'; + + return !isConnected ? : ; +} diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index b06a26d..f929bf6 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -611,6 +611,44 @@ __metadata: languageName: node linkType: hard +"@floating-ui/core@npm:^1.7.3": + version: 1.7.3 + resolution: "@floating-ui/core@npm:1.7.3" + dependencies: + "@floating-ui/utils": "npm:^0.2.10" + checksum: 10c0/edfc23800122d81df0df0fb780b7328ae6c5f00efbb55bd48ea340f4af8c5b3b121ceb4bb81220966ab0f87b443204d37105abdd93d94846468be3243984144c + languageName: node + linkType: hard + +"@floating-ui/dom@npm:^1.7.4": + version: 1.7.4 + resolution: "@floating-ui/dom@npm:1.7.4" + dependencies: + "@floating-ui/core": "npm:^1.7.3" + "@floating-ui/utils": "npm:^0.2.10" + checksum: 10c0/da6166c25f9b0729caa9f498685a73a0e28251613b35d27db8de8014bc9d045158a23c092b405321a3d67c2064909b6e2a7e6c1c9cc0f62967dca5779f5aef30 + languageName: node + linkType: hard + +"@floating-ui/react-dom@npm:^2.0.0": + version: 2.1.6 + resolution: "@floating-ui/react-dom@npm:2.1.6" + dependencies: + "@floating-ui/dom": "npm:^1.7.4" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 10c0/6654834a8e73ecbdbc6cad2ad8f7abc698ac7c1800ded4d61113525c591c03d2e3b59d3cf9205859221465ea38c87af4f9e6e204703c5b7a7e85332d1eef2e18 + languageName: node + linkType: hard + +"@floating-ui/utils@npm:^0.2.10": + version: 0.2.10 + resolution: "@floating-ui/utils@npm:0.2.10" + checksum: 10c0/e9bc2a1730ede1ee25843937e911ab6e846a733a4488623cd353f94721b05ec2c9ec6437613a2ac9379a94c2fd40c797a2ba6fa1df2716f5ce4aa6ddb1cf9ea4 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -718,6 +756,61 @@ __metadata: languageName: node linkType: hard +"@radix-ui/number@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/number@npm:1.1.1" + checksum: 10c0/0570ad92287398e8a7910786d7cee0a998174cdd6637ba61571992897c13204adf70b9ed02d0da2af554119411128e701d9c6b893420612897b438dc91db712b + languageName: node + linkType: hard + +"@radix-ui/primitive@npm:1.1.3": + version: 1.1.3 + resolution: "@radix-ui/primitive@npm:1.1.3" + checksum: 10c0/88860165ee7066fa2c179f32ffcd3ee6d527d9dcdc0e8be85e9cb0e2c84834be8e3c1a976c74ba44b193f709544e12f54455d892b28e32f0708d89deda6b9f1d + languageName: node + linkType: hard + +"@radix-ui/react-arrow@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-arrow@npm:1.1.7" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/c3b46766238b3ee2a394d8806a5141432361bf1425110c9f0dcf480bda4ebd304453a53f294b5399c6ee3ccfcae6fd544921fd01ddc379cf5942acdd7168664b + languageName: node + linkType: hard + +"@radix-ui/react-collection@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-collection@npm:1.1.7" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/fa321a7300095508491f75414f02b243f0c3f179dc0728cfd115e2ea9f6f48f1516532b59f526d9ac81bbab63cd98a052074b4703ec0b9428fac945ebabec5fd + languageName: node + linkType: hard + "@radix-ui/react-compose-refs@npm:1.1.2": version: 1.1.2 resolution: "@radix-ui/react-compose-refs@npm:1.1.2" @@ -731,7 +824,309 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-slot@npm:^1.2.3": +"@radix-ui/react-context@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-context@npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/cece731f8cc25d494c6589cc681e5c01a93867d895c75889973afa1a255f163c286e390baa7bc028858eaabe9f6b57270d0ca6377356f652c5557c1c7a41ccce + languageName: node + linkType: hard + +"@radix-ui/react-dialog@npm:^1.1.15": + version: 1.1.15 + resolution: "@radix-ui/react-dialog@npm:1.1.15" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-dismissable-layer": "npm:1.1.11" + "@radix-ui/react-focus-guards": "npm:1.1.3" + "@radix-ui/react-focus-scope": "npm:1.1.7" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-portal": "npm:1.1.9" + "@radix-ui/react-presence": "npm:1.1.5" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + aria-hidden: "npm:^1.2.4" + react-remove-scroll: "npm:^2.6.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/2f2c88e3c281acaea2fd9b96fa82132d59177d3aa5da2e7c045596fd4028e84e44ac52ac28f4f236910605dd7d9338c2858ba44a9ced2af2e3e523abbfd33014 + languageName: node + linkType: hard + +"@radix-ui/react-direction@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-direction@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7a89d9291f846a3105e45f4df98d6b7a08f8d7b30acdcd253005dc9db107ee83cbbebc9e47a9af1e400bcd47697f1511ceab23a399b0da854488fc7220482ac9 + languageName: node + linkType: hard + +"@radix-ui/react-dismissable-layer@npm:1.1.11": + version: 1.1.11 + resolution: "@radix-ui/react-dismissable-layer@npm:1.1.11" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-escape-keydown": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/c825572a64073c4d3853702029979f6658770ffd6a98eabc4984e1dee1b226b4078a2a4dc7003f96475b438985e9b21a58e75f51db74dd06848dcae1f2d395dc + languageName: node + linkType: hard + +"@radix-ui/react-focus-guards@npm:1.1.3": + version: 1.1.3 + resolution: "@radix-ui/react-focus-guards@npm:1.1.3" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/0bab65eb8d7e4f72f685d63de7fbba2450e3cb15ad6a20a16b42195e9d335c576356f5a47cb58d1ffc115393e46d7b14b12c5d4b10029b0ec090861255866985 + languageName: node + linkType: hard + +"@radix-ui/react-focus-scope@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-focus-scope@npm:1.1.7" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/8a6071331bdeeb79b223463de75caf759b8ad19339cab838e537b8dbb2db236891a1f4df252445c854d375d43d9d315dfcce0a6b01553a2984ec372bb8f1300e + languageName: node + linkType: hard + +"@radix-ui/react-id@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-id@npm:1.1.1" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7d12e76818763d592c331277ef62b197e2e64945307e650bd058f0090e5ae48bbd07691b23b7e9e977901ef4eadcb3e2d5eaeb17a13859083384be83fc1292c7 + languageName: node + linkType: hard + +"@radix-ui/react-label@npm:^2.1.7": + version: 2.1.7 + resolution: "@radix-ui/react-label@npm:2.1.7" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/d8c81411d5327b6db5cbf4b900bfcc52030315539911701cf8d82b4970aed80cbd66df5b62d2242859572c666cf4b0e147a8b39dc3c04bd024a4b4405e1183fe + languageName: node + linkType: hard + +"@radix-ui/react-popper@npm:1.2.8": + version: 1.2.8 + resolution: "@radix-ui/react-popper@npm:1.2.8" + dependencies: + "@floating-ui/react-dom": "npm:^2.0.0" + "@radix-ui/react-arrow": "npm:1.1.7" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + "@radix-ui/react-use-rect": "npm:1.1.1" + "@radix-ui/react-use-size": "npm:1.1.1" + "@radix-ui/rect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/48e3f13eac3b8c13aca8ded37d74db17e1bb294da8d69f142ab6b8719a06c3f90051668bed64520bf9f3abdd77b382ce7ce209d056bb56137cecc949b69b421c + languageName: node + linkType: hard + +"@radix-ui/react-portal@npm:1.1.9": + version: 1.1.9 + resolution: "@radix-ui/react-portal@npm:1.1.9" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/45b432497c722720c72c493a29ef6085bc84b50eafe79d48b45c553121b63e94f9cdb77a3a74b9c49126f8feb3feee009fe400d48b7759d3552396356b192cd7 + languageName: node + linkType: hard + +"@radix-ui/react-presence@npm:1.1.5": + version: 1.1.5 + resolution: "@radix-ui/react-presence@npm:1.1.5" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/d0e61d314250eeaef5369983cb790701d667f51734bafd98cf759072755562018052c594e6cdc5389789f4543cb0a4d98f03ff4e8f37338d6b5bf51a1700c1d1 + languageName: node + linkType: hard + +"@radix-ui/react-primitive@npm:2.1.3": + version: 2.1.3 + resolution: "@radix-ui/react-primitive@npm:2.1.3" + dependencies: + "@radix-ui/react-slot": "npm:1.2.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/fdff9b84913bb4172ef6d3af7442fca5f9bba5f2709cba08950071f819d7057aec3a4a2d9ef44cf9cbfb8014d02573c6884a04cff175895823aaef809ebdb034 + languageName: node + linkType: hard + +"@radix-ui/react-scroll-area@npm:^1.2.10": + version: 1.2.10 + resolution: "@radix-ui/react-scroll-area@npm:1.2.10" + dependencies: + "@radix-ui/number": "npm:1.1.1" + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-direction": "npm:1.1.1" + "@radix-ui/react-presence": "npm:1.1.5" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/8acdacd255fdfcefe4f72028a13dc554df73327db94c250f54a85b9608aa0313284dbb6c417f28a48e7b7b7bcaa76ddf3297e91ba07d833604d428f869259622 + languageName: node + linkType: hard + +"@radix-ui/react-select@npm:^2.2.6": + version: 2.2.6 + resolution: "@radix-ui/react-select@npm:2.2.6" + dependencies: + "@radix-ui/number": "npm:1.1.1" + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-collection": "npm:1.1.7" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-direction": "npm:1.1.1" + "@radix-ui/react-dismissable-layer": "npm:1.1.11" + "@radix-ui/react-focus-guards": "npm:1.1.3" + "@radix-ui/react-focus-scope": "npm:1.1.7" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-popper": "npm:1.2.8" + "@radix-ui/react-portal": "npm:1.1.9" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + "@radix-ui/react-use-previous": "npm:1.1.1" + "@radix-ui/react-visually-hidden": "npm:1.2.3" + aria-hidden: "npm:^1.2.4" + react-remove-scroll: "npm:^2.6.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/34b2492589c3a4b118a03900d622640033630f30ac93c4a69b3701513117607f4ac3a0d9dd3cad39caa8b6495660f71f3aa9d0074d4eb4dac6804dc0b8408deb + languageName: node + linkType: hard + +"@radix-ui/react-slot@npm:1.2.3, @radix-ui/react-slot@npm:^1.2.3": version: 1.2.3 resolution: "@radix-ui/react-slot@npm:1.2.3" dependencies: @@ -746,6 +1141,147 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-use-callback-ref@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-callback-ref@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5f6aff8592dea6a7e46589808912aba3fb3b626cf6edd2b14f01638b61dbbe49eeb9f67cd5601f4c15b2fb547b9a7e825f7c4961acd4dd70176c969ae405f8d8 + languageName: node + linkType: hard + +"@radix-ui/react-use-controllable-state@npm:1.2.2": + version: 1.2.2 + resolution: "@radix-ui/react-use-controllable-state@npm:1.2.2" + dependencies: + "@radix-ui/react-use-effect-event": "npm:0.0.2" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/f55c4b06e895293aed4b44c9ef26fb24432539f5346fcd6519c7745800535b571058685314e83486a45bf61dc83887e24826490d3068acc317fb0a9010516e63 + languageName: node + linkType: hard + +"@radix-ui/react-use-effect-event@npm:0.0.2": + version: 0.0.2 + resolution: "@radix-ui/react-use-effect-event@npm:0.0.2" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/e84ff72a3e76c5ae9c94941028bb4b6472f17d4104481b9eab773deab3da640ecea035e54da9d6f4df8d84c18ef6913baf92b7511bee06930dc58bd0c0add417 + languageName: node + linkType: hard + +"@radix-ui/react-use-escape-keydown@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-escape-keydown@npm:1.1.1" + dependencies: + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/bff53be99e940fef1d3c4df7d560e1d9133182e5a98336255d3063327d1d3dd4ec54a95dc5afe15cca4fb6c184f0a956c70de2815578c318cf995a7f9beabaa1 + languageName: node + linkType: hard + +"@radix-ui/react-use-layout-effect@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9f98fdaba008dfc58050de60a77670b885792df473cf82c1cef8daee919a5dd5a77d270209f5f0b0abfaac78cb1627396e3ff56c81b735be550409426fe8b040 + languageName: node + linkType: hard + +"@radix-ui/react-use-previous@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-previous@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/52f1089d941491cd59b7f52a5679a14e9381711419a0557ce0f3bc9a4c117078224efec54dcced41a3653a13a386a7b6ec75435d61a273e8b9f5d00235f2b182 + languageName: node + linkType: hard + +"@radix-ui/react-use-rect@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-rect@npm:1.1.1" + dependencies: + "@radix-ui/rect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/271711404c05c589c8dbdaa748749e7daf44bcc6bffc9ecd910821c3ebca0ee245616cf5b39653ce690f53f875c3836fd3f36f51ab1c628273b6db599eee4864 + languageName: node + linkType: hard + +"@radix-ui/react-use-size@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-size@npm:1.1.1" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/851d09a816f44282e0e9e2147b1b571410174cc048703a50c4fa54d672de994fd1dfff1da9d480ecfd12c77ae8f48d74f01adaf668f074156b8cd0043c6c21d8 + languageName: node + linkType: hard + +"@radix-ui/react-visually-hidden@npm:1.2.3": + version: 1.2.3 + resolution: "@radix-ui/react-visually-hidden@npm:1.2.3" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/cf86a37f1cbee50a964056f3dc4f6bb1ee79c76daa321f913aa20ff3e1ccdfafbf2b114d7bb616aeefc7c4b895e6ca898523fdb67710d89bd5d8edb739a0d9b6 + languageName: node + linkType: hard + +"@radix-ui/rect@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/rect@npm:1.1.1" + checksum: 10c0/0dac4f0f15691199abe6a0e067821ddd9d0349c0c05f39834e4eafc8403caf724106884035ae91bbc826e10367e6a5672e7bec4d4243860fa7649de246b1f60b + languageName: node + linkType: hard + "@rolldown/pluginutils@npm:1.0.0-beta.38": version: 1.0.0-beta.38 resolution: "@rolldown/pluginutils@npm:1.0.0-beta.38" @@ -1308,6 +1844,15 @@ __metadata: languageName: node linkType: hard +"aria-hidden@npm:^1.2.4": + version: 1.2.6 + resolution: "aria-hidden@npm:1.2.6" + dependencies: + tslib: "npm:^2.0.0" + checksum: 10c0/7720cb539497a9f760f68f98a4b30f22c6767aa0e72fa7d58279f7c164e258fc38b2699828f8de881aab0fc8e9c56d1313a3f1a965046fc0381a554dbc72b54a + languageName: node + linkType: hard + "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -1595,6 +2140,13 @@ __metadata: languageName: node linkType: hard +"detect-node-es@npm:^1.1.0": + version: 1.1.0 + resolution: "detect-node-es@npm:1.1.0" + checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe + languageName: node + linkType: hard + "dotenv@npm:^17.2.3": version: 17.2.3 resolution: "dotenv@npm:17.2.3" @@ -2044,6 +2596,13 @@ __metadata: languageName: node linkType: hard +"get-nonce@npm:^1.0.0": + version: 1.0.1 + resolution: "get-nonce@npm:1.0.1" + checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162 + languageName: node + linkType: hard + "get-proto@npm:^1.0.1": version: 1.0.1 resolution: "get-proto@npm:1.0.1" @@ -2599,6 +3158,16 @@ __metadata: languageName: node linkType: hard +"next-themes@npm:^0.4.6": + version: 0.4.6 + resolution: "next-themes@npm:0.4.6" + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + checksum: 10c0/83590c11d359ce7e4ced14f6ea9dd7a691d5ce6843fe2dc520fc27e29ae1c535118478d03e7f172609c41b1ef1b8da6b8dd2d2acd6cd79cac1abbdbd5b99f2c4 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 11.4.2 resolution: "node-gyp@npm:11.4.2" @@ -2842,6 +3411,73 @@ __metadata: languageName: node linkType: hard +"react-remove-scroll-bar@npm:^2.3.7": + version: 2.3.8 + resolution: "react-remove-scroll-bar@npm:2.3.8" + dependencies: + react-style-singleton: "npm:^2.2.2" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9a0675c66cbb52c325bdbfaed80987a829c4504cefd8ff2dd3b6b3afc9a1500b8ec57b212e92c1fb654396d07bbe18830a8146fe77677d2a29ce40b5e1f78654 + languageName: node + linkType: hard + +"react-remove-scroll@npm:^2.6.3": + version: 2.7.1 + resolution: "react-remove-scroll@npm:2.7.1" + dependencies: + react-remove-scroll-bar: "npm:^2.3.7" + react-style-singleton: "npm:^2.2.3" + tslib: "npm:^2.1.0" + use-callback-ref: "npm:^1.3.3" + use-sidecar: "npm:^1.1.3" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7ad8f6ffd3e2aedf9b3d79f0c9088a9a3d7c5332d80c923427a6d97fe0626fb4cb33a6d9174d19fad57d860be69c96f68497a0619c3a8af0e8a5332e49bdde31 + languageName: node + linkType: hard + +"react-router@npm:^7.9.3": + version: 7.9.3 + resolution: "react-router@npm:7.9.3" + dependencies: + cookie: "npm:^1.0.1" + set-cookie-parser: "npm:^2.6.0" + peerDependencies: + react: ">=18" + react-dom: ">=18" + peerDependenciesMeta: + react-dom: + optional: true + checksum: 10c0/ad77654d53df38b66415d158dfeb42d589e732691da6cb3ce77e8e31cb295a809f2a280e2ea203119d2b9e944992ca87f309db5c6524649cba6fa6539f6c4a83 + languageName: node + linkType: hard + +"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3": + version: 2.2.3 + resolution: "react-style-singleton@npm:2.2.3" + dependencies: + get-nonce: "npm:^1.0.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/841938ff16d16a6b76895f4cb2e1fea957e5fe3b30febbf03a54892dae1c9153f2383e231dea0b3ba41192ad2f2849448fa859caccd288943bce32639e971bee + languageName: node + linkType: hard + "react@npm:^19.1.1": version: 19.1.1 resolution: "react@npm:19.1.1" @@ -3117,6 +3753,16 @@ __metadata: languageName: node linkType: hard +"sonner@npm:^2.0.7": + version: 2.0.7 + resolution: "sonner@npm:2.0.7" + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + checksum: 10c0/6966ab5e892ed6aab579a175e4a24f3b48747f0fc21cb68c3e33cb41caa7a0eebeb098c210545395e47a18d585eb8734ae7dd12d2bd18c8a3294a1ee73f997d9 + languageName: node + linkType: hard + "source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" @@ -3247,7 +3893,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": +"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -3348,6 +3994,37 @@ __metadata: languageName: node linkType: hard +"use-callback-ref@npm:^1.3.3": + version: 1.3.3 + resolution: "use-callback-ref@npm:1.3.3" + dependencies: + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/f887488c6e6075cdad4962979da1714b217bcb1ee009a9e57ce9a844bcfc4c3a99e93983dfc2e5af9e0913824d24e730090ff255e902c516dcb58d2d3837e01c + languageName: node + linkType: hard + +"use-sidecar@npm:^1.1.3": + version: 1.1.3 + resolution: "use-sidecar@npm:1.1.3" + dependencies: + detect-node-es: "npm:^1.1.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/161599bf921cfaa41c85d2b01c871975ee99260f3e874c2d41c05890d41170297bdcf314bc5185e7a700de2034ac5b888e3efc8e9f35724f4918f53538d717c9 + languageName: node + linkType: hard + "uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" @@ -3417,6 +4094,10 @@ __metadata: resolution: "web@workspace:packages/web" dependencies: "@fishjam-cloud/react-client": "npm:^0.20.0" + "@radix-ui/react-dialog": "npm:^1.1.15" + "@radix-ui/react-label": "npm:^2.1.7" + "@radix-ui/react-scroll-area": "npm:^1.2.10" + "@radix-ui/react-select": "npm:^2.2.6" "@radix-ui/react-slot": "npm:^1.2.3" "@tailwindcss/vite": "npm:^4.1.13" "@tanstack/react-query": "npm:^5.90.2" @@ -3432,8 +4113,11 @@ __metadata: clsx: "npm:^2.1.1" globals: "npm:^16.4.0" lucide-react: "npm:^0.544.0" + next-themes: "npm:^0.4.6" react: "npm:^19.1.1" react-dom: "npm:^19.1.1" + react-router: "npm:^7.9.3" + sonner: "npm:^2.0.7" tailwind-merge: "npm:^3.3.1" tailwindcss: "npm:^4.1.13" tw-animate-css: "npm:^1.4.0" From ee80ff333f9d85e2750cbfb8c840b9665b0df355 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Tue, 7 Oct 2025 19:27:51 +0200 Subject: [PATCH 28/65] story selection api --- .../packages/backend/src/controllers/rooms.ts | 2 - .../backend/src/controllers/stories.ts | 56 +++++++++++++++++++ .../packages/backend/src/prompts/stories.json | 10 ++++ .../packages/backend/src/router.ts | 3 + .../packages/backend/src/schemas.ts | 5 ++ .../packages/backend/src/service/notifier.ts | 27 ++++++--- .../packages/backend/src/service/room.ts | 24 +++++++- .../packages/backend/src/types.ts | 1 + .../packages/backend/src/utils.ts | 6 +- .../packages/backend/tests/utils.test.ts | 22 +------- 10 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 deep-sea-stories/packages/backend/src/controllers/stories.ts diff --git a/deep-sea-stories/packages/backend/src/controllers/rooms.ts b/deep-sea-stories/packages/backend/src/controllers/rooms.ts index b29a49f..2080b63 100644 --- a/deep-sea-stories/packages/backend/src/controllers/rooms.ts +++ b/deep-sea-stories/packages/backend/src/controllers/rooms.ts @@ -1,11 +1,9 @@ import type { RoomId } from '@fishjam-cloud/js-server-sdk'; import { getRoomInputSchema } from '../schemas.js'; import { publicProcedure } from '../trpc.js'; -import { roomService } from '../service/room.js'; export const createRoom = publicProcedure.mutation(async ({ ctx }) => { const room = await ctx.fishjam.createRoom(); - roomService.createStory(room.id); return room; }); diff --git a/deep-sea-stories/packages/backend/src/controllers/stories.ts b/deep-sea-stories/packages/backend/src/controllers/stories.ts new file mode 100644 index 0000000..8fcfc5e --- /dev/null +++ b/deep-sea-stories/packages/backend/src/controllers/stories.ts @@ -0,0 +1,56 @@ +import { publicProcedure } from '../trpc.js'; +import { stories } from '../config.js'; +import { startStoryInputSchema } from '../schemas.js'; +import { roomService } from '../service/room.js'; +import type { RoomId } from '@fishjam-cloud/js-server-sdk'; + +export const startStory = publicProcedure + .input(startStoryInputSchema) + .mutation(async ({ input }) => { + const selectedStory = stories.find((s) => s.title === input.storyTitle); + if (!selectedStory) { + throw new Error(`Story with title ${input.storyTitle} does not exist`); + } + roomService.setStory(input.roomId as RoomId, selectedStory); + + // Create AI agent sessions for all currently connected peers + const connectedPeerIds = roomService.getConnectedPeers( + input.roomId as RoomId, + ); + const sessionManager = roomService.getSessionManager( + input.roomId as RoomId, + ); + + if (sessionManager && connectedPeerIds.length > 0) { + console.log( + `Creating AI sessions for ${connectedPeerIds.length} connected peers in room ${input.roomId}`, + ); + + // Create sessions for all connected peers + await Promise.all( + connectedPeerIds.map(async (peerId) => { + try { + await sessionManager.createSession(peerId, input.roomId as RoomId); + console.log( + `Created AI session for peer ${peerId} in room ${input.roomId}`, + ); + } catch (error) { + console.error( + `Failed to create session for peer ${peerId}:`, + error, + ); + } + }), + ); + } + + return { + success: true, + message: `Story "${input.storyTitle}" started successfully`, + sessionsCreated: connectedPeerIds.length, + }; + }); + +export const getStories = publicProcedure.query(() => { + return stories.map((s) => s.title); +}); diff --git a/deep-sea-stories/packages/backend/src/prompts/stories.json b/deep-sea-stories/packages/backend/src/prompts/stories.json index 66b62d2..fc8f8db 100644 --- a/deep-sea-stories/packages/backend/src/prompts/stories.json +++ b/deep-sea-stories/packages/backend/src/prompts/stories.json @@ -1,41 +1,51 @@ [ { + "title": "Dead Skydiver in a Field", "front": "A man was found dead in the middle of a field. There were no footprints around him and he had nothing in his hands. The only thing on him was a small parachute harness without a parachute attached.", "back": "The man was a skydiver. He had gone on a jump with a group of skydivers and had accidentally grabbed a faulty parachute. Mid-air, when he realized it was not functional, he attempted to fix it but couldn't. As he descended, the wind blew him away from the group, causing him to land in the open field, without any footprints nearby due to being airborne before the landing." }, { + "title": "Locked Apartment Mystery", "front": "A man is found dead in his locked apartment. The door is bolted from the inside, all the windows are closed, and there are no signs of forced entry. Next to him lies a puddle of water and some shattered glass.", "back": "The man had kept a large ice block propped against the door as an improvised barricade, fearing someone was after him. When he sat down to rest, the ice eventually melted, leaving only the puddle of water. The door closed and locked itself, and no one had to enter. He later died of unrelated causes (a heart attack)." }, { + "title": "Dead Men in a Mountain Cabin", "front": "Two men are found dead in a cabin on a mountain. The windows are shattered, but there are no footprints leading away from the cabin.", "back": "The men had been flying in a small airplane that crashed into the mountainside. What the rescuers thought was a 'cabin' was actually the remains of the airplane fuselage. They died on impact, and the shattered 'windows' were airplane windows, not a house." }, { + "title": "Death by Thirst in a Bar", "front": "A man dies of thirst in the middle of a bar full of people. Nobody helped him.", "back": "The bar was not a drinking establishment, but a sandbar in the desert. He was stranded, saw no one around, and perished from dehydration. The wording misleads the guessers into thinking of an alcohol-serving bar." }, { + "title": "Library Blunt Force Trauma", "front": "A body is found in a library, with dozens of books scattered around. Cause of death: blunt force trauma. There are no weapons nearby.", "back": "The man died when a heavy bookshelf collapsed on him while he was trying to reach a book from the top. The books scattered everywhere during the fall, concealing the true cause of his death until closer inspection." }, { + "title": "Hanging in an Empty Room", "front": "A man is found hanged in a room with a ceiling 4 meters high. There is no chair, no furniture, and the floor is bare.", "back": "The man stood on a large block of ice to hang himself. Over time, the ice melted completely, leaving no trace and creating the illusion of an impossible hanging." }, { + "title": "Sailor with Sand-Filled Pockets", "front": "A sailor is found dead on the deck of his ship. His pockets are full of sand, and there are no signs of injury.", "back": "The sailor had been rescued after a shipwreck. During the accident, he swallowed a large amount of seawater containing sand and silt. Though he survived the wreck, he later collapsed and died from internal damage caused by inhaling sand-filled water into his lungs." }, { + "title": "Death in a Phone Booth", "front": "A man lies dead in a phone booth. The glass is shattered, and he is clutching torn pages from a phone book.", "back": "The man was a fisherman who had boasted about the size of a fish he caught. His friends didn’t believe him, so he rushed to the phone booth to call and confirm it with someone. He angrily tore pages looking for the number but accidentally broke the glass and cut himself fatally in his frustration." }, { + "title": "Smiling Woman and Static TV", "front": "A woman is found dead in front of her television. The TV is on, but the screen shows only static. She has a smile on her face.", "back": "The woman had been terminally ill and bedridden. She watched a TV show religiously every week, and on the night of her death, the show aired its final episode. She smiled, having seen the ending she long awaited, and then peacefully passed away. The static was just the end of transmission." }, { + "title": "Shot in a Locked Car", "front": "A man is found shot to death in a car. All the doors are locked from the inside, and there is no gun in the vehicle.", "back": "The man was killed in a drive-by shooting. After he was shot, his car rolled forward and hit an obstacle, automatically locking the central locking system on impact. The attacker left with the weapon, leaving behind a locked car with a dead man inside." } diff --git a/deep-sea-stories/packages/backend/src/router.ts b/deep-sea-stories/packages/backend/src/router.ts index 351c404..374ce84 100644 --- a/deep-sea-stories/packages/backend/src/router.ts +++ b/deep-sea-stories/packages/backend/src/router.ts @@ -1,11 +1,14 @@ import { createRoom, getRoom } from './controllers/rooms.js'; import { createPeer } from './controllers/peers.js'; +import { startStory, getStories } from './controllers/stories.js'; import { router } from './trpc.js'; export const appRouter = router({ createRoom, getRoom, createPeer, + startStory, + getStories, }); export type AppRouter = typeof appRouter; diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts index 92f86c5..6ff83ff 100644 --- a/deep-sea-stories/packages/backend/src/schemas.ts +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -3,3 +3,8 @@ import z from 'zod'; export const getRoomInputSchema = z.object({ roomId: z.string() }); export const createPeerInputSchema = z.object({ roomId: z.string() }); + +export const startStoryInputSchema = z.object({ + roomId: z.string(), + storyTitle: z.string(), +}); diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 35d30ac..078356e 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -32,17 +32,29 @@ class NotifierService { this.notifier.on('peerConnected', async (msg) => { console.log(`Peer connected: ${msg.peerId} in room ${msg.roomId}`); - if (!roomService.getPeers(msg.roomId).find((p) => p.id === msg.peerId)) { - return; - } + roomService.addConnectedPeer(msg.roomId, msg.peerId); - const sessionManager = roomService.getSessionManager(msg.roomId); - await sessionManager?.createSession(msg.peerId, msg.roomId); + const story = roomService.getStory(msg.roomId); + if (story) { + const sessionManager = roomService.getSessionManager(msg.roomId); + try { + await sessionManager?.createSession(msg.peerId, msg.roomId); + console.log( + `Created AI session for peer ${msg.peerId} in room ${msg.roomId}`, + ); + } catch (error) { + console.error( + `Failed to create session for peer ${msg.peerId}:`, + error, + ); + } + } const fishjam_agent = roomService.getAgent(msg.roomId); - fishjam_agent?.on('trackData', (msg) => { - const { data, peerId } = msg; + fishjam_agent?.on('trackData', (trackMsg) => { + const { data, peerId } = trackMsg; + const sessionManager = roomService.getSessionManager(msg.roomId); const session = sessionManager?.getSession(peerId); if (session && data) { @@ -64,6 +76,7 @@ class NotifierService { this.notifier.on('peerDisconnected', async (msg) => { console.log(`Peer disconnected: ${msg.peerId} from room ${msg.roomId}`); + roomService.removeConnectedPeer(msg.roomId, msg.peerId); const sessionManager = roomService.getSessionManager(msg.roomId); await sessionManager?.deleteSession(msg.peerId); }); diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index 69021e9..a916e7a 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -2,16 +2,17 @@ import type { FishjamAgent, FishjamClient, Peer, + PeerId, RoomId, } from '@fishjam-cloud/js-server-sdk'; import type { Story } from '../types.js'; -import { getRandomStory } from '../utils.js'; import { FISHJAM_AGENT_OPTIONS } from '../config.js'; import { SessionManager } from './session.js'; class RoomService { private RoomToStory = new Map(); private RoomToPeers = new Map(); + private RoomToConnectedPeers = new Map>(); private RoomToFishjamAgent = new Map(); private RoomToSessionManager = new Map(); @@ -27,6 +28,24 @@ class RoomService { return this.RoomToPeers.get(roomId) || []; } + getConnectedPeers(roomId: RoomId): PeerId[] { + const connectedPeerIds = this.RoomToConnectedPeers.get(roomId) || new Set(); + return Array.from(connectedPeerIds); + } + + addConnectedPeer(roomId: RoomId, peerId: PeerId) { + const connectedPeers = this.RoomToConnectedPeers.get(roomId) || new Set(); + connectedPeers.add(peerId); + this.RoomToConnectedPeers.set(roomId, connectedPeers); + } + + removeConnectedPeer(roomId: RoomId, peerId: PeerId) { + const connectedPeers = this.RoomToConnectedPeers.get(roomId); + if (connectedPeers) { + connectedPeers.delete(peerId); + } + } + getSessionManager(roomId: RoomId) { if (!this.RoomToSessionManager.get(roomId)) { this.RoomToSessionManager.set(roomId, new SessionManager()); @@ -34,8 +53,7 @@ class RoomService { return this.RoomToSessionManager.get(roomId); } - createStory(roomId: RoomId) { - const story = getRandomStory(); + setStory(roomId: RoomId, story: Story) { this.RoomToStory.set(roomId, story); } diff --git a/deep-sea-stories/packages/backend/src/types.ts b/deep-sea-stories/packages/backend/src/types.ts index 2cb6a43..0799439 100644 --- a/deep-sea-stories/packages/backend/src/types.ts +++ b/deep-sea-stories/packages/backend/src/types.ts @@ -1,4 +1,5 @@ export interface Story { + title: string; front: string; back: string; } diff --git a/deep-sea-stories/packages/backend/src/utils.ts b/deep-sea-stories/packages/backend/src/utils.ts index ecacfcd..41bd669 100644 --- a/deep-sea-stories/packages/backend/src/utils.ts +++ b/deep-sea-stories/packages/backend/src/utils.ts @@ -1,10 +1,6 @@ -import { stories, AGENT_INSTRUCTIONS_TEMPLATE } from './config.js'; +import { AGENT_INSTRUCTIONS_TEMPLATE } from './config.js'; import type { Story } from './types.js'; -export function getRandomStory(): Story { - return stories[Math.floor(Math.random() * stories.length)]; -} - export function getInstructionsForStory(story: Story): string { return AGENT_INSTRUCTIONS_TEMPLATE.replace('{{FRONT}}', story.front).replace( '{{BACK}}', diff --git a/deep-sea-stories/packages/backend/tests/utils.test.ts b/deep-sea-stories/packages/backend/tests/utils.test.ts index ad8c72e..5b916cf 100644 --- a/deep-sea-stories/packages/backend/tests/utils.test.ts +++ b/deep-sea-stories/packages/backend/tests/utils.test.ts @@ -1,30 +1,12 @@ import { test, describe } from 'node:test'; import assert from 'node:assert'; -import { getRandomStory, getInstructionsForStory } from '../src/utils.js'; +import { getInstructionsForStory } from '../src/utils.js'; import type { Story } from '../src/types.js'; describe('Stories Service', () => { - test('getRandomStory should return a valid Story object', () => { - const story = getRandomStory(); - - assert.strictEqual(typeof story, 'object'); - assert(story !== null, 'Story should not be null'); - - assert( - typeof story.front === 'string', - 'Story should have a front property of type string', - ); - assert( - typeof story.back === 'string', - 'Story should have a back property of type string', - ); - - assert(story.front.length > 0, 'Story front should not be empty'); - assert(story.back.length > 0, 'Story back should not be empty'); - }); - test('getInstructionsForStory should replace template placeholders', () => { const testStory: Story = { + title: 'Test Story', front: 'Test front story', back: 'Test back story', }; From 3e357eee6831962f49add195dbe44574eabcddeb Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Tue, 7 Oct 2025 20:02:30 +0200 Subject: [PATCH 29/65] extract game starting stopping to separate file --- .../backend/src/controllers/stories.ts | 46 ++----- .../packages/backend/src/service/game.ts | 124 ++++++++++++++++++ .../packages/backend/src/service/notifier.ts | 43 ++---- .../packages/backend/src/service/room.ts | 10 +- 4 files changed, 152 insertions(+), 71 deletions(-) create mode 100644 deep-sea-stories/packages/backend/src/service/game.ts diff --git a/deep-sea-stories/packages/backend/src/controllers/stories.ts b/deep-sea-stories/packages/backend/src/controllers/stories.ts index 8fcfc5e..a54e4be 100644 --- a/deep-sea-stories/packages/backend/src/controllers/stories.ts +++ b/deep-sea-stories/packages/backend/src/controllers/stories.ts @@ -1,7 +1,7 @@ import { publicProcedure } from '../trpc.js'; import { stories } from '../config.js'; import { startStoryInputSchema } from '../schemas.js'; -import { roomService } from '../service/room.js'; +import { gameService } from '../service/game.js'; import type { RoomId } from '@fishjam-cloud/js-server-sdk'; export const startStory = publicProcedure @@ -11,44 +11,20 @@ export const startStory = publicProcedure if (!selectedStory) { throw new Error(`Story with title ${input.storyTitle} does not exist`); } - roomService.setStory(input.roomId as RoomId, selectedStory); - // Create AI agent sessions for all currently connected peers - const connectedPeerIds = roomService.getConnectedPeers( - input.roomId as RoomId, - ); - const sessionManager = roomService.getSessionManager( - input.roomId as RoomId, - ); + try { + await gameService.startGame(input.roomId as RoomId, selectedStory); - if (sessionManager && connectedPeerIds.length > 0) { - console.log( - `Creating AI sessions for ${connectedPeerIds.length} connected peers in room ${input.roomId}`, - ); - - // Create sessions for all connected peers - await Promise.all( - connectedPeerIds.map(async (peerId) => { - try { - await sessionManager.createSession(peerId, input.roomId as RoomId); - console.log( - `Created AI session for peer ${peerId} in room ${input.roomId}`, - ); - } catch (error) { - console.error( - `Failed to create session for peer ${peerId}:`, - error, - ); - } - }), + return { + success: true, + message: `Story "${input.storyTitle}" started successfully`, + }; + } catch (error) { + console.error(`Failed to start story: ${error}`); + throw new Error( + `Failed to start story: ${error instanceof Error ? error.message : 'Unknown error'}`, ); } - - return { - success: true, - message: `Story "${input.storyTitle}" started successfully`, - sessionsCreated: connectedPeerIds.length, - }; }); export const getStories = publicProcedure.query(() => { diff --git a/deep-sea-stories/packages/backend/src/service/game.ts b/deep-sea-stories/packages/backend/src/service/game.ts new file mode 100644 index 0000000..f1f61b0 --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/game.ts @@ -0,0 +1,124 @@ +import type { PeerId, RoomId } from '@fishjam-cloud/js-server-sdk'; +import { roomService } from './room.js'; +import type { Story } from '../types.js'; + +class GameService { + async startGame(roomId: RoomId, story: Story): Promise { + roomService.setStory(roomId, story); + + const connectedPeerIds = roomService.getConnectedPeers(roomId); + + if (connectedPeerIds.length > 0) { + console.log( + `Starting game for ${connectedPeerIds.length} connected peers in room ${roomId}`, + ); + + await this.startGameForPeers(roomId, connectedPeerIds); + } + } + + async startGameForPeers(roomId: RoomId, peerIds: PeerId[]): Promise { + const sessionManager = roomService.getSessionManager(roomId); + + if (!sessionManager) { + throw new Error(`No session manager found for room ${roomId}`); + } + + await Promise.all( + peerIds.map(async (peerId) => { + try { + await this.startGameForPeer(roomId, peerId); + } catch (error) { + console.error( + `Failed to start game for peer ${peerId} in room ${roomId}:`, + error, + ); + } + }), + ); + } + + async startGameForPeer(roomId: RoomId, peerId: PeerId): Promise { + const story = roomService.getStory(roomId); + if (!story) { + throw new Error(`No active game found for room ${roomId}`); + } + + const sessionManager = roomService.getSessionManager(roomId); + if (!sessionManager) { + throw new Error(`No session manager found for room ${roomId}`); + } + + try { + await sessionManager.createSession(peerId, roomId); + console.log(`Started game session for peer ${peerId} in room ${roomId}`); + + this.setupAudioStreaming(roomId, peerId); + } catch (error) { + console.error(`Failed to start game session for peer ${peerId}:`, error); + throw error; + } + } + + private setupAudioStreaming(roomId: RoomId, peerId: PeerId): void { + const fishjamAgent = roomService.getAgent(roomId); + const sessionManager = roomService.getSessionManager(roomId); + + if (!fishjamAgent || !sessionManager) { + console.error( + `Cannot setup audio streaming: missing agent or session manager for room ${roomId}`, + ); + return; + } + + fishjamAgent.on('trackData', (trackMsg) => { + const connectedPeers = roomService.getConnectedPeers(roomId); + if (!connectedPeers.includes(peerId)) { + return; + } + + const { data } = trackMsg; + const session = sessionManager.getSession(peerId); + + if (session && data) { + console.log( + `Sending ${data.byteLength} bytes of audio data to ElevenLabs for peer ${peerId}`, + ); + try { + const audioBuffer = Buffer.from(data); + session.sendAudio(audioBuffer); + } catch (error) { + console.error( + `Error sending audio to ElevenLabs for peer ${peerId}:`, + error, + ); + } + } + }); + } + + isGameActive(roomId: RoomId): boolean { + return roomService.getStory(roomId) !== undefined; + } + + async stopGame(roomId: RoomId): Promise { + const sessionManager = roomService.getSessionManager(roomId); + if (sessionManager) { + await sessionManager.cleanup(); + } + + roomService.setStory(roomId, null); + + console.log(`Stopped game for room ${roomId}`); + } + + async removePeerFromGame(roomId: RoomId, peerId: PeerId): Promise { + const sessionManager = roomService.getSessionManager(roomId); + if (sessionManager) { + await sessionManager.deleteSession(peerId); + console.log(`Removed peer ${peerId} from game in room ${roomId}`); + } + } +} + +export const gameService = new GameService(); diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 078356e..342bbbb 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -1,6 +1,7 @@ import { FishjamWSNotifier } from '@fishjam-cloud/js-server-sdk'; import { CONFIG } from '../config.js'; import { roomService } from './room.js'; +import { gameService } from './game.js'; class NotifierService { private notifier: FishjamWSNotifier | null = null; @@ -29,56 +30,32 @@ class NotifierService { private setupEventHandlers() { if (!this.notifier) return; + this.notifier.on('peerConnected', async (msg) => { console.log(`Peer connected: ${msg.peerId} in room ${msg.roomId}`); roomService.addConnectedPeer(msg.roomId, msg.peerId); - const story = roomService.getStory(msg.roomId); - if (story) { - const sessionManager = roomService.getSessionManager(msg.roomId); + if (gameService.isGameActive(msg.roomId)) { try { - await sessionManager?.createSession(msg.peerId, msg.roomId); - console.log( - `Created AI session for peer ${msg.peerId} in room ${msg.roomId}`, - ); + await gameService.startGameForPeer(msg.roomId, msg.peerId); } catch (error) { console.error( - `Failed to create session for peer ${msg.peerId}:`, + `Failed to start game for newly connected peer ${msg.peerId}:`, error, ); } } - - const fishjam_agent = roomService.getAgent(msg.roomId); - fishjam_agent?.on('trackData', (trackMsg) => { - const { data, peerId } = trackMsg; - - const sessionManager = roomService.getSessionManager(msg.roomId); - const session = sessionManager?.getSession(peerId); - - if (session && data) { - console.log( - `Sending ${data.byteLength} bytes of audio data to ElevenLabs for peer ${peerId}`, - ); - try { - const audioBuffer = Buffer.from(data); - session.sendAudio(audioBuffer); - } catch (error) { - console.error( - `Error sending audio to ElevenLabs for peer ${peerId}:`, - error, - ); - } - } - }); }); this.notifier.on('peerDisconnected', async (msg) => { console.log(`Peer disconnected: ${msg.peerId} from room ${msg.roomId}`); + roomService.removeConnectedPeer(msg.roomId, msg.peerId); - const sessionManager = roomService.getSessionManager(msg.roomId); - await sessionManager?.deleteSession(msg.peerId); + + if (gameService.isGameActive(msg.roomId)) { + await gameService.removePeerFromGame(msg.roomId, msg.peerId); + } }); } } diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index a916e7a..46937fa 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -16,7 +16,7 @@ class RoomService { private RoomToFishjamAgent = new Map(); private RoomToSessionManager = new Map(); - getStory(roomId: RoomId) { + getStory(roomId: RoomId): Story | undefined { return this.RoomToStory.get(roomId); } @@ -53,8 +53,12 @@ class RoomService { return this.RoomToSessionManager.get(roomId); } - setStory(roomId: RoomId, story: Story) { - this.RoomToStory.set(roomId, story); + setStory(roomId: RoomId, story: Story | null) { + if (story === null) { + this.RoomToStory.delete(roomId); + } else { + this.RoomToStory.set(roomId, story); + } } async createPeer(roomId: RoomId, fishjam: FishjamClient) { From 9ee5740e617e6776fb893d583123697e6e1f2b73 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Wed, 8 Oct 2025 15:09:24 +0200 Subject: [PATCH 30/65] almost works --- .../backend/src/service/elevenlabs.ts | 14 +++-- .../packages/backend/src/service/game.ts | 51 ++++++++++++++----- .../packages/backend/src/service/notifier.ts | 6 ++- .../packages/backend/src/service/room.ts | 9 +++- .../packages/backend/src/service/session.ts | 10 ++-- 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts index 71bb21a..fc6ae1d 100644 --- a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts @@ -27,12 +27,18 @@ interface ElevenLabsMessage { client_tool_call?: unknown; } -interface ConversationConfig { - agent_prompt?: string; +interface Prompt { + prompt?: string; +} + +interface AgentConfig { first_message?: string; language?: string; - voice_id?: string; - [key: string]: unknown; + prompt?: Prompt; +} + +interface ConversationConfig { + agent?: AgentConfig; } interface AgentCreateRequest { diff --git a/deep-sea-stories/packages/backend/src/service/game.ts b/deep-sea-stories/packages/backend/src/service/game.ts index f1f61b0..c853a0c 100644 --- a/deep-sea-stories/packages/backend/src/service/game.ts +++ b/deep-sea-stories/packages/backend/src/service/game.ts @@ -1,4 +1,4 @@ -import type { PeerId, RoomId } from '@fishjam-cloud/js-server-sdk'; +import type { PeerId, RoomId, TrackId } from '@fishjam-cloud/js-server-sdk'; import { roomService } from './room.js'; import type { Story } from '../types.js'; @@ -36,6 +36,7 @@ class GameService { } }), ); + this.setupAudioStreaming(roomId); } async startGameForPeer(roomId: RoomId, peerId: PeerId): Promise { @@ -52,17 +53,16 @@ class GameService { try { await sessionManager.createSession(peerId, roomId); console.log(`Started game session for peer ${peerId} in room ${roomId}`); - - this.setupAudioStreaming(roomId, peerId); } catch (error) { console.error(`Failed to start game session for peer ${peerId}:`, error); throw error; } } - private setupAudioStreaming(roomId: RoomId, peerId: PeerId): void { - const fishjamAgent = roomService.getAgent(roomId); + private setupAudioStreaming(roomId: RoomId): void { + const { fishjamAgent } = roomService.getAgent(roomId); const sessionManager = roomService.getSessionManager(roomId); + const connectedPeers = roomService.getConnectedPeers(roomId); if (!fishjamAgent || !sessionManager) { console.error( @@ -72,29 +72,56 @@ class GameService { } fishjamAgent.on('trackData', (trackMsg) => { - const connectedPeers = roomService.getConnectedPeers(roomId); - if (!connectedPeers.includes(peerId)) { + if (!connectedPeers.includes(trackMsg.peerId)) { return; } const { data } = trackMsg; - const session = sessionManager.getSession(peerId); + const session = sessionManager.getSession(trackMsg.peerId); if (session && data) { - console.log( - `Sending ${data.byteLength} bytes of audio data to ElevenLabs for peer ${peerId}`, - ); try { const audioBuffer = Buffer.from(data); session.sendAudio(audioBuffer); } catch (error) { console.error( - `Error sending audio to ElevenLabs for peer ${peerId}:`, + `Error sending audio to ElevenLabs for peer ${trackMsg.peerId}:`, error, ); } } }); + const audioTrack = fishjamAgent.createTrack({ + encoding: 'pcm16', + sampleRate: 16000, + channels: 1, + }); + + for (const peerId of connectedPeers) { + try { + const agentSession = sessionManager.getSession(peerId); + agentSession?.on('agentAudio', (audioEvent) => { + try { + const audioBuffer = Uint8Array.from( + atob(audioEvent.audio_base_64), + (c) => c.charCodeAt(0), + ); + if (!audioBuffer) { + console.error('Received empty audio buffer from ElevenLabs'); + return; + } + fishjamAgent.sendData(audioTrack.id as TrackId, audioBuffer); + } catch (error) { + console.error('Error sending agent audio track to room:', error); + } + }); + } catch (error) { + console.error( + `Error setting up agent audio for peer ${peerId}:`, + error, + ); + } + } } isGameActive(roomId: RoomId): boolean { diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 342bbbb..ca10f23 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -16,7 +16,7 @@ class NotifierService { managementToken: CONFIG.FISHJAM_MANAGEMENT_TOKEN, }, (msg) => { - console.log(`Got error: ${msg}`); + console.log(`FishjamWSNotifier got error: ${msg}`); }, (code, reason) => { console.log( @@ -33,6 +33,10 @@ class NotifierService { this.notifier.on('peerConnected', async (msg) => { console.log(`Peer connected: ${msg.peerId} in room ${msg.roomId}`); + const { peerId } = roomService.getAgent(msg.roomId); + if (msg.peerId === peerId) { + return; + } roomService.addConnectedPeer(msg.roomId, msg.peerId); diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index 46937fa..a74aa9a 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -14,6 +14,7 @@ class RoomService { private RoomToPeers = new Map(); private RoomToConnectedPeers = new Map>(); private RoomToFishjamAgent = new Map(); + private RoomToFishjamAgentId = new Map(); private RoomToSessionManager = new Map(); getStory(roomId: RoomId): Story | undefined { @@ -21,7 +22,10 @@ class RoomService { } getAgent(roomId: RoomId) { - return this.RoomToFishjamAgent.get(roomId); + return { + fishjamAgent: this.RoomToFishjamAgent.get(roomId), + peerId: this.RoomToFishjamAgentId.get(roomId), + }; } getPeers(roomId: RoomId) { @@ -70,7 +74,7 @@ class RoomService { } async createFishjamAgent(roomId: RoomId, fishjam: FishjamClient) { - const { agent } = await fishjam.createAgent( + const { agent, peer } = await fishjam.createAgent( roomId, FISHJAM_AGENT_OPTIONS, (msg) => { @@ -84,6 +88,7 @@ class RoomService { ); this.RoomToFishjamAgent.set(roomId, agent); + this.RoomToFishjamAgentId.set(roomId, peer.id); } } diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index 75eb83f..05ff43f 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -21,9 +21,13 @@ export class SessionManager { const instructions = getInstructionsForStory(story); const agentId = await elevenLabs.createAgent({ - agent_prompt: instructions, - first_message: 'Welcome to the deep sea stories!', - language: 'en', + agent: { + first_message: 'Welcome to Deepsea stories', + language: 'en', + prompt: { + prompt: instructions, + }, + }, }); const session = new ElevenLabsConversation( From 80526bea9c5cbd28e2f40ebfd29f7f16f31eb132 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 10 Oct 2025 12:39:24 +0200 Subject: [PATCH 31/65] adjust sample rate to elevenlabs's default --- deep-sea-stories/packages/backend/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index 5faf222..8b71d01 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -31,6 +31,6 @@ export const AGENT_INSTRUCTIONS_TEMPLATE = fs.readFileSync( export const FISHJAM_AGENT_OPTIONS: PeerOptions = { output: { - audioSampleRate: 24_000, + audioSampleRate: 16_000, }, }; From c4796786912b820031f9842b0bdbb3fa06edfbef Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 10 Oct 2025 14:56:44 +0200 Subject: [PATCH 32/65] apply comment suggestions --- .../packages/backend/src/service/game.ts | 12 +++++++----- .../packages/backend/src/service/notifier.ts | 17 ++++++++--------- .../packages/backend/src/service/room.ts | 8 ++++---- .../packages/backend/src/service/session.ts | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/service/game.ts b/deep-sea-stories/packages/backend/src/service/game.ts index c853a0c..9f81453 100644 --- a/deep-sea-stories/packages/backend/src/service/game.ts +++ b/deep-sea-stories/packages/backend/src/service/game.ts @@ -14,11 +14,13 @@ class GameService { ); await this.startGameForPeers(roomId, connectedPeerIds); + } else { + throw new Error(`No connected peers in room ${roomId}`); } } async startGameForPeers(roomId: RoomId, peerIds: PeerId[]): Promise { - const sessionManager = roomService.getSessionManager(roomId); + const sessionManager = roomService.getAiSessionManager(roomId); if (!sessionManager) { throw new Error(`No session manager found for room ${roomId}`); @@ -45,7 +47,7 @@ class GameService { throw new Error(`No active game found for room ${roomId}`); } - const sessionManager = roomService.getSessionManager(roomId); + const sessionManager = roomService.getAiSessionManager(roomId); if (!sessionManager) { throw new Error(`No session manager found for room ${roomId}`); } @@ -61,7 +63,7 @@ class GameService { private setupAudioStreaming(roomId: RoomId): void { const { fishjamAgent } = roomService.getAgent(roomId); - const sessionManager = roomService.getSessionManager(roomId); + const sessionManager = roomService.getAiSessionManager(roomId); const connectedPeers = roomService.getConnectedPeers(roomId); if (!fishjamAgent || !sessionManager) { @@ -129,7 +131,7 @@ class GameService { } async stopGame(roomId: RoomId): Promise { - const sessionManager = roomService.getSessionManager(roomId); + const sessionManager = roomService.getAiSessionManager(roomId); if (sessionManager) { await sessionManager.cleanup(); } @@ -140,7 +142,7 @@ class GameService { } async removePeerFromGame(roomId: RoomId, peerId: PeerId): Promise { - const sessionManager = roomService.getSessionManager(roomId); + const sessionManager = roomService.getAiSessionManager(roomId); if (sessionManager) { await sessionManager.deleteSession(peerId); console.log(`Removed peer ${peerId} from game in room ${roomId}`); diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index ca10f23..8d91444 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -39,16 +39,15 @@ class NotifierService { } roomService.addConnectedPeer(msg.roomId, msg.peerId); + if (gameService.isGameActive(msg.roomId)) return; - if (gameService.isGameActive(msg.roomId)) { - try { - await gameService.startGameForPeer(msg.roomId, msg.peerId); - } catch (error) { - console.error( - `Failed to start game for newly connected peer ${msg.peerId}:`, - error, - ); - } + try { + await gameService.startGameForPeer(msg.roomId, msg.peerId); + } catch (error) { + console.error( + `Failed to start game for newly connected peer ${msg.peerId}:`, + error, + ); } }); diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index a74aa9a..b3457f1 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -7,7 +7,7 @@ import type { } from '@fishjam-cloud/js-server-sdk'; import type { Story } from '../types.js'; import { FISHJAM_AGENT_OPTIONS } from '../config.js'; -import { SessionManager } from './session.js'; +import { AiSessionManager } from './session.js'; class RoomService { private RoomToStory = new Map(); @@ -15,7 +15,7 @@ class RoomService { private RoomToConnectedPeers = new Map>(); private RoomToFishjamAgent = new Map(); private RoomToFishjamAgentId = new Map(); - private RoomToSessionManager = new Map(); + private RoomToSessionManager = new Map(); getStory(roomId: RoomId): Story | undefined { return this.RoomToStory.get(roomId); @@ -50,9 +50,9 @@ class RoomService { } } - getSessionManager(roomId: RoomId) { + getAiSessionManager(roomId: RoomId) { if (!this.RoomToSessionManager.get(roomId)) { - this.RoomToSessionManager.set(roomId, new SessionManager()); + this.RoomToSessionManager.set(roomId, new AiSessionManager()); } return this.RoomToSessionManager.get(roomId); } diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index 05ff43f..c4093e3 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -4,7 +4,7 @@ import { roomService } from './room.js'; import { getInstructionsForStory } from '../utils.js'; import { CONFIG } from '../config.js'; -export class SessionManager { +export class AiSessionManager { private sessions = new Map(); async createSession( From 241d7dd5fa8b053916846ccc4a5d05cb56d2f423 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 10 Oct 2025 15:02:49 +0200 Subject: [PATCH 33/65] throw when room nonempty with no fishjam agent --- deep-sea-stories/packages/backend/src/controllers/peers.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index d88f965..5b687ca 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -10,6 +10,12 @@ export const createPeer = publicProcedure if (!room) { throw new Error(`Room with id ${input.roomId} does not exist`); } + const roomAgent = roomService.getAgent(room.id); + if (room.peers.length > 0 && !roomAgent) { + throw new Error( + `Room with id ${input.roomId} already has a peer and no agent`, + ); + } if (room.peers.length === 0) { await roomService.createFishjamAgent(room.id, ctx.fishjam); } From 0ef8e4410ad6e3935e6da161e6b34a8851f9bd9b Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 13 Oct 2025 16:04:18 +0200 Subject: [PATCH 34/65] apply comment suggestions --- .../packages/backend/src/service/game.ts | 23 +++++++++---------- .../packages/backend/src/service/room.ts | 8 +++---- .../packages/backend/src/service/session.ts | 2 +- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/service/game.ts b/deep-sea-stories/packages/backend/src/service/game.ts index 9f81453..9655539 100644 --- a/deep-sea-stories/packages/backend/src/service/game.ts +++ b/deep-sea-stories/packages/backend/src/service/game.ts @@ -8,19 +8,18 @@ class GameService { const connectedPeerIds = roomService.getConnectedPeers(roomId); - if (connectedPeerIds.length > 0) { - console.log( - `Starting game for ${connectedPeerIds.length} connected peers in room ${roomId}`, - ); - - await this.startGameForPeers(roomId, connectedPeerIds); - } else { + if (!connectedPeerIds.length) { throw new Error(`No connected peers in room ${roomId}`); } + console.log( + `Starting game for ${connectedPeerIds.length} connected peers in room ${roomId}`, + ); + + await this.startGameForPeers(roomId, connectedPeerIds); } async startGameForPeers(roomId: RoomId, peerIds: PeerId[]): Promise { - const sessionManager = roomService.getAiSessionManager(roomId); + const sessionManager = roomService.getElevenLabsSessionManager(roomId); if (!sessionManager) { throw new Error(`No session manager found for room ${roomId}`); @@ -47,7 +46,7 @@ class GameService { throw new Error(`No active game found for room ${roomId}`); } - const sessionManager = roomService.getAiSessionManager(roomId); + const sessionManager = roomService.getElevenLabsSessionManager(roomId); if (!sessionManager) { throw new Error(`No session manager found for room ${roomId}`); } @@ -63,7 +62,7 @@ class GameService { private setupAudioStreaming(roomId: RoomId): void { const { fishjamAgent } = roomService.getAgent(roomId); - const sessionManager = roomService.getAiSessionManager(roomId); + const sessionManager = roomService.getElevenLabsSessionManager(roomId); const connectedPeers = roomService.getConnectedPeers(roomId); if (!fishjamAgent || !sessionManager) { @@ -131,7 +130,7 @@ class GameService { } async stopGame(roomId: RoomId): Promise { - const sessionManager = roomService.getAiSessionManager(roomId); + const sessionManager = roomService.getElevenLabsSessionManager(roomId); if (sessionManager) { await sessionManager.cleanup(); } @@ -142,7 +141,7 @@ class GameService { } async removePeerFromGame(roomId: RoomId, peerId: PeerId): Promise { - const sessionManager = roomService.getAiSessionManager(roomId); + const sessionManager = roomService.getElevenLabsSessionManager(roomId); if (sessionManager) { await sessionManager.deleteSession(peerId); console.log(`Removed peer ${peerId} from game in room ${roomId}`); diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index b3457f1..bca24bc 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -7,7 +7,7 @@ import type { } from '@fishjam-cloud/js-server-sdk'; import type { Story } from '../types.js'; import { FISHJAM_AGENT_OPTIONS } from '../config.js'; -import { AiSessionManager } from './session.js'; +import { ElevenLabsSessionManager } from './session.js'; class RoomService { private RoomToStory = new Map(); @@ -15,7 +15,7 @@ class RoomService { private RoomToConnectedPeers = new Map>(); private RoomToFishjamAgent = new Map(); private RoomToFishjamAgentId = new Map(); - private RoomToSessionManager = new Map(); + private RoomToSessionManager = new Map(); getStory(roomId: RoomId): Story | undefined { return this.RoomToStory.get(roomId); @@ -50,9 +50,9 @@ class RoomService { } } - getAiSessionManager(roomId: RoomId) { + getElevenLabsSessionManager(roomId: RoomId) { if (!this.RoomToSessionManager.get(roomId)) { - this.RoomToSessionManager.set(roomId, new AiSessionManager()); + this.RoomToSessionManager.set(roomId, new ElevenLabsSessionManager()); } return this.RoomToSessionManager.get(roomId); } diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index c4093e3..2bd966f 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -4,7 +4,7 @@ import { roomService } from './room.js'; import { getInstructionsForStory } from '../utils.js'; import { CONFIG } from '../config.js'; -export class AiSessionManager { +export class ElevenLabsSessionManager { private sessions = new Map(); async createSession( From f366650a575749bca0509dac9655427327844ad2 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 13 Oct 2025 16:08:02 +0200 Subject: [PATCH 35/65] fix adding peer during game logic --- deep-sea-stories/packages/backend/src/service/notifier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index 8d91444..ed7fb75 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -39,7 +39,7 @@ class NotifierService { } roomService.addConnectedPeer(msg.roomId, msg.peerId); - if (gameService.isGameActive(msg.roomId)) return; + if (!gameService.isGameActive(msg.roomId)) return; try { await gameService.startGameForPeer(msg.roomId, msg.peerId); From ec8669cccff3f0f6c76b8f1fdee0bff9f5de4072 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur <47872060+AHGIJMKLKKZNPJKQR@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:18:58 +0200 Subject: [PATCH 36/65] Safelist grid cols --- deep-sea-stories/packages/web/src/index.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css index a98e4e7..258b6b6 100644 --- a/deep-sea-stories/packages/web/src/index.css +++ b/deep-sea-stories/packages/web/src/index.css @@ -3,6 +3,8 @@ @import "tailwindcss"; @import "tw-animate-css"; +@source inline("grid-cols-{1..4..1}") + @custom-variant dark (&:is(.dark *)); @theme { From 4b21f8489f6545cad6461730259dd1ff724ea47d Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Wed, 15 Oct 2025 15:09:41 +0200 Subject: [PATCH 37/65] builting websocket, implement creating agent using elevenlabs-js --- .../packages/backend/package.json | 2 +- .../backend/src/service/elevenlabs.ts | 98 +++---------------- .../packages/backend/src/service/game.ts | 6 -- .../packages/backend/src/service/session.ts | 16 +-- deep-sea-stories/yarn.lock | 72 +++++++++++--- 5 files changed, 79 insertions(+), 115 deletions(-) diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 674dc0b..661de91 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -4,13 +4,13 @@ "main": "./src/main.ts", "type": "module", "dependencies": { + "@elevenlabs/elevenlabs-js": "^2.19.0", "@fishjam-cloud/js-server-sdk": "^0.22.0", "@trpc/server": "^11.6.0", "@types/ws": "^8.18.1", "dotenv": "^17.2.3", "fastify": "^5.6.1", "pino-pretty": "^13.1.1", - "ws": "^8.18.3", "zod": "^4.1.11" }, "devDependencies": { diff --git a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts index fc6ae1d..3d9d9c7 100644 --- a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts @@ -1,6 +1,6 @@ import { CONFIG } from '../config.js'; -import WebSocket from 'ws'; import { EventEmitter } from 'node:events'; +import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'; interface ConversationInitiationMetadataEvent { conversation_id: string; @@ -27,84 +27,10 @@ interface ElevenLabsMessage { client_tool_call?: unknown; } -interface Prompt { - prompt?: string; -} - -interface AgentConfig { - first_message?: string; - language?: string; - prompt?: Prompt; -} - -interface ConversationConfig { - agent?: AgentConfig; -} - -interface AgentCreateRequest { - conversation_config: ConversationConfig; - platform_settings?: { - [key: string]: unknown; - }; - name?: string; - tags?: string[]; -} - export interface AgentId { agent_id: string; } -class ElevenLabs { - private apiKey: string; - private baseUrl: string = 'https://api.elevenlabs.io'; - - constructor(apiKey: string) { - this.apiKey = apiKey; - } - - async createAgent( - conversationConfig: ConversationConfig, - options?: { - name?: string; - tags?: string[]; - platformSettings?: { [key: string]: unknown }; - }, - ): Promise { - try { - const requestBody: AgentCreateRequest = { - conversation_config: conversationConfig, - ...(options?.name && { name: options.name }), - ...(options?.tags && { tags: options.tags }), - ...(options?.platformSettings && { - platform_settings: options.platformSettings, - }), - }; - - const response = await fetch(`${this.baseUrl}/v1/convai/agents/create`, { - method: 'POST', - headers: { - 'xi-api-key': this.apiKey, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(requestBody), - }); - - if (!response.ok) { - const errorText = await response.text(); - throw new Error( - `ElevenLabs API error: ${response.status} ${response.statusText} - ${errorText}`, - ); - } - - return (await response.json()) as AgentId; - } catch (error) { - throw new Error( - `Failed to create ElevenLabs agent: ${error instanceof Error ? error.message : 'Unknown error'}`, - ); - } - } -} - /** * WebSocket-based conversation with ElevenLabs for real-time audio streaming * https://elevenlabs.io/docs/agents-platform/api-reference/agents-platform/websocket @@ -150,7 +76,7 @@ export class ElevenLabsConversation extends EventEmitter { }, }); - this.ws.on('open', () => { + this.ws.addEventListener('open', () => { console.log('Connected to ElevenLabs WebSocket'); this.isConnected = true; @@ -162,27 +88,27 @@ export class ElevenLabsConversation extends EventEmitter { resolve(); }); - this.ws.on('message', (data: Buffer) => { + this.ws.addEventListener('message', (event) => { try { - const message = JSON.parse(data.toString()); + const message = JSON.parse(event.data.toString()); this.handleMessage(message); } catch (error) { console.error('Failed to parse WebSocket message:', error); } }); - this.ws.on('close', (code: number, reason: Buffer) => { + this.ws.addEventListener('close', (event) => { console.log( - `ElevenLabs WebSocket connection closed: ${code} - ${reason.toString()}`, + `ElevenLabs WebSocket connection closed: ${event.code} - ${event.reason}`, ); this.isConnected = false; - this.emit('disconnected', { code, reason: reason.toString() }); + this.emit('disconnected', { code: event.code, reason: event.reason }); }); - this.ws.on('error', (error) => { - console.error('ElevenLabs WebSocket error:', error); + this.ws.addEventListener('error', (event) => { + console.error('ElevenLabs WebSocket error:', event); this.isConnected = false; - reject(error); + reject(new Error('WebSocket error occurred')); }); } catch (error) { reject(error); @@ -356,4 +282,6 @@ export class ElevenLabsConversation extends EventEmitter { } } -export const elevenLabs = new ElevenLabs(CONFIG.ELEVENLABS_API_KEY); +export const elevenLabs = new ElevenLabsClient({ + apiKey: CONFIG.ELEVENLABS_API_KEY, +}); diff --git a/deep-sea-stories/packages/backend/src/service/game.ts b/deep-sea-stories/packages/backend/src/service/game.ts index 9655539..a4b9e93 100644 --- a/deep-sea-stories/packages/backend/src/service/game.ts +++ b/deep-sea-stories/packages/backend/src/service/game.ts @@ -19,12 +19,6 @@ class GameService { } async startGameForPeers(roomId: RoomId, peerIds: PeerId[]): Promise { - const sessionManager = roomService.getElevenLabsSessionManager(roomId); - - if (!sessionManager) { - throw new Error(`No session manager found for room ${roomId}`); - } - await Promise.all( peerIds.map(async (peerId) => { try { diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index 2bd966f..823c85c 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -20,18 +20,20 @@ export class ElevenLabsSessionManager { const instructions = getInstructionsForStory(story); - const agentId = await elevenLabs.createAgent({ - agent: { - first_message: 'Welcome to Deepsea stories', - language: 'en', - prompt: { - prompt: instructions, + const { agentId } = await elevenLabs.conversationalAi.agents.create({ + conversationConfig: { + agent: { + firstMessage: 'Welcome to Deepsea stories', + language: 'en', + prompt: { + prompt: instructions, + }, }, }, }); const session = new ElevenLabsConversation( - agentId.agent_id, + agentId, CONFIG.ELEVENLABS_API_KEY, ); await session.connect(); diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index efa24bb..801b472 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -300,6 +300,16 @@ __metadata: languageName: node linkType: hard +"@elevenlabs/elevenlabs-js@npm:^2.19.0": + version: 2.19.0 + resolution: "@elevenlabs/elevenlabs-js@npm:2.19.0" + dependencies: + command-exists: "npm:^1.2.9" + node-fetch: "npm:^2.7.0" + checksum: 10c0/1d2a055767f1e0b5804fc85929857a7d39623fca5fc3756d35e3bf7b1e857e9bfcfe94b69ad54269f967d2d60b90b1665f3ab1c17c23f61c71b043a45425cd66 + languageName: node + linkType: hard + "@emnapi/core@npm:^1.4.3, @emnapi/core@npm:^1.4.5": version: 1.5.0 resolution: "@emnapi/core@npm:1.5.0" @@ -1350,6 +1360,7 @@ __metadata: version: 0.0.0-use.local resolution: "backend@workspace:packages/backend" dependencies: + "@elevenlabs/elevenlabs-js": "npm:^2.19.0" "@fishjam-cloud/js-server-sdk": "npm:^0.22.0" "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" @@ -1359,7 +1370,6 @@ __metadata: fastify: "npm:^5.6.1" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" - ws: "npm:^8.18.3" zod: "npm:^4.1.11" languageName: unknown linkType: soft @@ -1496,6 +1506,13 @@ __metadata: languageName: node linkType: hard +"command-exists@npm:^1.2.9": + version: 1.2.9 + resolution: "command-exists@npm:1.2.9" + checksum: 10c0/75040240062de46cd6cd43e6b3032a8b0494525c89d3962e280dde665103f8cc304a8b313a5aa541b91da2f5a9af75c5959dc3a77893a2726407a5e9a0234c16 + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -2567,6 +2584,20 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^2.7.0": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: "npm:^5.0.0" + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 11.4.2 resolution: "node-gyp@npm:11.4.2" @@ -3206,6 +3237,13 @@ __metadata: languageName: node linkType: hard +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 + languageName: node + linkType: hard + "tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" @@ -3394,6 +3432,23 @@ __metadata: languageName: unknown linkType: soft +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 + languageName: node + linkType: hard + "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -3445,21 +3500,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.18.3": - version: 8.18.3 - resolution: "ws@npm:8.18.3" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10c0/eac918213de265ef7cb3d4ca348b891a51a520d839aa51cdb8ca93d4fa7ff9f6ccb339ccee89e4075324097f0a55157c89fa3f7147bde9d8d7e90335dc087b53 - languageName: node - linkType: hard - "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" From a89a63afb46f40289e68b8dc707fc2877afffd5f Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Wed, 15 Oct 2025 15:51:04 +0200 Subject: [PATCH 38/65] utilize nunjucks add interface for sessions and conversations, add id to stories --- .../packages/backend/package.json | 2 + .../backend/src/controllers/stories.ts | 6 +-- .../src/prompts/instructions-template.md | 4 +- .../packages/backend/src/prompts/stories.json | 10 ++++ .../packages/backend/src/schemas.ts | 2 +- .../backend/src/service/elevenlabs.ts | 18 +++++-- .../packages/backend/src/service/session.ts | 3 +- .../packages/backend/src/types.ts | 12 +++++ .../packages/backend/src/utils.ts | 9 ++-- .../packages/backend/tests/utils.test.ts | 1 + deep-sea-stories/yarn.lock | 48 +++++++++++++++++++ 11 files changed, 100 insertions(+), 15 deletions(-) diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 661de91..295c43a 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -7,9 +7,11 @@ "@elevenlabs/elevenlabs-js": "^2.19.0", "@fishjam-cloud/js-server-sdk": "^0.22.0", "@trpc/server": "^11.6.0", + "@types/nunjucks": "^3.2.6", "@types/ws": "^8.18.1", "dotenv": "^17.2.3", "fastify": "^5.6.1", + "nunjucks": "^3.2.4", "pino-pretty": "^13.1.1", "zod": "^4.1.11" }, diff --git a/deep-sea-stories/packages/backend/src/controllers/stories.ts b/deep-sea-stories/packages/backend/src/controllers/stories.ts index a54e4be..0936bec 100644 --- a/deep-sea-stories/packages/backend/src/controllers/stories.ts +++ b/deep-sea-stories/packages/backend/src/controllers/stories.ts @@ -7,9 +7,9 @@ import type { RoomId } from '@fishjam-cloud/js-server-sdk'; export const startStory = publicProcedure .input(startStoryInputSchema) .mutation(async ({ input }) => { - const selectedStory = stories.find((s) => s.title === input.storyTitle); + const selectedStory = stories.find((s) => s.id === input.storyId); if (!selectedStory) { - throw new Error(`Story with title ${input.storyTitle} does not exist`); + throw new Error(`Story with id ${input.storyId} does not exist`); } try { @@ -17,7 +17,7 @@ export const startStory = publicProcedure return { success: true, - message: `Story "${input.storyTitle}" started successfully`, + message: `Story "${input.storyId}" started successfully`, }; } catch (error) { console.error(`Failed to start story: ${error}`); diff --git a/deep-sea-stories/packages/backend/src/prompts/instructions-template.md b/deep-sea-stories/packages/backend/src/prompts/instructions-template.md index 9fcf390..5f2c863 100644 --- a/deep-sea-stories/packages/backend/src/prompts/instructions-template.md +++ b/deep-sea-stories/packages/backend/src/prompts/instructions-template.md @@ -40,6 +40,6 @@ My role Your card content is: ### Front of the Card -{{FRONT}} +{{ FRONT }} ### Back of the Card -{{BACK}} \ No newline at end of file +{{ BACK }} \ No newline at end of file diff --git a/deep-sea-stories/packages/backend/src/prompts/stories.json b/deep-sea-stories/packages/backend/src/prompts/stories.json index fc8f8db..2641a55 100644 --- a/deep-sea-stories/packages/backend/src/prompts/stories.json +++ b/deep-sea-stories/packages/backend/src/prompts/stories.json @@ -1,50 +1,60 @@ [ { + "id": 1, "title": "Dead Skydiver in a Field", "front": "A man was found dead in the middle of a field. There were no footprints around him and he had nothing in his hands. The only thing on him was a small parachute harness without a parachute attached.", "back": "The man was a skydiver. He had gone on a jump with a group of skydivers and had accidentally grabbed a faulty parachute. Mid-air, when he realized it was not functional, he attempted to fix it but couldn't. As he descended, the wind blew him away from the group, causing him to land in the open field, without any footprints nearby due to being airborne before the landing." }, { + "id": 2, "title": "Locked Apartment Mystery", "front": "A man is found dead in his locked apartment. The door is bolted from the inside, all the windows are closed, and there are no signs of forced entry. Next to him lies a puddle of water and some shattered glass.", "back": "The man had kept a large ice block propped against the door as an improvised barricade, fearing someone was after him. When he sat down to rest, the ice eventually melted, leaving only the puddle of water. The door closed and locked itself, and no one had to enter. He later died of unrelated causes (a heart attack)." }, { + "id": 3, "title": "Dead Men in a Mountain Cabin", "front": "Two men are found dead in a cabin on a mountain. The windows are shattered, but there are no footprints leading away from the cabin.", "back": "The men had been flying in a small airplane that crashed into the mountainside. What the rescuers thought was a 'cabin' was actually the remains of the airplane fuselage. They died on impact, and the shattered 'windows' were airplane windows, not a house." }, { + "id": 4, "title": "Death by Thirst in a Bar", "front": "A man dies of thirst in the middle of a bar full of people. Nobody helped him.", "back": "The bar was not a drinking establishment, but a sandbar in the desert. He was stranded, saw no one around, and perished from dehydration. The wording misleads the guessers into thinking of an alcohol-serving bar." }, { + "id": 5, "title": "Library Blunt Force Trauma", "front": "A body is found in a library, with dozens of books scattered around. Cause of death: blunt force trauma. There are no weapons nearby.", "back": "The man died when a heavy bookshelf collapsed on him while he was trying to reach a book from the top. The books scattered everywhere during the fall, concealing the true cause of his death until closer inspection." }, { + "id": 6, "title": "Hanging in an Empty Room", "front": "A man is found hanged in a room with a ceiling 4 meters high. There is no chair, no furniture, and the floor is bare.", "back": "The man stood on a large block of ice to hang himself. Over time, the ice melted completely, leaving no trace and creating the illusion of an impossible hanging." }, { + "id": 7, "title": "Sailor with Sand-Filled Pockets", "front": "A sailor is found dead on the deck of his ship. His pockets are full of sand, and there are no signs of injury.", "back": "The sailor had been rescued after a shipwreck. During the accident, he swallowed a large amount of seawater containing sand and silt. Though he survived the wreck, he later collapsed and died from internal damage caused by inhaling sand-filled water into his lungs." }, { + "id": 8, "title": "Death in a Phone Booth", "front": "A man lies dead in a phone booth. The glass is shattered, and he is clutching torn pages from a phone book.", "back": "The man was a fisherman who had boasted about the size of a fish he caught. His friends didn’t believe him, so he rushed to the phone booth to call and confirm it with someone. He angrily tore pages looking for the number but accidentally broke the glass and cut himself fatally in his frustration." }, { + "id": 9, "title": "Smiling Woman and Static TV", "front": "A woman is found dead in front of her television. The TV is on, but the screen shows only static. She has a smile on her face.", "back": "The woman had been terminally ill and bedridden. She watched a TV show religiously every week, and on the night of her death, the show aired its final episode. She smiled, having seen the ending she long awaited, and then peacefully passed away. The static was just the end of transmission." }, { + "id": 10, "title": "Shot in a Locked Car", "front": "A man is found shot to death in a car. All the doors are locked from the inside, and there is no gun in the vehicle.", "back": "The man was killed in a drive-by shooting. After he was shot, his car rolled forward and hit an obstacle, automatically locking the central locking system on impact. The attacker left with the weapon, leaving behind a locked car with a dead man inside." diff --git a/deep-sea-stories/packages/backend/src/schemas.ts b/deep-sea-stories/packages/backend/src/schemas.ts index 6ff83ff..bb2d1e1 100644 --- a/deep-sea-stories/packages/backend/src/schemas.ts +++ b/deep-sea-stories/packages/backend/src/schemas.ts @@ -6,5 +6,5 @@ export const createPeerInputSchema = z.object({ roomId: z.string() }); export const startStoryInputSchema = z.object({ roomId: z.string(), - storyTitle: z.string(), + storyId: z.number(), }); diff --git a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts index 3d9d9c7..1731128 100644 --- a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs.ts @@ -1,6 +1,7 @@ import { CONFIG } from '../config.js'; import { EventEmitter } from 'node:events'; import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'; +import type { Conversation } from '../types.js'; interface ConversationInitiationMetadataEvent { conversation_id: string; @@ -46,19 +47,28 @@ export interface AgentId { * - 'clientToolCall': (ClientToolCall) - Client tool call request * - 'disconnected': ({ code, reason }) - When WebSocket disconnects */ -export class ElevenLabsConversation extends EventEmitter { +export class ElevenLabsConversation + extends EventEmitter + implements Conversation +{ private ws: WebSocket | null = null; private conversationId: string | null = null; private isConnected = false; private audioFormat: string | null = null; private inputFormat: string | null = null; + private agentId: string; + private apiKey: string; + private baseUrl: string; constructor( - private agentId: string, - private apiKey: string, - private baseUrl: string = 'wss://api.elevenlabs.io', + agentId: string, + apiKey: string, + baseUrl: string = 'wss://api.elevenlabs.io', ) { super(); + this.agentId = agentId; + this.apiKey = apiKey; + this.baseUrl = baseUrl; } /** diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/session.ts index 823c85c..c6bd3b1 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/session.ts @@ -3,8 +3,9 @@ import { elevenLabs, ElevenLabsConversation } from './elevenlabs.js'; import { roomService } from './room.js'; import { getInstructionsForStory } from '../utils.js'; import { CONFIG } from '../config.js'; +import type { VoiceAgentSessionManager } from '../types.js'; -export class ElevenLabsSessionManager { +export class ElevenLabsSessionManager implements VoiceAgentSessionManager { private sessions = new Map(); async createSession( diff --git a/deep-sea-stories/packages/backend/src/types.ts b/deep-sea-stories/packages/backend/src/types.ts index 0799439..03808e6 100644 --- a/deep-sea-stories/packages/backend/src/types.ts +++ b/deep-sea-stories/packages/backend/src/types.ts @@ -1,5 +1,17 @@ +import type { PeerId, RoomId } from '@fishjam-cloud/js-server-sdk'; export interface Story { + id: number; title: string; front: string; back: string; } + +export interface Conversation { + sendAudio(audioBuffer: Buffer): void; +} + +export interface VoiceAgentSessionManager { + createSession(peerId: PeerId, roomId: RoomId): Promise; + deleteSession(peerId: PeerId): Promise; + getSession(peerId: PeerId): Conversation | undefined; +} diff --git a/deep-sea-stories/packages/backend/src/utils.ts b/deep-sea-stories/packages/backend/src/utils.ts index 41bd669..f9257f7 100644 --- a/deep-sea-stories/packages/backend/src/utils.ts +++ b/deep-sea-stories/packages/backend/src/utils.ts @@ -1,9 +1,10 @@ +import nunjucks from 'nunjucks'; import { AGENT_INSTRUCTIONS_TEMPLATE } from './config.js'; import type { Story } from './types.js'; export function getInstructionsForStory(story: Story): string { - return AGENT_INSTRUCTIONS_TEMPLATE.replace('{{FRONT}}', story.front).replace( - '{{BACK}}', - story.back, - ); + return nunjucks.renderString(AGENT_INSTRUCTIONS_TEMPLATE, { + FRONT: story.front, + BACK: story.back, + }); } diff --git a/deep-sea-stories/packages/backend/tests/utils.test.ts b/deep-sea-stories/packages/backend/tests/utils.test.ts index 5b916cf..e165dca 100644 --- a/deep-sea-stories/packages/backend/tests/utils.test.ts +++ b/deep-sea-stories/packages/backend/tests/utils.test.ts @@ -6,6 +6,7 @@ import type { Story } from '../src/types.js'; describe('Stories Service', () => { test('getInstructionsForStory should replace template placeholders', () => { const testStory: Story = { + id: 999, title: 'Test Story', front: 'Test front story', back: 'Test back story', diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index 801b472..3daff00 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -1178,6 +1178,13 @@ __metadata: languageName: node linkType: hard +"@types/nunjucks@npm:^3.2.6": + version: 3.2.6 + resolution: "@types/nunjucks@npm:3.2.6" + checksum: 10c0/bc62c5c9305c0c63a49a55c3553393fdc84d123b4831668212380077ee6646c3ba52bc49e3c651257addf3a47d775707dcefeaf5e1b76cf7f680096939894142 + languageName: node + linkType: hard + "@types/react-dom@npm:^19.1.9": version: 19.1.9 resolution: "@types/react-dom@npm:19.1.9" @@ -1221,6 +1228,13 @@ __metadata: languageName: node linkType: hard +"a-sync-waterfall@npm:^1.0.0": + version: 1.0.1 + resolution: "a-sync-waterfall@npm:1.0.1" + checksum: 10c0/1c7b258da2c77eb1447dcc683afb10ca3dc8880de990562ccbb7b282538aba01e910345ce9e8500c1458272c7866b85fcfa5ca8159e33550b011ab5c586ec5a4 + languageName: node + linkType: hard + "abbrev@npm:^3.0.0": version: 3.0.1 resolution: "abbrev@npm:3.0.1" @@ -1298,6 +1312,13 @@ __metadata: languageName: node linkType: hard +"asap@npm:^2.0.3": + version: 2.0.6 + resolution: "asap@npm:2.0.6" + checksum: 10c0/c6d5e39fe1f15e4b87677460bd66b66050cd14c772269cee6688824c1410a08ab20254bb6784f9afb75af9144a9f9a7692d49547f4d19d715aeb7c0318f3136d + languageName: node + linkType: hard + "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -1365,9 +1386,11 @@ __metadata: "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" "@types/node": "npm:^24.5.2" + "@types/nunjucks": "npm:^3.2.6" "@types/ws": "npm:^8.18.1" dotenv: "npm:^17.2.3" fastify: "npm:^5.6.1" + nunjucks: "npm:^3.2.4" pino-pretty: "npm:^13.1.1" tsx: "npm:^4.20.6" zod: "npm:^4.1.11" @@ -1513,6 +1536,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^5.1.0": + version: 5.1.0 + resolution: "commander@npm:5.1.0" + checksum: 10c0/da9d71dbe4ce039faf1fe9eac3771dca8c11d66963341f62602f7b66e36d2a3f8883407af4f9a37b1db1a55c59c0c1325f186425764c2e963dc1d67aec2a4b6d + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -2636,6 +2666,24 @@ __metadata: languageName: node linkType: hard +"nunjucks@npm:^3.2.4": + version: 3.2.4 + resolution: "nunjucks@npm:3.2.4" + dependencies: + a-sync-waterfall: "npm:^1.0.0" + asap: "npm:^2.0.3" + commander: "npm:^5.1.0" + peerDependencies: + chokidar: ^3.3.0 + peerDependenciesMeta: + chokidar: + optional: true + bin: + nunjucks-precompile: bin/precompile + checksum: 10c0/7fe5197559b7c09972c79e2a86f9c093459b9075bc9b41134cd2bc599ae93567b53bd09d472a748edc736192d9ccd2998aa8c20cfcbe6a3fffd281f91897c888 + languageName: node + linkType: hard + "on-exit-leak-free@npm:^2.1.0": version: 2.1.2 resolution: "on-exit-leak-free@npm:2.1.2" From 79f323add1d9fefb0f0e2eb96491b08f413faade Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Wed, 15 Oct 2025 15:55:23 +0200 Subject: [PATCH 39/65] add tests to CI --- .github/workflows/CI.yaml | 3 +++ deep-sea-stories/packages/backend/tests/config.test.ts | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index d18c98e..35c0cc2 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -34,3 +34,6 @@ jobs: - name: Run lint run: yarn lint + + - name: Run backend tests + run: yarn workspace backend test diff --git a/deep-sea-stories/packages/backend/tests/config.test.ts b/deep-sea-stories/packages/backend/tests/config.test.ts index f35a342..9cf0d8f 100644 --- a/deep-sea-stories/packages/backend/tests/config.test.ts +++ b/deep-sea-stories/packages/backend/tests/config.test.ts @@ -45,12 +45,12 @@ describe('Configuration', () => { ); assert( - AGENT_INSTRUCTIONS_TEMPLATE.includes('{{FRONT}}'), - 'Template should contain {{FRONT}} placeholder', + AGENT_INSTRUCTIONS_TEMPLATE.includes('{{ FRONT }}'), + 'Template should contain {{ FRONT }} placeholder', ); assert( - AGENT_INSTRUCTIONS_TEMPLATE.includes('{{BACK}}'), - 'Template should contain {{BACK}} placeholder', + AGENT_INSTRUCTIONS_TEMPLATE.includes('{{ BACK }}'), + 'Template should contain {{ BACK }} placeholder', ); }); From 22b60948fd601e474f76d9d83515097034ea00a1 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 10:00:15 +0200 Subject: [PATCH 40/65] use globalSetup in tests --- deep-sea-stories/packages/backend/package.json | 6 +++--- deep-sea-stories/packages/backend/src/config.ts | 2 +- deep-sea-stories/packages/backend/tests/index.test.ts | 6 ------ .../backend/tests/{setup.ts => setup-module.ts} | 10 ++++++---- 4 files changed, 10 insertions(+), 14 deletions(-) delete mode 100644 deep-sea-stories/packages/backend/tests/index.test.ts rename deep-sea-stories/packages/backend/tests/{setup.ts => setup-module.ts} (66%) diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index 295c43a..b84e1c7 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -21,10 +21,10 @@ "tsx": "^4.20.6" }, "scripts": { - "build": "tsc -p tsconfig.json", + "build": "tsc -p tsconfig.json && mkdir -p dist/src/prompts && cp -R src/prompts/* dist/src/prompts/", "start": "tsx watch src/main.ts", "typecheck": "tsc --noEmit", - "test": "node --test --import tsx/esm tests/index.test.ts", - "test:watch": "node --test --watch --import tsx/esm tests/index.test.ts" + "test": "tsx --test --test-global-setup=./tests/setup-module.ts", + "test:watch": "tsx --test --watch --test-global-setup=./tests/setup-module.ts" } } diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index 8b71d01..e22721b 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -6,7 +6,7 @@ import { dirname, join } from 'node:path'; import type { Story } from './types.js'; import type { PeerOptions } from '@fishjam-cloud/js-server-sdk'; -dotenv.config(); +dotenv.config({quiet: true}) const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/deep-sea-stories/packages/backend/tests/index.test.ts b/deep-sea-stories/packages/backend/tests/index.test.ts deleted file mode 100644 index 8149735..0000000 --- a/deep-sea-stories/packages/backend/tests/index.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -console.log('🧪 Running Deep Sea Stories Backend Tests...\n'); - -import './setup.js'; - -import './config.test.js'; -import './utils.test.js'; diff --git a/deep-sea-stories/packages/backend/tests/setup.ts b/deep-sea-stories/packages/backend/tests/setup-module.ts similarity index 66% rename from deep-sea-stories/packages/backend/tests/setup.ts rename to deep-sea-stories/packages/backend/tests/setup-module.ts index dec3bf9..e62a004 100644 --- a/deep-sea-stories/packages/backend/tests/setup.ts +++ b/deep-sea-stories/packages/backend/tests/setup-module.ts @@ -6,7 +6,9 @@ import { dirname } from 'node:path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -dotenv.config({ - path: join(__dirname, '.env.test'), - override: true, -}); +export async function globalSetup() { + dotenv.config({ + path: join(__dirname, '.env.test'), + override: true, + }); +} From 5a5524c5bc2464a89f16ea57e7c328f5eb83268b Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 10:01:09 +0200 Subject: [PATCH 41/65] format --- deep-sea-stories/packages/backend/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deep-sea-stories/packages/backend/src/config.ts b/deep-sea-stories/packages/backend/src/config.ts index e22721b..4b0567a 100644 --- a/deep-sea-stories/packages/backend/src/config.ts +++ b/deep-sea-stories/packages/backend/src/config.ts @@ -6,7 +6,7 @@ import { dirname, join } from 'node:path'; import type { Story } from './types.js'; import type { PeerOptions } from '@fishjam-cloud/js-server-sdk'; -dotenv.config({quiet: true}) +dotenv.config({ quiet: true }); const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); From 881068f3eedb977e0b4e5f9f9e538cd499be85ad Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 12:22:36 +0200 Subject: [PATCH 42/65] refactor --- .../packages/backend/src/controllers/peers.ts | 17 +- .../backend/src/controllers/stories.ts | 5 +- .../packages/backend/src/domain/errors.ts | 58 ++++++ .../service/audio-streaming-orchestrator.ts | 94 ++++++++++ ...evenlabs.ts => elevenlabs-conversation.ts} | 4 - .../{session.ts => elevenlabs-session.ts} | 58 +++++- .../backend/src/service/game-session.ts | 172 ++++++++++++++++++ .../packages/backend/src/service/game.ts | 146 --------------- .../packages/backend/src/service/notifier.ts | 29 ++- .../packages/backend/src/service/room.ts | 94 +--------- .../packages/backend/src/types.ts | 5 +- 11 files changed, 423 insertions(+), 259 deletions(-) create mode 100644 deep-sea-stories/packages/backend/src/domain/errors.ts create mode 100644 deep-sea-stories/packages/backend/src/service/audio-streaming-orchestrator.ts rename deep-sea-stories/packages/backend/src/service/{elevenlabs.ts => elevenlabs-conversation.ts} (98%) rename deep-sea-stories/packages/backend/src/service/{session.ts => elevenlabs-session.ts} (56%) create mode 100644 deep-sea-stories/packages/backend/src/service/game-session.ts delete mode 100644 deep-sea-stories/packages/backend/src/service/game.ts diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index 5b687ca..2c3099d 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -10,19 +10,24 @@ export const createPeer = publicProcedure if (!room) { throw new Error(`Room with id ${input.roomId} does not exist`); } - const roomAgent = roomService.getAgent(room.id); + + const gameSession = roomService.getGameSession(room.id); + if (!gameSession) { + throw new Error(`No game session found for room with id ${input.roomId}`); + } + + const roomAgent = gameSession.getFishjamAgent(); if (room.peers.length > 0 && !roomAgent) { throw new Error( `Room with id ${input.roomId} already has a peer and no agent`, ); } + if (room.peers.length === 0) { - await roomService.createFishjamAgent(room.id, ctx.fishjam); + await gameSession.createFishjamAgent(ctx.fishjam); } - const { peer, peerToken } = await roomService.createPeer( - room.id, - ctx.fishjam, - ); + + const { peer, peerToken } = await gameSession.createPeer(ctx.fishjam); return { peer: peer, diff --git a/deep-sea-stories/packages/backend/src/controllers/stories.ts b/deep-sea-stories/packages/backend/src/controllers/stories.ts index 0936bec..47467dc 100644 --- a/deep-sea-stories/packages/backend/src/controllers/stories.ts +++ b/deep-sea-stories/packages/backend/src/controllers/stories.ts @@ -1,8 +1,8 @@ import { publicProcedure } from '../trpc.js'; import { stories } from '../config.js'; import { startStoryInputSchema } from '../schemas.js'; -import { gameService } from '../service/game.js'; import type { RoomId } from '@fishjam-cloud/js-server-sdk'; +import { roomService } from '../service/room.js'; export const startStory = publicProcedure .input(startStoryInputSchema) @@ -13,7 +13,8 @@ export const startStory = publicProcedure } try { - await gameService.startGame(input.roomId as RoomId, selectedStory); + const gameSession = roomService.getGameSession(input.roomId as RoomId); + await gameSession?.startGame(selectedStory); return { success: true, diff --git a/deep-sea-stories/packages/backend/src/domain/errors.ts b/deep-sea-stories/packages/backend/src/domain/errors.ts new file mode 100644 index 0000000..bf4e5dd --- /dev/null +++ b/deep-sea-stories/packages/backend/src/domain/errors.ts @@ -0,0 +1,58 @@ +export class DomainError extends Error { + code: string; + statusCode: number; + + constructor(code: string, message: string, statusCode: number = 500) { + super(message); + this.code = code; + this.statusCode = statusCode; + this.name = 'DomainError'; + } +} + +export class GameSessionNotFoundError extends DomainError { + constructor(roomId: string) { + super( + 'GAME_SESSION_NOT_FOUND', + `No game session found for room ${roomId}`, + 404, + ); + this.name = 'GameSessionNotFoundError'; + } +} + +export class StoryNotFoundError extends DomainError { + constructor(roomId: string) { + super('STORY_NOT_FOUND', `No story available for room ${roomId}`, 400); + this.name = 'StoryNotFoundError'; + } +} + +export class NoPeersConnectedError extends DomainError { + constructor(roomId: string) { + super('NO_PEERS_CONNECTED', `No connected peers in room ${roomId}`, 400); + this.name = 'NoPeersConnectedError'; + } +} + +export class NoVoiceSessionManagerError extends DomainError { + constructor(roomId: string) { + super( + 'NO_VOICE_SESSION_MANAGER', + `No voice session manager configured for room ${roomId}`, + 500, + ); + this.name = 'NoVoiceSessionManagerError'; + } +} + +export class AudioConnectionError extends DomainError { + constructor(peerId: string, reason: string) { + super( + 'AUDIO_CONNECTION_ERROR', + `Failed to establish audio connection for peer ${peerId}: ${reason}`, + 500, + ); + this.name = 'AudioConnectionError'; + } +} diff --git a/deep-sea-stories/packages/backend/src/service/audio-streaming-orchestrator.ts b/deep-sea-stories/packages/backend/src/service/audio-streaming-orchestrator.ts new file mode 100644 index 0000000..7d4259f --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/audio-streaming-orchestrator.ts @@ -0,0 +1,94 @@ +import type { + FishjamAgent, + PeerId, + TrackId, +} from '@fishjam-cloud/js-server-sdk'; +import type { VoiceAgentSessionManager } from '../types.js'; + +export class AudioStreamingOrchestrator { + private fishjamAgent: FishjamAgent; + private sessionManager: VoiceAgentSessionManager; + private connectedPeers: Set; + + constructor( + fishjamAgent: FishjamAgent, + sessionManager: VoiceAgentSessionManager, + connectedPeers: Set, + ) { + this.fishjamAgent = fishjamAgent; + this.sessionManager = sessionManager; + this.connectedPeers = connectedPeers; + } + + setupIncomingAudioPipeline(): void { + this.fishjamAgent.on('trackData', (trackMsg) => { + if (!this.connectedPeers.has(trackMsg.peerId)) { + return; + } + + const session = this.sessionManager.getSession(trackMsg.peerId); + if (session && trackMsg.data) { + try { + const audioBuffer = Buffer.from(trackMsg.data); + session.sendAudio(audioBuffer); + } catch (error) { + console.error( + `Error sending audio to AI voice agent for peer ${trackMsg.peerId}:`, + error, + ); + } + } + }); + } + + setupOutgoingAudioPipeline(): void { + const audioTrack = this.fishjamAgent.createTrack({ + encoding: 'pcm16', + sampleRate: 16000, + channels: 1, + }); + + for (const peerId of this.connectedPeers) { + const session = this.sessionManager.getSession(peerId); + if (!session) { + console.warn(`No session found for peer ${peerId}`); + continue; + } + + session.on('agentAudio', (audioEvent) => { + try { + const audioBuffer = this.decodeAudioEvent(audioEvent); + if (audioBuffer && audioBuffer.length > 0) { + this.fishjamAgent.sendData(audioTrack.id as TrackId, audioBuffer); + } else { + console.error('Received empty audio buffer from AI voice agent'); + } + } catch (error) { + console.error('Error sending agent audio track to room:', error); + } + }); + } + } + + setupAudioPipelines(): void { + this.setupIncomingAudioPipeline(); + this.setupOutgoingAudioPipeline(); + } + + private decodeAudioEvent(audioEvent: { + audio_base_64?: string; + }): Uint8Array | null { + if (!audioEvent.audio_base_64) { + return null; + } + + try { + return Uint8Array.from(atob(audioEvent.audio_base_64), (c) => + c.charCodeAt(0), + ); + } catch (error) { + console.error('Error decoding audio event:', error); + return null; + } + } +} diff --git a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs-conversation.ts similarity index 98% rename from deep-sea-stories/packages/backend/src/service/elevenlabs.ts rename to deep-sea-stories/packages/backend/src/service/elevenlabs-conversation.ts index 1731128..9261818 100644 --- a/deep-sea-stories/packages/backend/src/service/elevenlabs.ts +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs-conversation.ts @@ -126,10 +126,6 @@ export class ElevenLabsConversation }); } - /** - * Send raw audio data to ElevenLabs - * @param audioBuffer Raw audio data as Buffer - */ sendAudio(audioBuffer: Buffer): void { if (!this.isConnected || !this.ws) { console.warn('Cannot send audio: WebSocket not connected'); diff --git a/deep-sea-stories/packages/backend/src/service/session.ts b/deep-sea-stories/packages/backend/src/service/elevenlabs-session.ts similarity index 56% rename from deep-sea-stories/packages/backend/src/service/session.ts rename to deep-sea-stories/packages/backend/src/service/elevenlabs-session.ts index c6bd3b1..0000abf 100644 --- a/deep-sea-stories/packages/backend/src/service/session.ts +++ b/deep-sea-stories/packages/backend/src/service/elevenlabs-session.ts @@ -1,24 +1,63 @@ import type { RoomId, PeerId } from '@fishjam-cloud/js-server-sdk'; -import { elevenLabs, ElevenLabsConversation } from './elevenlabs.js'; +import { + elevenLabs, + ElevenLabsConversation, +} from './elevenlabs-conversation.js'; import { roomService } from './room.js'; import { getInstructionsForStory } from '../utils.js'; import { CONFIG } from '../config.js'; import type { VoiceAgentSessionManager } from '../types.js'; +import { + GameSessionNotFoundError, + StoryNotFoundError, +} from '../domain/errors.js'; export class ElevenLabsSessionManager implements VoiceAgentSessionManager { private sessions = new Map(); + private inFlightCreations = new Map< + PeerId, + Promise + >(); + + private async resolveStory(roomId: RoomId) { + const gameSession = roomService.getGameSession(roomId); + if (!gameSession) { + throw new GameSessionNotFoundError(roomId); + } + + const story = gameSession.getStory(); + if (!story) { + throw new StoryNotFoundError(roomId); + } + + return story; + } async createSession( peerId: PeerId, roomId: RoomId, ): Promise { - await this.deleteSession(peerId); - - const story = roomService.getStory(roomId); - if (!story) { - throw new Error(`No story found for room ${roomId}`); + if (this.inFlightCreations.has(peerId)) { + return this.inFlightCreations.get( + peerId, + ) as Promise; } + const promise = this._createSessionInternal(peerId, roomId).finally(() => + this.inFlightCreations.delete(peerId), + ); + + this.inFlightCreations.set(peerId, promise); + return promise; + } + + private async _createSessionInternal( + peerId: PeerId, + roomId: RoomId, + ): Promise { + await this.deleteSession(peerId); + + const story = await this.resolveStory(roomId); const instructions = getInstructionsForStory(story); const { agentId } = await elevenLabs.conversationalAi.agents.create({ @@ -61,8 +100,11 @@ export class ElevenLabsSessionManager implements VoiceAgentSessionManager { async cleanup(): Promise { const promises = Array.from(this.sessions.keys()).map((peerId) => - this.deleteSession(peerId), + this.deleteSession(peerId).catch((error) => { + console.error(`Failed to cleanup session for peer ${peerId}:`, error); + }), ); - await Promise.all(promises); + + await Promise.allSettled(promises); } } diff --git a/deep-sea-stories/packages/backend/src/service/game-session.ts b/deep-sea-stories/packages/backend/src/service/game-session.ts new file mode 100644 index 0000000..6a563cb --- /dev/null +++ b/deep-sea-stories/packages/backend/src/service/game-session.ts @@ -0,0 +1,172 @@ +import type { + FishjamAgent, + FishjamClient, + Peer, + PeerId, + RoomId, +} from '@fishjam-cloud/js-server-sdk'; +import type { Story, VoiceAgentSessionManager } from '../types.js'; +import { FISHJAM_AGENT_OPTIONS } from '../config.js'; +import { AudioStreamingOrchestrator } from './audio-streaming-orchestrator.js'; +import { + NoPeersConnectedError, + NoVoiceSessionManagerError, +} from '../domain/errors.js'; + +export class GameSession { + private roomId: RoomId; + private story: Story | undefined; + private peers: Peer[]; + private connectedPeers: Set; + private fishjamAgent: FishjamAgent | undefined; + private fishjamAgentId: PeerId | undefined; + private voiceSessionManager: VoiceAgentSessionManager | undefined; + + constructor(roomId: RoomId) { + this.roomId = roomId; + this.story = undefined; + this.peers = []; + this.connectedPeers = new Set(); + } + + getStory(): Story | undefined { + return this.story; + } + + getPeers(): Peer[] { + return this.peers; + } + + getConnectedPeers(): PeerId[] { + return Array.from(this.connectedPeers); + } + + getFishjamAgent(): { + fishjamAgent: FishjamAgent | undefined; + peerId: PeerId | undefined; + } { + return { + fishjamAgent: this.fishjamAgent, + peerId: this.fishjamAgentId, + }; + } + + getVoiceSessionManager(): VoiceAgentSessionManager | undefined { + return this.voiceSessionManager; + } + + setStory(story: Story | undefined) { + this.story = story; + } + + async createPeer( + fishjam: FishjamClient, + ): Promise<{ peer: Peer; peerToken: string }> { + const { peer, peerToken } = await fishjam.createPeer(this.roomId); + this.peers.push(peer); + return { peer, peerToken }; + } + + setConnectedPeer(peerId: PeerId) { + this.connectedPeers.add(peerId); + } + + removeConnectedPeer(peerId: PeerId) { + this.connectedPeers.delete(peerId); + } + + async createFishjamAgent(fishjam: FishjamClient) { + const { agent, peer } = await fishjam.createAgent( + this.roomId, + FISHJAM_AGENT_OPTIONS, + (msg) => { + console.log(`Fishjam Agent for room: ${this.roomId} got error: ${msg}`); + }, + (code, reason) => { + console.log( + `Fishjam Agent for room: ${this.roomId} closed with code: ${code}, reason: ${reason}`, + ); + }, + ); + + this.fishjamAgent = agent; + this.fishjamAgentId = peer.id; + } + + setVoiceSessionManager(manager: VoiceAgentSessionManager) { + this.voiceSessionManager = manager; + } + + async startGame(story: Story): Promise { + this.setStory(story); + + if (this.connectedPeers.size === 0) { + throw new NoPeersConnectedError(this.roomId); + } + + console.log( + `Starting game for ${this.connectedPeers.size} connected peers in room ${this.roomId}`, + ); + + const peerIds = Array.from(this.connectedPeers); + await Promise.all( + peerIds.map(async (peerId) => { + try { + await this.startGameForPeer(peerId); + } catch (error) { + console.error( + `Failed to start game for peer ${peerId} in room ${this.roomId}:`, + error, + ); + } + }), + ); + this.setupAudioStreaming(); + } + + async startGameForPeer(peerId: PeerId): Promise { + if (!this.voiceSessionManager) { + throw new NoVoiceSessionManagerError(this.roomId); + } + + try { + await this.voiceSessionManager.createSession(peerId, this.roomId); + console.log( + `Started game session for peer ${peerId} in room ${this.roomId}`, + ); + } catch (error) { + console.error(`Failed to start game session for peer ${peerId}:`, error); + throw error; + } + } + + private setupAudioStreaming(): void { + if (!this.fishjamAgent || !this.voiceSessionManager) { + console.error( + `Cannot setup audio streaming: missing agent or session manager for room ${this.roomId}`, + ); + return; + } + + const orchestrator = new AudioStreamingOrchestrator( + this.fishjamAgent, + this.voiceSessionManager, + this.connectedPeers, + ); + + orchestrator.setupAudioPipelines(); + } + + async stopGame(roomId: RoomId): Promise { + this.voiceSessionManager?.cleanup(); + this.setStory(undefined); + console.log(`Stopped game for room ${roomId}`); + } + + async removePeerFromGame(roomId: RoomId, peerId: PeerId): Promise { + if (this.voiceSessionManager) { + await this.voiceSessionManager.deleteSession(peerId); + console.log(`Removed peer ${peerId} from game in room ${roomId}`); + } + } +} diff --git a/deep-sea-stories/packages/backend/src/service/game.ts b/deep-sea-stories/packages/backend/src/service/game.ts deleted file mode 100644 index a4b9e93..0000000 --- a/deep-sea-stories/packages/backend/src/service/game.ts +++ /dev/null @@ -1,146 +0,0 @@ -import type { PeerId, RoomId, TrackId } from '@fishjam-cloud/js-server-sdk'; -import { roomService } from './room.js'; -import type { Story } from '../types.js'; - -class GameService { - async startGame(roomId: RoomId, story: Story): Promise { - roomService.setStory(roomId, story); - - const connectedPeerIds = roomService.getConnectedPeers(roomId); - - if (!connectedPeerIds.length) { - throw new Error(`No connected peers in room ${roomId}`); - } - console.log( - `Starting game for ${connectedPeerIds.length} connected peers in room ${roomId}`, - ); - - await this.startGameForPeers(roomId, connectedPeerIds); - } - - async startGameForPeers(roomId: RoomId, peerIds: PeerId[]): Promise { - await Promise.all( - peerIds.map(async (peerId) => { - try { - await this.startGameForPeer(roomId, peerId); - } catch (error) { - console.error( - `Failed to start game for peer ${peerId} in room ${roomId}:`, - error, - ); - } - }), - ); - this.setupAudioStreaming(roomId); - } - - async startGameForPeer(roomId: RoomId, peerId: PeerId): Promise { - const story = roomService.getStory(roomId); - if (!story) { - throw new Error(`No active game found for room ${roomId}`); - } - - const sessionManager = roomService.getElevenLabsSessionManager(roomId); - if (!sessionManager) { - throw new Error(`No session manager found for room ${roomId}`); - } - - try { - await sessionManager.createSession(peerId, roomId); - console.log(`Started game session for peer ${peerId} in room ${roomId}`); - } catch (error) { - console.error(`Failed to start game session for peer ${peerId}:`, error); - throw error; - } - } - - private setupAudioStreaming(roomId: RoomId): void { - const { fishjamAgent } = roomService.getAgent(roomId); - const sessionManager = roomService.getElevenLabsSessionManager(roomId); - const connectedPeers = roomService.getConnectedPeers(roomId); - - if (!fishjamAgent || !sessionManager) { - console.error( - `Cannot setup audio streaming: missing agent or session manager for room ${roomId}`, - ); - return; - } - - fishjamAgent.on('trackData', (trackMsg) => { - if (!connectedPeers.includes(trackMsg.peerId)) { - return; - } - - const { data } = trackMsg; - const session = sessionManager.getSession(trackMsg.peerId); - - if (session && data) { - try { - const audioBuffer = Buffer.from(data); - session.sendAudio(audioBuffer); - } catch (error) { - console.error( - `Error sending audio to ElevenLabs for peer ${trackMsg.peerId}:`, - error, - ); - } - } - }); - const audioTrack = fishjamAgent.createTrack({ - encoding: 'pcm16', - sampleRate: 16000, - channels: 1, - }); - - for (const peerId of connectedPeers) { - try { - const agentSession = sessionManager.getSession(peerId); - agentSession?.on('agentAudio', (audioEvent) => { - try { - const audioBuffer = Uint8Array.from( - atob(audioEvent.audio_base_64), - (c) => c.charCodeAt(0), - ); - if (!audioBuffer) { - console.error('Received empty audio buffer from ElevenLabs'); - return; - } - fishjamAgent.sendData(audioTrack.id as TrackId, audioBuffer); - } catch (error) { - console.error('Error sending agent audio track to room:', error); - } - }); - } catch (error) { - console.error( - `Error setting up agent audio for peer ${peerId}:`, - error, - ); - } - } - } - - isGameActive(roomId: RoomId): boolean { - return roomService.getStory(roomId) !== undefined; - } - - async stopGame(roomId: RoomId): Promise { - const sessionManager = roomService.getElevenLabsSessionManager(roomId); - if (sessionManager) { - await sessionManager.cleanup(); - } - - roomService.setStory(roomId, null); - - console.log(`Stopped game for room ${roomId}`); - } - - async removePeerFromGame(roomId: RoomId, peerId: PeerId): Promise { - const sessionManager = roomService.getElevenLabsSessionManager(roomId); - if (sessionManager) { - await sessionManager.deleteSession(peerId); - console.log(`Removed peer ${peerId} from game in room ${roomId}`); - } - } -} - -export const gameService = new GameService(); diff --git a/deep-sea-stories/packages/backend/src/service/notifier.ts b/deep-sea-stories/packages/backend/src/service/notifier.ts index ed7fb75..b8ff233 100644 --- a/deep-sea-stories/packages/backend/src/service/notifier.ts +++ b/deep-sea-stories/packages/backend/src/service/notifier.ts @@ -1,7 +1,6 @@ import { FishjamWSNotifier } from '@fishjam-cloud/js-server-sdk'; import { CONFIG } from '../config.js'; import { roomService } from './room.js'; -import { gameService } from './game.js'; class NotifierService { private notifier: FishjamWSNotifier | null = null; @@ -33,16 +32,23 @@ class NotifierService { this.notifier.on('peerConnected', async (msg) => { console.log(`Peer connected: ${msg.peerId} in room ${msg.roomId}`); - const { peerId } = roomService.getAgent(msg.roomId); + const gameSession = roomService.getGameSession(msg.roomId); + if (!gameSession) { + console.warn( + `No game session found for room ${msg.roomId} when peer ${msg.peerId} connected.`, + ); + return; + } + const { peerId } = gameSession.getFishjamAgent(); if (msg.peerId === peerId) { return; } - roomService.addConnectedPeer(msg.roomId, msg.peerId); - if (!gameService.isGameActive(msg.roomId)) return; + gameSession.setConnectedPeer(msg.peerId); + if (!roomService.isGameActive(msg.roomId)) return; try { - await gameService.startGameForPeer(msg.roomId, msg.peerId); + await gameSession.startGameForPeer(msg.peerId); } catch (error) { console.error( `Failed to start game for newly connected peer ${msg.peerId}:`, @@ -54,10 +60,17 @@ class NotifierService { this.notifier.on('peerDisconnected', async (msg) => { console.log(`Peer disconnected: ${msg.peerId} from room ${msg.roomId}`); - roomService.removeConnectedPeer(msg.roomId, msg.peerId); + const gameSession = roomService.getGameSession(msg.roomId); + if (!gameSession) { + console.warn( + `No game session found for room ${msg.roomId} when peer ${msg.peerId} disconnected.`, + ); + return; + } + gameSession.removeConnectedPeer(msg.peerId); - if (gameService.isGameActive(msg.roomId)) { - await gameService.removePeerFromGame(msg.roomId, msg.peerId); + if (roomService.isGameActive(msg.roomId)) { + await gameSession.removePeerFromGame(msg.roomId, msg.peerId); } }); } diff --git a/deep-sea-stories/packages/backend/src/service/room.ts b/deep-sea-stories/packages/backend/src/service/room.ts index bca24bc..71fa6c4 100644 --- a/deep-sea-stories/packages/backend/src/service/room.ts +++ b/deep-sea-stories/packages/backend/src/service/room.ts @@ -1,94 +1,20 @@ -import type { - FishjamAgent, - FishjamClient, - Peer, - PeerId, - RoomId, -} from '@fishjam-cloud/js-server-sdk'; -import type { Story } from '../types.js'; -import { FISHJAM_AGENT_OPTIONS } from '../config.js'; -import { ElevenLabsSessionManager } from './session.js'; +import type { RoomId } from '@fishjam-cloud/js-server-sdk'; +import type { GameSession } from './game-session.js'; class RoomService { - private RoomToStory = new Map(); - private RoomToPeers = new Map(); - private RoomToConnectedPeers = new Map>(); - private RoomToFishjamAgent = new Map(); - private RoomToFishjamAgentId = new Map(); - private RoomToSessionManager = new Map(); + private RoomToGameSession = new Map(); - getStory(roomId: RoomId): Story | undefined { - return this.RoomToStory.get(roomId); + getGameSession(roomId: RoomId): GameSession | undefined { + return this.RoomToGameSession.get(roomId); } - getAgent(roomId: RoomId) { - return { - fishjamAgent: this.RoomToFishjamAgent.get(roomId), - peerId: this.RoomToFishjamAgentId.get(roomId), - }; + setGameSession(roomId: RoomId, gameSession: GameSession) { + this.RoomToGameSession.set(roomId, gameSession); } - getPeers(roomId: RoomId) { - return this.RoomToPeers.get(roomId) || []; - } - - getConnectedPeers(roomId: RoomId): PeerId[] { - const connectedPeerIds = this.RoomToConnectedPeers.get(roomId) || new Set(); - return Array.from(connectedPeerIds); - } - - addConnectedPeer(roomId: RoomId, peerId: PeerId) { - const connectedPeers = this.RoomToConnectedPeers.get(roomId) || new Set(); - connectedPeers.add(peerId); - this.RoomToConnectedPeers.set(roomId, connectedPeers); - } - - removeConnectedPeer(roomId: RoomId, peerId: PeerId) { - const connectedPeers = this.RoomToConnectedPeers.get(roomId); - if (connectedPeers) { - connectedPeers.delete(peerId); - } - } - - getElevenLabsSessionManager(roomId: RoomId) { - if (!this.RoomToSessionManager.get(roomId)) { - this.RoomToSessionManager.set(roomId, new ElevenLabsSessionManager()); - } - return this.RoomToSessionManager.get(roomId); - } - - setStory(roomId: RoomId, story: Story | null) { - if (story === null) { - this.RoomToStory.delete(roomId); - } else { - this.RoomToStory.set(roomId, story); - } - } - - async createPeer(roomId: RoomId, fishjam: FishjamClient) { - const { peer, peerToken } = await fishjam.createPeer(roomId); - const peers = this.RoomToPeers.get(roomId) || []; - peers.push(peer); - this.RoomToPeers.set(roomId, peers); - return { peer, peerToken }; - } - - async createFishjamAgent(roomId: RoomId, fishjam: FishjamClient) { - const { agent, peer } = await fishjam.createAgent( - roomId, - FISHJAM_AGENT_OPTIONS, - (msg) => { - console.log(`Fishjam Agent for room: ${roomId} got error: ${msg}`); - }, - (code, reason) => { - console.log( - `Fishjam Agent for room: ${roomId} closed with code: ${code}, reason: ${reason}`, - ); - }, - ); - - this.RoomToFishjamAgent.set(roomId, agent); - this.RoomToFishjamAgentId.set(roomId, peer.id); + isGameActive(roomId: RoomId): boolean { + const gameSession = this.RoomToGameSession.get(roomId); + return gameSession !== undefined && gameSession.getStory() !== undefined; } } diff --git a/deep-sea-stories/packages/backend/src/types.ts b/deep-sea-stories/packages/backend/src/types.ts index 03808e6..5942424 100644 --- a/deep-sea-stories/packages/backend/src/types.ts +++ b/deep-sea-stories/packages/backend/src/types.ts @@ -1,4 +1,6 @@ import type { PeerId, RoomId } from '@fishjam-cloud/js-server-sdk'; +import type { EventEmitter } from 'node:events'; + export interface Story { id: number; title: string; @@ -6,7 +8,7 @@ export interface Story { back: string; } -export interface Conversation { +export interface Conversation extends EventEmitter { sendAudio(audioBuffer: Buffer): void; } @@ -14,4 +16,5 @@ export interface VoiceAgentSessionManager { createSession(peerId: PeerId, roomId: RoomId): Promise; deleteSession(peerId: PeerId): Promise; getSession(peerId: PeerId): Conversation | undefined; + cleanup(): Promise; } From 14a7f3e2425e7171f757f758a60a6a870731026c Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 13:38:32 +0200 Subject: [PATCH 43/65] add common types package, adjust adjust format bar --- deep-sea-stories/packages/common/package.json | 25 +++++++++++++++++++ .../packages/common/src/events.ts | 16 ++++++++++++ deep-sea-stories/packages/common/src/index.ts | 6 +++++ .../packages/common/tsconfig.json | 15 +++++++++++ deep-sea-stories/packages/web/package.json | 1 + .../web/src/components/AgentPanel.tsx | 22 +++------------- .../packages/web/src/components/TitleBar.tsx | 6 ++--- deep-sea-stories/packages/web/src/index.css | 2 +- deep-sea-stories/yarn.lock | 9 +++++++ 9 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 deep-sea-stories/packages/common/package.json create mode 100644 deep-sea-stories/packages/common/src/events.ts create mode 100644 deep-sea-stories/packages/common/src/index.ts create mode 100644 deep-sea-stories/packages/common/tsconfig.json diff --git a/deep-sea-stories/packages/common/package.json b/deep-sea-stories/packages/common/package.json new file mode 100644 index 0000000..4004df1 --- /dev/null +++ b/deep-sea-stories/packages/common/package.json @@ -0,0 +1,25 @@ +{ + "name": "common", + "private": true, + "version": "0.0.0", + "type": "module", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./src/index.ts" + } + }, + "main": "./dist/index.js", + "types": "./src/index.ts", + "files": [ + "dist", + "src" + ], + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "typescript": "^5.9.2" + } +} diff --git a/deep-sea-stories/packages/common/src/events.ts b/deep-sea-stories/packages/common/src/events.ts new file mode 100644 index 0000000..612ca9b --- /dev/null +++ b/deep-sea-stories/packages/common/src/events.ts @@ -0,0 +1,16 @@ +export interface BaseEvent { + type: string; + timestamp: number; +} + +export interface JoinEvent extends BaseEvent { + type: 'join'; + name: string; +} + +export interface TranscriptionEvent extends BaseEvent { + type: 'transcription'; + text: string; +} + +export type AgentEvent = JoinEvent | TranscriptionEvent; diff --git a/deep-sea-stories/packages/common/src/index.ts b/deep-sea-stories/packages/common/src/index.ts new file mode 100644 index 0000000..b7aa838 --- /dev/null +++ b/deep-sea-stories/packages/common/src/index.ts @@ -0,0 +1,6 @@ +export type { + AgentEvent, + BaseEvent, + JoinEvent, + TranscriptionEvent, +} from './events.js'; diff --git a/deep-sea-stories/packages/common/tsconfig.json b/deep-sea-stories/packages/common/tsconfig.json new file mode 100644 index 0000000..ef5d4bb --- /dev/null +++ b/deep-sea-stories/packages/common/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "composite": true, + "declaration": true, + "emitDeclarationOnly": false, + "outDir": "dist", + "rootDir": "src", + "module": "ESNext", + "target": "ES2022", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 1f7aa2a..4e8d56f 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -24,6 +24,7 @@ "backend": "workspace:*", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "common": "workspace:*", "lucide-react": "^0.544.0", "next-themes": "^0.4.6", "react": "^19.1.1", diff --git a/deep-sea-stories/packages/web/src/components/AgentPanel.tsx b/deep-sea-stories/packages/web/src/components/AgentPanel.tsx index 7f68896..b4f62a1 100644 --- a/deep-sea-stories/packages/web/src/components/AgentPanel.tsx +++ b/deep-sea-stories/packages/web/src/components/AgentPanel.tsx @@ -1,25 +1,9 @@ import { LogIn, type LucideIcon, MessageSquare } from 'lucide-react'; import type { FC, PropsWithChildren } from 'react'; +import type { AgentEvent } from 'common'; import blob from '@/assets/blob.png'; import { ScrollArea } from './ui/scroll-area'; -interface BaseEvent { - type: string; - timestamp: number; -} - -interface JoinEvent extends BaseEvent { - type: 'join'; - name: string; -} - -interface TranscriptionEvent extends BaseEvent { - type: 'transcription'; - text: string; -} - -type AgentPanelEvent = JoinEvent | TranscriptionEvent; - type PanelEventProps = { icon: LucideIcon; timestamp: number; @@ -39,7 +23,7 @@ const PanelEvent: FC> = ({
); -const renderEvent = (event: AgentPanelEvent) => { +const renderEvent = (event: AgentEvent) => { switch (event.type) { case 'join': return ( @@ -63,7 +47,7 @@ const renderEvent = (event: AgentPanelEvent) => { }; const AgentPanel = () => { - const events: AgentPanelEvent[] = [ + const events: AgentEvent[] = [ { type: 'join', name: 'Gordon', diff --git a/deep-sea-stories/packages/web/src/components/TitleBar.tsx b/deep-sea-stories/packages/web/src/components/TitleBar.tsx index 31d3eee..f8468f0 100644 --- a/deep-sea-stories/packages/web/src/components/TitleBar.tsx +++ b/deep-sea-stories/packages/web/src/components/TitleBar.tsx @@ -3,10 +3,10 @@ import type { FC } from 'react'; const TitleBar: FC = () => { return (
-
Deep Sea Stories
-
+

Deep Sea Stories

+

Hear the most mysterious stories and try to deduce how they happened. -

+
); }; diff --git a/deep-sea-stories/packages/web/src/index.css b/deep-sea-stories/packages/web/src/index.css index 258b6b6..ab4e770 100644 --- a/deep-sea-stories/packages/web/src/index.css +++ b/deep-sea-stories/packages/web/src/index.css @@ -3,7 +3,7 @@ @import "tailwindcss"; @import "tw-animate-css"; -@source inline("grid-cols-{1..4..1}") +@source "inline:grid-cols-{1..4..1}"; @custom-variant dark (&:is(.dark *)); diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index f929bf6..8004480 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -2059,6 +2059,14 @@ __metadata: languageName: node linkType: hard +"common@workspace:*, common@workspace:packages/common": + version: 0.0.0-use.local + resolution: "common@workspace:packages/common" + dependencies: + typescript: "npm:^5.9.2" + languageName: unknown + linkType: soft + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -4111,6 +4119,7 @@ __metadata: backend: "workspace:*" class-variance-authority: "npm:^0.7.1" clsx: "npm:^2.1.1" + common: "workspace:*" globals: "npm:^16.4.0" lucide-react: "npm:^0.544.0" next-themes: "npm:^0.4.6" From 5d9216834d27e2167bfaa47d3c18ae8a6ca566b2 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 13:43:55 +0200 Subject: [PATCH 44/65] readable-slug ref --- .../packages/web/src/lib/utils.ts | 23 +++++++++++-------- .../packages/web/src/views/HomeView.tsx | 5 ++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/deep-sea-stories/packages/web/src/lib/utils.ts b/deep-sea-stories/packages/web/src/lib/utils.ts index d2b2633..de87cd4 100644 --- a/deep-sea-stories/packages/web/src/lib/utils.ts +++ b/deep-sea-stories/packages/web/src/lib/utils.ts @@ -5,15 +5,20 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -const ALPHANUM = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; +const adjectives = [ + 'abyssal', 'deep', 'azure', 'sunken', 'coral', 'oceanic', 'tidal', + 'bioluminescent', 'mysterious', 'ancient', 'dark', 'glowing' +]; -export function randomString(length: number = 10): string { - let result = ''; +const nouns = [ + 'trench', 'reef', 'anemone', 'whale', 'kraken', 'octopus', 'leviathan', + 'shark', 'jellyfish', 'nautilus', 'squid', 'shipwreck', 'angler' +]; - for (let i = 0; i < length; i++) { - result += ALPHANUM.charAt(Math.floor(Math.random() * ALPHANUM.length)); - } - - return result; +export function generateDeepSeaSlug(): string { + + const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)]; + const randomNoun = nouns[Math.floor(Math.random() * nouns.length)]; + + return `${randomAdjective}-${randomNoun}-${Math.floor(Math.random() * 100)}`; } diff --git a/deep-sea-stories/packages/web/src/views/HomeView.tsx b/deep-sea-stories/packages/web/src/views/HomeView.tsx index f6aba8a..3b3c374 100644 --- a/deep-sea-stories/packages/web/src/views/HomeView.tsx +++ b/deep-sea-stories/packages/web/src/views/HomeView.tsx @@ -1,14 +1,15 @@ import Footer from '@/components/Footer'; import LinkButton from '@/components/LinkButton'; import TitleBar from '@/components/TitleBar'; -import { randomString } from '@/lib/utils'; +import { generateDeepSeaSlug } from '@/lib/utils'; + export default function HomeView() { return ( <>
- + Create a game room
From 162b4a9ee191bf076a527f4a3d189ccad3b20ea4 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 13:50:11 +0200 Subject: [PATCH 45/65] make sure grid is displayed correctly --- deep-sea-stories/packages/web/src/views/GameView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deep-sea-stories/packages/web/src/views/GameView.tsx b/deep-sea-stories/packages/web/src/views/GameView.tsx index ec1bde5..5ff0383 100644 --- a/deep-sea-stories/packages/web/src/views/GameView.tsx +++ b/deep-sea-stories/packages/web/src/views/GameView.tsx @@ -18,7 +18,8 @@ const GameView: FC = ({ roomId }) => {
Date: Fri, 17 Oct 2025 13:53:45 +0200 Subject: [PATCH 46/65] fmt --- .../packages/web/src/lib/utils.ts | 35 +++++++++++++++---- .../packages/web/src/views/HomeView.tsx | 1 - 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/deep-sea-stories/packages/web/src/lib/utils.ts b/deep-sea-stories/packages/web/src/lib/utils.ts index de87cd4..51f4330 100644 --- a/deep-sea-stories/packages/web/src/lib/utils.ts +++ b/deep-sea-stories/packages/web/src/lib/utils.ts @@ -6,19 +6,40 @@ export function cn(...inputs: ClassValue[]) { } const adjectives = [ - 'abyssal', 'deep', 'azure', 'sunken', 'coral', 'oceanic', 'tidal', - 'bioluminescent', 'mysterious', 'ancient', 'dark', 'glowing' + 'abyssal', + 'deep', + 'azure', + 'sunken', + 'coral', + 'oceanic', + 'tidal', + 'bioluminescent', + 'mysterious', + 'ancient', + 'dark', + 'glowing', ]; const nouns = [ - 'trench', 'reef', 'anemone', 'whale', 'kraken', 'octopus', 'leviathan', - 'shark', 'jellyfish', 'nautilus', 'squid', 'shipwreck', 'angler' + 'trench', + 'reef', + 'anemone', + 'whale', + 'kraken', + 'octopus', + 'leviathan', + 'shark', + 'jellyfish', + 'nautilus', + 'squid', + 'shipwreck', + 'angler', ]; export function generateDeepSeaSlug(): string { - - const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)]; + const randomAdjective = + adjectives[Math.floor(Math.random() * adjectives.length)]; const randomNoun = nouns[Math.floor(Math.random() * nouns.length)]; - + return `${randomAdjective}-${randomNoun}-${Math.floor(Math.random() * 100)}`; } diff --git a/deep-sea-stories/packages/web/src/views/HomeView.tsx b/deep-sea-stories/packages/web/src/views/HomeView.tsx index 3b3c374..ca071f6 100644 --- a/deep-sea-stories/packages/web/src/views/HomeView.tsx +++ b/deep-sea-stories/packages/web/src/views/HomeView.tsx @@ -3,7 +3,6 @@ import LinkButton from '@/components/LinkButton'; import TitleBar from '@/components/TitleBar'; import { generateDeepSeaSlug } from '@/lib/utils'; - export default function HomeView() { return ( <> From 635739c2212b392c6f29a46df47a608b31803161 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 14:05:34 +0200 Subject: [PATCH 47/65] comment suggestiosn --- .../packages/backend/src/controllers/stories.ts | 8 +++++--- .../packages/backend/src/domain/errors.ts | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/controllers/stories.ts b/deep-sea-stories/packages/backend/src/controllers/stories.ts index 47467dc..b0752b5 100644 --- a/deep-sea-stories/packages/backend/src/controllers/stories.ts +++ b/deep-sea-stories/packages/backend/src/controllers/stories.ts @@ -3,6 +3,7 @@ import { stories } from '../config.js'; import { startStoryInputSchema } from '../schemas.js'; import type { RoomId } from '@fishjam-cloud/js-server-sdk'; import { roomService } from '../service/room.js'; +import { FailedToStartStoryError } from '../domain/errors.js'; export const startStory = publicProcedure .input(startStoryInputSchema) @@ -21,9 +22,10 @@ export const startStory = publicProcedure message: `Story "${input.storyId}" started successfully`, }; } catch (error) { - console.error(`Failed to start story: ${error}`); - throw new Error( - `Failed to start story: ${error instanceof Error ? error.message : 'Unknown error'}`, + console.error(`Failed to start story: %o`, error); + throw new FailedToStartStoryError( + input.storyId, + (error as Error).message, ); } }); diff --git a/deep-sea-stories/packages/backend/src/domain/errors.ts b/deep-sea-stories/packages/backend/src/domain/errors.ts index bf4e5dd..bfcebac 100644 --- a/deep-sea-stories/packages/backend/src/domain/errors.ts +++ b/deep-sea-stories/packages/backend/src/domain/errors.ts @@ -1,4 +1,4 @@ -export class DomainError extends Error { +export abstract class DomainError extends Error { code: string; statusCode: number; @@ -6,7 +6,6 @@ export class DomainError extends Error { super(message); this.code = code; this.statusCode = statusCode; - this.name = 'DomainError'; } } @@ -56,3 +55,14 @@ export class AudioConnectionError extends DomainError { this.name = 'AudioConnectionError'; } } + +export class FailedToStartStoryError extends DomainError { + constructor(storyId: number, reason: string) { + super( + 'FAILED_TO_START_STORY', + `Failed to start story ${storyId}: ${reason}`, + 500, + ); + this.name = 'FailedToStartStoryError'; + } +} From c4f27db24b0b357b17bca6cba40869f71c801330 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 17 Oct 2025 17:04:47 +0200 Subject: [PATCH 48/65] make backend work again --- deep-sea-stories/packages/backend/src/controllers/peers.ts | 6 ++++-- .../packages/backend/src/service/game-session.ts | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/deep-sea-stories/packages/backend/src/controllers/peers.ts b/deep-sea-stories/packages/backend/src/controllers/peers.ts index 2c3099d..6f5390f 100644 --- a/deep-sea-stories/packages/backend/src/controllers/peers.ts +++ b/deep-sea-stories/packages/backend/src/controllers/peers.ts @@ -2,6 +2,7 @@ import type { RoomId } from '@fishjam-cloud/js-server-sdk'; import { createPeerInputSchema } from '../schemas.js'; import { publicProcedure } from '../trpc.js'; import { roomService } from '../service/room.js'; +import { GameSession } from '../service/game-session.js'; export const createPeer = publicProcedure .input(createPeerInputSchema) @@ -11,9 +12,10 @@ export const createPeer = publicProcedure throw new Error(`Room with id ${input.roomId} does not exist`); } - const gameSession = roomService.getGameSession(room.id); + let gameSession = roomService.getGameSession(room.id); if (!gameSession) { - throw new Error(`No game session found for room with id ${input.roomId}`); + gameSession = new GameSession(room.id); + roomService.setGameSession(room.id, gameSession); } const roomAgent = gameSession.getFishjamAgent(); diff --git a/deep-sea-stories/packages/backend/src/service/game-session.ts b/deep-sea-stories/packages/backend/src/service/game-session.ts index 6a563cb..f81b5ef 100644 --- a/deep-sea-stories/packages/backend/src/service/game-session.ts +++ b/deep-sea-stories/packages/backend/src/service/game-session.ts @@ -12,6 +12,7 @@ import { NoPeersConnectedError, NoVoiceSessionManagerError, } from '../domain/errors.js'; +import { ElevenLabsSessionManager } from './elevenlabs-session.js'; export class GameSession { private roomId: RoomId; @@ -108,6 +109,9 @@ export class GameSession { `Starting game for ${this.connectedPeers.size} connected peers in room ${this.roomId}`, ); + const gameSession = new ElevenLabsSessionManager(); + this.setVoiceSessionManager(gameSession); + const peerIds = Array.from(this.connectedPeers); await Promise.all( peerIds.map(async (peerId) => { From 535b367c5f7a26275cbb7f9ef3bdb38511c909ba Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 20 Oct 2025 15:36:35 +0200 Subject: [PATCH 49/65] scope common package --- deep-sea-stories/packages/common/package.json | 2 +- deep-sea-stories/packages/web/package.json | 2 +- .../web/src/components/AgentPanel.tsx | 2 +- deep-sea-stories/yarn.lock | 912 +++++++++--------- 4 files changed, 457 insertions(+), 461 deletions(-) diff --git a/deep-sea-stories/packages/common/package.json b/deep-sea-stories/packages/common/package.json index 4004df1..1f4dc35 100644 --- a/deep-sea-stories/packages/common/package.json +++ b/deep-sea-stories/packages/common/package.json @@ -1,5 +1,5 @@ { - "name": "common", + "name": "@deep-sea-stories/common", "private": true, "version": "0.0.0", "type": "module", diff --git a/deep-sea-stories/packages/web/package.json b/deep-sea-stories/packages/web/package.json index 4e8d56f..60bc1ed 100644 --- a/deep-sea-stories/packages/web/package.json +++ b/deep-sea-stories/packages/web/package.json @@ -10,6 +10,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@deep-sea-stories/common": "workspace:*", "@fishjam-cloud/react-client": "^0.20.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.7", @@ -24,7 +25,6 @@ "backend": "workspace:*", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "common": "workspace:*", "lucide-react": "^0.544.0", "next-themes": "^0.4.6", "react": "^19.1.1", diff --git a/deep-sea-stories/packages/web/src/components/AgentPanel.tsx b/deep-sea-stories/packages/web/src/components/AgentPanel.tsx index b4f62a1..789fde4 100644 --- a/deep-sea-stories/packages/web/src/components/AgentPanel.tsx +++ b/deep-sea-stories/packages/web/src/components/AgentPanel.tsx @@ -1,6 +1,6 @@ import { LogIn, type LucideIcon, MessageSquare } from 'lucide-react'; import type { FC, PropsWithChildren } from 'react'; -import type { AgentEvent } from 'common'; +import type { AgentEvent } from '@deep-sea-stories/common'; import blob from '@/assets/blob.png'; import { ScrollArea } from './ui/scroll-area'; diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index e476fa3..ba6382e 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -311,6 +311,16 @@ __metadata: version: 2.9.0 resolution: "@bufbuild/protobuf@npm:2.9.0" checksum: 10c0/fe46723c12204c00ff1f4eefb3636a7e7ad9e3c87736ed92e9de77aad6f29edae9b903a1517bb0cd8d1b24da46934ab1ae7acebc04c151b8f3a6151b7583f20f + languageName: node + linkType: hard + +"@deep-sea-stories/common@workspace:*, @deep-sea-stories/common@workspace:packages/common": + version: 0.0.0-use.local + resolution: "@deep-sea-stories/common@workspace:packages/common" + dependencies: + typescript: "npm:^5.9.2" + languageName: unknown + linkType: soft "@elevenlabs/elevenlabs-js@npm:^2.19.0": version: 2.19.0 @@ -322,7 +332,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/core@npm:^1.4.3, @emnapi/core@npm:^1.4.5": +"@emnapi/core@npm:^1.5.0": version: 1.5.0 resolution: "@emnapi/core@npm:1.5.0" dependencies: @@ -332,7 +342,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.4.5": +"@emnapi/runtime@npm:^1.5.0": version: 1.5.0 resolution: "@emnapi/runtime@npm:1.5.0" dependencies: @@ -341,7 +351,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/wasi-threads@npm:1.1.0, @emnapi/wasi-threads@npm:^1.0.4": +"@emnapi/wasi-threads@npm:1.1.0, @emnapi/wasi-threads@npm:^1.1.0": version: 1.1.0 resolution: "@emnapi/wasi-threads@npm:1.1.0" dependencies: @@ -350,196 +360,196 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/aix-ppc64@npm:0.25.10" +"@esbuild/aix-ppc64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/aix-ppc64@npm:0.25.11" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/android-arm64@npm:0.25.10" +"@esbuild/android-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/android-arm64@npm:0.25.11" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/android-arm@npm:0.25.10" +"@esbuild/android-arm@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/android-arm@npm:0.25.11" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/android-x64@npm:0.25.10" +"@esbuild/android-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/android-x64@npm:0.25.11" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/darwin-arm64@npm:0.25.10" +"@esbuild/darwin-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/darwin-arm64@npm:0.25.11" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/darwin-x64@npm:0.25.10" +"@esbuild/darwin-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/darwin-x64@npm:0.25.11" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/freebsd-arm64@npm:0.25.10" +"@esbuild/freebsd-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/freebsd-arm64@npm:0.25.11" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/freebsd-x64@npm:0.25.10" +"@esbuild/freebsd-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/freebsd-x64@npm:0.25.11" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-arm64@npm:0.25.10" +"@esbuild/linux-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-arm64@npm:0.25.11" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-arm@npm:0.25.10" +"@esbuild/linux-arm@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-arm@npm:0.25.11" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-ia32@npm:0.25.10" +"@esbuild/linux-ia32@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-ia32@npm:0.25.11" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-loong64@npm:0.25.10" +"@esbuild/linux-loong64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-loong64@npm:0.25.11" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-mips64el@npm:0.25.10" +"@esbuild/linux-mips64el@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-mips64el@npm:0.25.11" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-ppc64@npm:0.25.10" +"@esbuild/linux-ppc64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-ppc64@npm:0.25.11" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-riscv64@npm:0.25.10" +"@esbuild/linux-riscv64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-riscv64@npm:0.25.11" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-s390x@npm:0.25.10" +"@esbuild/linux-s390x@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-s390x@npm:0.25.11" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/linux-x64@npm:0.25.10" +"@esbuild/linux-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/linux-x64@npm:0.25.11" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/netbsd-arm64@npm:0.25.10" +"@esbuild/netbsd-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/netbsd-arm64@npm:0.25.11" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/netbsd-x64@npm:0.25.10" +"@esbuild/netbsd-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/netbsd-x64@npm:0.25.11" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/openbsd-arm64@npm:0.25.10" +"@esbuild/openbsd-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/openbsd-arm64@npm:0.25.11" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/openbsd-x64@npm:0.25.10" +"@esbuild/openbsd-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/openbsd-x64@npm:0.25.11" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openharmony-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/openharmony-arm64@npm:0.25.10" +"@esbuild/openharmony-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/openharmony-arm64@npm:0.25.11" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/sunos-x64@npm:0.25.10" +"@esbuild/sunos-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/sunos-x64@npm:0.25.11" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/win32-arm64@npm:0.25.10" +"@esbuild/win32-arm64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/win32-arm64@npm:0.25.11" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/win32-ia32@npm:0.25.10" +"@esbuild/win32-ia32@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/win32-ia32@npm:0.25.11" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.25.10": - version: 0.25.10 - resolution: "@esbuild/win32-x64@npm:0.25.10" +"@esbuild/win32-x64@npm:0.25.11": + version: 0.25.11 + resolution: "@esbuild/win32-x64@npm:0.25.11" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@fastify/ajv-compiler@npm:^4.0.0": - version: 4.0.2 - resolution: "@fastify/ajv-compiler@npm:4.0.2" + version: 4.0.5 + resolution: "@fastify/ajv-compiler@npm:4.0.5" dependencies: ajv: "npm:^8.12.0" ajv-formats: "npm:^3.0.1" fast-uri: "npm:^3.0.0" - checksum: 10c0/ca048db219cc958fb1b962f5dfc141f29e067ecb28a8dbe782bbef80ae3c920021468009cad613f0ed68db410890bb09c773ba2f33cb13e055b48c9c338bd8fa + checksum: 10c0/b701602c5fad35d1327a6ebda530ca5ba2c7728223cd214b2b24af7cb2522c864b6cbbe77335ddd6a55d03f76899fb009386da783121b7ece136feb7ea937e13 languageName: node linkType: hard @@ -586,12 +596,12 @@ __metadata: linkType: hard "@fishjam-cloud/js-server-sdk@npm:^0.22.0": - version: 0.22.0 - resolution: "@fishjam-cloud/js-server-sdk@npm:0.22.0" + version: 0.22.1 + resolution: "@fishjam-cloud/js-server-sdk@npm:0.22.1" dependencies: axios: "npm:^1.7.9" uuid: "npm:^11.1.0" - checksum: 10c0/cf1022a0887e4df018c9b449999d85349b64214c20a7620d78d11d9b9c26571d126e82ebb448115e72054cd13112eb386df1db2a87bbfffc26feb8a385f662c4 + checksum: 10c0/a6d005795b820459339787d613422b15c27fbc0c1bc903a33f92bc268af7a2ea762066b4261ab9bd2b545db668e8ea7b490ae73471cb992eeafddb53299a5a2f languageName: node linkType: hard @@ -724,14 +734,14 @@ __metadata: languageName: node linkType: hard -"@napi-rs/wasm-runtime@npm:^0.2.12": - version: 0.2.12 - resolution: "@napi-rs/wasm-runtime@npm:0.2.12" +"@napi-rs/wasm-runtime@npm:^1.0.7": + version: 1.0.7 + resolution: "@napi-rs/wasm-runtime@npm:1.0.7" dependencies: - "@emnapi/core": "npm:^1.4.3" - "@emnapi/runtime": "npm:^1.4.3" - "@tybys/wasm-util": "npm:^0.10.0" - checksum: 10c0/6d07922c0613aab30c6a497f4df297ca7c54e5b480e00035e0209b872d5c6aab7162fc49477267556109c2c7ed1eb9c65a174e27e9b87568106a87b0a6e3ca7d + "@emnapi/core": "npm:^1.5.0" + "@emnapi/runtime": "npm:^1.5.0" + "@tybys/wasm-util": "npm:^0.10.1" + checksum: 10c0/2d8635498136abb49d6dbf7395b78c63422292240963bf055f307b77aeafbde57ae2c0ceaaef215601531b36d6eb92a2cdd6f5ba90ed2aa8127c27aff9c4ae55 languageName: node linkType: hard @@ -757,6 +767,13 @@ __metadata: languageName: node linkType: hard +"@pinojs/redact@npm:^0.4.0": + version: 0.4.0 + resolution: "@pinojs/redact@npm:0.4.0" + checksum: 10c0/4b311ba17ee0cf154ff9c39eb063ec04cd0d0017cb3750efcdf06c2d485df3e1095e13e872175993568c5568c23e4508dd877c981bbc9c5ae5e384d569efcdff + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -1297,284 +1314,282 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.52.3" +"@rollup/rollup-android-arm-eabi@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.52.5" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-android-arm64@npm:4.52.3" +"@rollup/rollup-android-arm64@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-android-arm64@npm:4.52.5" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-darwin-arm64@npm:4.52.3" +"@rollup/rollup-darwin-arm64@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-darwin-arm64@npm:4.52.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-darwin-x64@npm:4.52.3" +"@rollup/rollup-darwin-x64@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-darwin-x64@npm:4.52.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.52.3" +"@rollup/rollup-freebsd-arm64@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.52.5" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-freebsd-x64@npm:4.52.3" +"@rollup/rollup-freebsd-x64@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-freebsd-x64@npm:4.52.5" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.52.3" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.52.5" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.52.3" +"@rollup/rollup-linux-arm-musleabihf@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.52.5" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.52.3" +"@rollup/rollup-linux-arm64-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.52.5" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.52.3" +"@rollup/rollup-linux-arm64-musl@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.52.5" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loong64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.52.3" +"@rollup/rollup-linux-loong64-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.52.5" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.52.3" +"@rollup/rollup-linux-ppc64-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.52.5" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.52.3" +"@rollup/rollup-linux-riscv64-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.52.5" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.52.3" +"@rollup/rollup-linux-riscv64-musl@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.52.5" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.52.3" +"@rollup/rollup-linux-s390x-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.52.5" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.52.3" +"@rollup/rollup-linux-x64-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.52.5" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.52.3" +"@rollup/rollup-linux-x64-musl@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.52.5" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-openharmony-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-openharmony-arm64@npm:4.52.3" +"@rollup/rollup-openharmony-arm64@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.52.5" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.52.3" +"@rollup/rollup-win32-arm64-msvc@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.52.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.52.3" +"@rollup/rollup-win32-ia32-msvc@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.52.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-x64-gnu@npm:4.52.3" +"@rollup/rollup-win32-x64-gnu@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.52.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.52.3" +"@rollup/rollup-win32-x64-msvc@npm:4.52.5": + version: 4.52.5 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.52.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@tailwindcss/node@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/node@npm:4.1.13" +"@tailwindcss/node@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/node@npm:4.1.15" dependencies: "@jridgewell/remapping": "npm:^2.3.4" enhanced-resolve: "npm:^5.18.3" - jiti: "npm:^2.5.1" - lightningcss: "npm:1.30.1" - magic-string: "npm:^0.30.18" + jiti: "npm:^2.6.0" + lightningcss: "npm:1.30.2" + magic-string: "npm:^0.30.19" source-map-js: "npm:^1.2.1" - tailwindcss: "npm:4.1.13" - checksum: 10c0/969b2eaefced271655fdf53a07737103736115c6b55fa1559c78147d17871da988c165ab2236bf4da8cdbde1e50a5116b8df2225e20f63de981d43da5b69e3f1 + tailwindcss: "npm:4.1.15" + checksum: 10c0/2bf8a04c7cb480bd7e41c75228b50ba020705653ef92b4bb2463488dc7a1d3e6c8e9c8d3a0780adb98640ac9ea705106f824f6d2b4c6e3f7205f5eec08af4b74 languageName: node linkType: hard -"@tailwindcss/oxide-android-arm64@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-android-arm64@npm:4.1.13" +"@tailwindcss/oxide-android-arm64@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-android-arm64@npm:4.1.15" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@tailwindcss/oxide-darwin-arm64@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-darwin-arm64@npm:4.1.13" +"@tailwindcss/oxide-darwin-arm64@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-darwin-arm64@npm:4.1.15" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@tailwindcss/oxide-darwin-x64@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-darwin-x64@npm:4.1.13" +"@tailwindcss/oxide-darwin-x64@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-darwin-x64@npm:4.1.15" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@tailwindcss/oxide-freebsd-x64@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-freebsd-x64@npm:4.1.13" +"@tailwindcss/oxide-freebsd-x64@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-freebsd-x64@npm:4.1.15" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.1.13" +"@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.1.15" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@tailwindcss/oxide-linux-arm64-gnu@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-linux-arm64-gnu@npm:4.1.13" +"@tailwindcss/oxide-linux-arm64-gnu@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-linux-arm64-gnu@npm:4.1.15" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@tailwindcss/oxide-linux-arm64-musl@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-linux-arm64-musl@npm:4.1.13" +"@tailwindcss/oxide-linux-arm64-musl@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-linux-arm64-musl@npm:4.1.15" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@tailwindcss/oxide-linux-x64-gnu@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-linux-x64-gnu@npm:4.1.13" +"@tailwindcss/oxide-linux-x64-gnu@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-linux-x64-gnu@npm:4.1.15" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@tailwindcss/oxide-linux-x64-musl@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-linux-x64-musl@npm:4.1.13" +"@tailwindcss/oxide-linux-x64-musl@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-linux-x64-musl@npm:4.1.15" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@tailwindcss/oxide-wasm32-wasi@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-wasm32-wasi@npm:4.1.13" +"@tailwindcss/oxide-wasm32-wasi@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-wasm32-wasi@npm:4.1.15" dependencies: - "@emnapi/core": "npm:^1.4.5" - "@emnapi/runtime": "npm:^1.4.5" - "@emnapi/wasi-threads": "npm:^1.0.4" - "@napi-rs/wasm-runtime": "npm:^0.2.12" - "@tybys/wasm-util": "npm:^0.10.0" - tslib: "npm:^2.8.0" + "@emnapi/core": "npm:^1.5.0" + "@emnapi/runtime": "npm:^1.5.0" + "@emnapi/wasi-threads": "npm:^1.1.0" + "@napi-rs/wasm-runtime": "npm:^1.0.7" + "@tybys/wasm-util": "npm:^0.10.1" + tslib: "npm:^2.4.0" conditions: cpu=wasm32 languageName: node linkType: hard -"@tailwindcss/oxide-win32-arm64-msvc@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-win32-arm64-msvc@npm:4.1.13" +"@tailwindcss/oxide-win32-arm64-msvc@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-win32-arm64-msvc@npm:4.1.15" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@tailwindcss/oxide-win32-x64-msvc@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide-win32-x64-msvc@npm:4.1.13" +"@tailwindcss/oxide-win32-x64-msvc@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide-win32-x64-msvc@npm:4.1.15" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@tailwindcss/oxide@npm:4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/oxide@npm:4.1.13" - dependencies: - "@tailwindcss/oxide-android-arm64": "npm:4.1.13" - "@tailwindcss/oxide-darwin-arm64": "npm:4.1.13" - "@tailwindcss/oxide-darwin-x64": "npm:4.1.13" - "@tailwindcss/oxide-freebsd-x64": "npm:4.1.13" - "@tailwindcss/oxide-linux-arm-gnueabihf": "npm:4.1.13" - "@tailwindcss/oxide-linux-arm64-gnu": "npm:4.1.13" - "@tailwindcss/oxide-linux-arm64-musl": "npm:4.1.13" - "@tailwindcss/oxide-linux-x64-gnu": "npm:4.1.13" - "@tailwindcss/oxide-linux-x64-musl": "npm:4.1.13" - "@tailwindcss/oxide-wasm32-wasi": "npm:4.1.13" - "@tailwindcss/oxide-win32-arm64-msvc": "npm:4.1.13" - "@tailwindcss/oxide-win32-x64-msvc": "npm:4.1.13" - detect-libc: "npm:^2.0.4" - tar: "npm:^7.4.3" +"@tailwindcss/oxide@npm:4.1.15": + version: 4.1.15 + resolution: "@tailwindcss/oxide@npm:4.1.15" + dependencies: + "@tailwindcss/oxide-android-arm64": "npm:4.1.15" + "@tailwindcss/oxide-darwin-arm64": "npm:4.1.15" + "@tailwindcss/oxide-darwin-x64": "npm:4.1.15" + "@tailwindcss/oxide-freebsd-x64": "npm:4.1.15" + "@tailwindcss/oxide-linux-arm-gnueabihf": "npm:4.1.15" + "@tailwindcss/oxide-linux-arm64-gnu": "npm:4.1.15" + "@tailwindcss/oxide-linux-arm64-musl": "npm:4.1.15" + "@tailwindcss/oxide-linux-x64-gnu": "npm:4.1.15" + "@tailwindcss/oxide-linux-x64-musl": "npm:4.1.15" + "@tailwindcss/oxide-wasm32-wasi": "npm:4.1.15" + "@tailwindcss/oxide-win32-arm64-msvc": "npm:4.1.15" + "@tailwindcss/oxide-win32-x64-msvc": "npm:4.1.15" dependenciesMeta: "@tailwindcss/oxide-android-arm64": optional: true @@ -1600,38 +1615,38 @@ __metadata: optional: true "@tailwindcss/oxide-win32-x64-msvc": optional: true - checksum: 10c0/7cc64827b0c854724a3b371a7f1484535db5cca9f53dda359631bce9c42b043f2822db6c5359f7ed9f1c8adbc48ecb52c414454f9330ffd25a9a679686d2a83e + checksum: 10c0/81b3f5f0029d1b9e97bd0472449fad406f654d1471888d2bd8d9a645f1f253416bf804a5b3a42cf4087f3f85defe0e7a432f6b37791bed2a623b02795a1db450 languageName: node linkType: hard "@tailwindcss/vite@npm:^4.1.13": - version: 4.1.13 - resolution: "@tailwindcss/vite@npm:4.1.13" + version: 4.1.15 + resolution: "@tailwindcss/vite@npm:4.1.15" dependencies: - "@tailwindcss/node": "npm:4.1.13" - "@tailwindcss/oxide": "npm:4.1.13" - tailwindcss: "npm:4.1.13" + "@tailwindcss/node": "npm:4.1.15" + "@tailwindcss/oxide": "npm:4.1.15" + tailwindcss: "npm:4.1.15" peerDependencies: vite: ^5.2.0 || ^6 || ^7 - checksum: 10c0/4e9b1d54a64655b775f26816a7be52236d4716a35f88af6b835fcb4f7f466db3c9cbb6c052e5550a97b3e5cff821f337cd6d9ddefd480e71db21a2844719b20e + checksum: 10c0/56e72cb7c04c1874ac15a7939198a906fe337625a98df5566946d710cfe69d88e11f4fef666e58c71a9fb8aee0b90e89e01ac780d6335f21161508efd0b2e32a languageName: node linkType: hard -"@tanstack/query-core@npm:5.90.2": - version: 5.90.2 - resolution: "@tanstack/query-core@npm:5.90.2" - checksum: 10c0/695a7450b0bb9f6dd21bebeacfc962dfc886631a3b3a13c33a842ef719b4c3dd30c15febe8c1ade6902a85e0f387c51a97570f430cc8f5c7032ff737d6410597 +"@tanstack/query-core@npm:5.90.5": + version: 5.90.5 + resolution: "@tanstack/query-core@npm:5.90.5" + checksum: 10c0/3b9460cc10d494357a30ddd3138f2a831611d14b5b8ce3587daa17a078d63945fcdf419864d9dc8e1249aa89b512003d2f134977c64ceccdbdfdd79f1f7e0a34 languageName: node linkType: hard "@tanstack/react-query@npm:^5.90.2": - version: 5.90.2 - resolution: "@tanstack/react-query@npm:5.90.2" + version: 5.90.5 + resolution: "@tanstack/react-query@npm:5.90.5" dependencies: - "@tanstack/query-core": "npm:5.90.2" + "@tanstack/query-core": "npm:5.90.5" peerDependencies: react: ^18 || ^19 - checksum: 10c0/22e76626a59890409858521b0e42b49219126a4ea5ed79eaa48a267959175dfdd28b30b9b03a415dccf703d95c18100a9d8917679818f6d2adc26d6c5f96a4d6 + checksum: 10c0/b2450259e40afc2aec5e455414f204c511ec98ebbbd25963316ab72b25758722ee424ed51210bd6863f78f03ae414e18571879f9d70a022e11049f3f04ef5ce2 languageName: node linkType: hard @@ -1675,7 +1690,7 @@ __metadata: languageName: node linkType: hard -"@tybys/wasm-util@npm:^0.10.0": +"@tybys/wasm-util@npm:^0.10.1": version: 0.10.1 resolution: "@tybys/wasm-util@npm:0.10.1" dependencies: @@ -1732,21 +1747,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": - version: 24.7.0 - resolution: "@types/node@npm:24.7.0" +"@types/node@npm:*, @types/node@npm:^24.5.2": + version: 24.8.1 + resolution: "@types/node@npm:24.8.1" dependencies: undici-types: "npm:~7.14.0" - checksum: 10c0/f036c78062cb3a0d5c6586bf2dac347ed3f4af121cef4ab92c85c44e32be1c50aab5ba96955842b7f8165f0e0f1c8066d1813ae259372df6c0fa9fadb1116a3e - languageName: node - linkType: hard - -"@types/node@npm:^24.5.2": - version: 24.6.1 - resolution: "@types/node@npm:24.6.1" - dependencies: - undici-types: "npm:~7.13.0" - checksum: 10c0/f2f8aea441d72139345cfa2e392af51bc27d12eb5f74b9b4d202046a2e82ab70d6da89c46a2ac7feea98854c2919e53070869d4af9d448e173a77249fcb7bca3 + checksum: 10c0/d185f2f14aa26cc2b482aa730bfc452943f9636df37aad6ceed80aa397f1278f894043336bd72f74c47b3dbef23e772ac9b1a256168984aa8aee26836132d290 languageName: node linkType: hard @@ -1758,20 +1764,20 @@ __metadata: linkType: hard "@types/react-dom@npm:^19.1.9": - version: 19.1.9 - resolution: "@types/react-dom@npm:19.1.9" + version: 19.2.2 + resolution: "@types/react-dom@npm:19.2.2" peerDependencies: - "@types/react": ^19.0.0 - checksum: 10c0/34c8dda86c1590b3ef0e7ecd38f9663a66ba2dd69113ba74fb0adc36b83bbfb8c94c1487a2505282a5f7e5e000d2ebf36f4c0fd41b3b672f5178fd1d4f1f8f58 + "@types/react": ^19.2.0 + checksum: 10c0/6154dfb8e7a638313d7fa15b2b16494f2235afda4c43be37d10f34e5c7a730f6b95117facb5e6eebc73b15cceea7f6da23be46cda5d2262fd00fd7e6069547e3 languageName: node linkType: hard "@types/react@npm:^19.1.13": - version: 19.1.16 - resolution: "@types/react@npm:19.1.16" + version: 19.2.2 + resolution: "@types/react@npm:19.2.2" dependencies: csstype: "npm:^3.0.2" - checksum: 10c0/3d781f715f15f308b601d74142fae77c65679c318a3bb0a319df898f39095e738ba7ed7061cec971b19b6d33969ef9cd50fec92b034024ef3fcc25bb9a2eb3d0 + checksum: 10c0/f830b1204aca4634ce3c6cb3477b5d3d066b80a4dd832a4ee0069acb504b6debd2416548a43a11c1407c12bc60e2dc6cf362934a18fe75fe06a69c0a98cba8ab languageName: node linkType: hard @@ -1890,6 +1896,8 @@ __metadata: dependencies: tslib: "npm:^2.0.0" checksum: 10c0/7720cb539497a9f760f68f98a4b30f22c6767aa0e72fa7d58279f7c164e258fc38b2699828f8de881aab0fc8e9c56d1313a3f1a965046fc0381a554dbc72b54a + languageName: node + linkType: hard "asap@npm:^2.0.3": version: 2.0.6 @@ -1984,11 +1992,11 @@ __metadata: linkType: hard "baseline-browser-mapping@npm:^2.8.9": - version: 2.8.10 - resolution: "baseline-browser-mapping@npm:2.8.10" + version: 2.8.18 + resolution: "baseline-browser-mapping@npm:2.8.18" bin: baseline-browser-mapping: dist/cli.js - checksum: 10c0/3ab9eee25e161a689b70b82887c8ee5cefb690a50da1d15655e2dd959de70916a43789b5ddf6968e272029002891e90a5cb46ed90ee54042e6aeae3b1c9630d4 + checksum: 10c0/fa319aab5761ccb78ec7f5e5905149ae1916d65b68009aa1c8b6ec7f0bdb878bfa57a553235024179ed5ba8b36d668a22f599861990ce6ceb1aeeafb1e5704ae languageName: node linkType: hard @@ -2047,9 +2055,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001746": - version: 1.0.30001746 - resolution: "caniuse-lite@npm:1.0.30001746" - checksum: 10c0/e656a9dc811be2316e3b6dbd3bf25d0e32dbce645b1284821b4ec93fb81dc3e3f73b9473e2f66c921b620ea8b25ebbae9ee70c3d13dad85f8dd69d6bb2c91d46 + version: 1.0.30001751 + resolution: "caniuse-lite@npm:1.0.30001751" + checksum: 10c0/c3f2d448f3569004ace160fd9379ea0def8e7a7bc6e65611baadb57d24e1f418258647a6210e46732419f5663e2356c22aa841f92449dd3849eb6471bb7ad592 languageName: node linkType: hard @@ -2108,14 +2116,6 @@ __metadata: languageName: node linkType: hard -"common@workspace:*, common@workspace:packages/common": - version: 0.0.0-use.local - resolution: "common@workspace:packages/common" - dependencies: - typescript: "npm:^5.9.2" - languageName: unknown - linkType: soft - "command-exists@npm:^1.2.9": version: 1.2.9 resolution: "command-exists@npm:1.2.9" @@ -2204,10 +2204,10 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.3, detect-libc@npm:^2.0.4": - version: 2.1.1 - resolution: "detect-libc@npm:2.1.1" - checksum: 10c0/97053299c1f68c7c4adf7b78c8d506e1d5f3a3fbc775920aaa0ecf7f8fcc6dfa46338a6ca82fe4500b4a51937def314584265a4ec9d565577485c4496aa7d64e +"detect-libc@npm:^2.0.3": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4 languageName: node linkType: hard @@ -2244,9 +2244,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.5.227": - version: 1.5.228 - resolution: "electron-to-chromium@npm:1.5.228" - checksum: 10c0/e04272ca5bf086cdea17c6ae855047bf3164c26e38ba76da38a09d57977daf5fa7ced225173315252a98d6784af4172e6cb8d8ab5ed0fe4acf3f503dcbab159b + version: 1.5.237 + resolution: "electron-to-chromium@npm:1.5.237" + checksum: 10c0/b9a9ba6ba3db5cc7e402fcc78f2ddf8bfc4b142dfcfa83e37a6ba99337d186025c4311db345d95ecf2b404e9d3fcd5ec7b1be56e6b998ff6b8fe348569eaf4b7 languageName: node linkType: hard @@ -2342,35 +2342,35 @@ __metadata: linkType: hard "esbuild@npm:^0.25.0, esbuild@npm:~0.25.0": - version: 0.25.10 - resolution: "esbuild@npm:0.25.10" - dependencies: - "@esbuild/aix-ppc64": "npm:0.25.10" - "@esbuild/android-arm": "npm:0.25.10" - "@esbuild/android-arm64": "npm:0.25.10" - "@esbuild/android-x64": "npm:0.25.10" - "@esbuild/darwin-arm64": "npm:0.25.10" - "@esbuild/darwin-x64": "npm:0.25.10" - "@esbuild/freebsd-arm64": "npm:0.25.10" - "@esbuild/freebsd-x64": "npm:0.25.10" - "@esbuild/linux-arm": "npm:0.25.10" - "@esbuild/linux-arm64": "npm:0.25.10" - "@esbuild/linux-ia32": "npm:0.25.10" - "@esbuild/linux-loong64": "npm:0.25.10" - "@esbuild/linux-mips64el": "npm:0.25.10" - "@esbuild/linux-ppc64": "npm:0.25.10" - "@esbuild/linux-riscv64": "npm:0.25.10" - "@esbuild/linux-s390x": "npm:0.25.10" - "@esbuild/linux-x64": "npm:0.25.10" - "@esbuild/netbsd-arm64": "npm:0.25.10" - "@esbuild/netbsd-x64": "npm:0.25.10" - "@esbuild/openbsd-arm64": "npm:0.25.10" - "@esbuild/openbsd-x64": "npm:0.25.10" - "@esbuild/openharmony-arm64": "npm:0.25.10" - "@esbuild/sunos-x64": "npm:0.25.10" - "@esbuild/win32-arm64": "npm:0.25.10" - "@esbuild/win32-ia32": "npm:0.25.10" - "@esbuild/win32-x64": "npm:0.25.10" + version: 0.25.11 + resolution: "esbuild@npm:0.25.11" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.11" + "@esbuild/android-arm": "npm:0.25.11" + "@esbuild/android-arm64": "npm:0.25.11" + "@esbuild/android-x64": "npm:0.25.11" + "@esbuild/darwin-arm64": "npm:0.25.11" + "@esbuild/darwin-x64": "npm:0.25.11" + "@esbuild/freebsd-arm64": "npm:0.25.11" + "@esbuild/freebsd-x64": "npm:0.25.11" + "@esbuild/linux-arm": "npm:0.25.11" + "@esbuild/linux-arm64": "npm:0.25.11" + "@esbuild/linux-ia32": "npm:0.25.11" + "@esbuild/linux-loong64": "npm:0.25.11" + "@esbuild/linux-mips64el": "npm:0.25.11" + "@esbuild/linux-ppc64": "npm:0.25.11" + "@esbuild/linux-riscv64": "npm:0.25.11" + "@esbuild/linux-s390x": "npm:0.25.11" + "@esbuild/linux-x64": "npm:0.25.11" + "@esbuild/netbsd-arm64": "npm:0.25.11" + "@esbuild/netbsd-x64": "npm:0.25.11" + "@esbuild/openbsd-arm64": "npm:0.25.11" + "@esbuild/openbsd-x64": "npm:0.25.11" + "@esbuild/openharmony-arm64": "npm:0.25.11" + "@esbuild/sunos-x64": "npm:0.25.11" + "@esbuild/win32-arm64": "npm:0.25.11" + "@esbuild/win32-ia32": "npm:0.25.11" + "@esbuild/win32-x64": "npm:0.25.11" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -2426,7 +2426,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10c0/8ee5fdd43ed0d4092ce7f41577c63147f54049d5617763f0549c638bbe939e8adaa8f1a2728adb63417eb11df51956b7b0d8eb88ee08c27ad1d42960256158fa + checksum: 10c0/7f819b16a9f502091ddc6e1855291eaa5ede32c2b792cd8a8a60cc24faee469e3c7b607e2f22ea8684eb7c7bc377b2509e9f1cd50f10b3bf5042d1e9e4234be3 languageName: node linkType: hard @@ -2445,9 +2445,9 @@ __metadata: linkType: hard "exponential-backoff@npm:^3.1.1": - version: 3.1.2 - resolution: "exponential-backoff@npm:3.1.2" - checksum: 10c0/d9d3e1eafa21b78464297df91f1776f7fbaa3d5e3f7f0995648ca5b89c069d17055033817348d9f4a43d1c20b0eab84f75af6991751e839df53e4dfd6f22e844 + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 languageName: node linkType: hard @@ -2685,11 +2685,11 @@ __metadata: linkType: hard "get-tsconfig@npm:^4.7.5": - version: 4.10.1 - resolution: "get-tsconfig@npm:4.10.1" + version: 4.12.0 + resolution: "get-tsconfig@npm:4.12.0" dependencies: resolve-pkg-maps: "npm:^1.0.0" - checksum: 10c0/7f8e3dabc6a49b747920a800fb88e1952fef871cdf51b79e98db48275a5de6cdaf499c55ee67df5fa6fe7ce65f0063e26de0f2e53049b408c585aa74d39ffa21 + checksum: 10c0/3438106bd46bfc6595fce6117190f1ac0998de2e6916b40ec23b20c784b0b47e79ea2b920895b9ed26029b1f80b8867626fb24795d5f45abbdab716a4ba1ef92 languageName: node linkType: hard @@ -2853,7 +2853,7 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^2.5.1": +"jiti@npm:^2.6.0": version: 2.6.1 resolution: "jiti@npm:2.6.1" bin: @@ -2921,92 +2921,102 @@ __metadata: languageName: node linkType: hard -"lightningcss-darwin-arm64@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-darwin-arm64@npm:1.30.1" +"lightningcss-android-arm64@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-android-arm64@npm:1.30.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-arm64@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-darwin-arm64@npm:1.30.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"lightningcss-darwin-x64@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-darwin-x64@npm:1.30.1" +"lightningcss-darwin-x64@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-darwin-x64@npm:1.30.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"lightningcss-freebsd-x64@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-freebsd-x64@npm:1.30.1" +"lightningcss-freebsd-x64@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-freebsd-x64@npm:1.30.2" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"lightningcss-linux-arm-gnueabihf@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-linux-arm-gnueabihf@npm:1.30.1" +"lightningcss-linux-arm-gnueabihf@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.30.2" conditions: os=linux & cpu=arm languageName: node linkType: hard -"lightningcss-linux-arm64-gnu@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-linux-arm64-gnu@npm:1.30.1" +"lightningcss-linux-arm64-gnu@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-linux-arm64-gnu@npm:1.30.2" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-arm64-musl@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-linux-arm64-musl@npm:1.30.1" +"lightningcss-linux-arm64-musl@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-linux-arm64-musl@npm:1.30.2" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"lightningcss-linux-x64-gnu@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-linux-x64-gnu@npm:1.30.1" +"lightningcss-linux-x64-gnu@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-linux-x64-gnu@npm:1.30.2" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-x64-musl@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-linux-x64-musl@npm:1.30.1" +"lightningcss-linux-x64-musl@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-linux-x64-musl@npm:1.30.2" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"lightningcss-win32-arm64-msvc@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-win32-arm64-msvc@npm:1.30.1" +"lightningcss-win32-arm64-msvc@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-win32-arm64-msvc@npm:1.30.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"lightningcss-win32-x64-msvc@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss-win32-x64-msvc@npm:1.30.1" +"lightningcss-win32-x64-msvc@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss-win32-x64-msvc@npm:1.30.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"lightningcss@npm:1.30.1": - version: 1.30.1 - resolution: "lightningcss@npm:1.30.1" +"lightningcss@npm:1.30.2": + version: 1.30.2 + resolution: "lightningcss@npm:1.30.2" dependencies: detect-libc: "npm:^2.0.3" - lightningcss-darwin-arm64: "npm:1.30.1" - lightningcss-darwin-x64: "npm:1.30.1" - lightningcss-freebsd-x64: "npm:1.30.1" - lightningcss-linux-arm-gnueabihf: "npm:1.30.1" - lightningcss-linux-arm64-gnu: "npm:1.30.1" - lightningcss-linux-arm64-musl: "npm:1.30.1" - lightningcss-linux-x64-gnu: "npm:1.30.1" - lightningcss-linux-x64-musl: "npm:1.30.1" - lightningcss-win32-arm64-msvc: "npm:1.30.1" - lightningcss-win32-x64-msvc: "npm:1.30.1" + lightningcss-android-arm64: "npm:1.30.2" + lightningcss-darwin-arm64: "npm:1.30.2" + lightningcss-darwin-x64: "npm:1.30.2" + lightningcss-freebsd-x64: "npm:1.30.2" + lightningcss-linux-arm-gnueabihf: "npm:1.30.2" + lightningcss-linux-arm64-gnu: "npm:1.30.2" + lightningcss-linux-arm64-musl: "npm:1.30.2" + lightningcss-linux-x64-gnu: "npm:1.30.2" + lightningcss-linux-x64-musl: "npm:1.30.2" + lightningcss-win32-arm64-msvc: "npm:1.30.2" + lightningcss-win32-x64-msvc: "npm:1.30.2" dependenciesMeta: + lightningcss-android-arm64: + optional: true lightningcss-darwin-arm64: optional: true lightningcss-darwin-x64: @@ -3027,7 +3037,7 @@ __metadata: optional: true lightningcss-win32-x64-msvc: optional: true - checksum: 10c0/1e1ad908f3c68bf39d964a6735435a8dd5474fb2765076732d64a7b6aa2af1f084da65a9462443a9adfebf7dcfb02fb532fce1d78697f2a9de29c8f40f09aee3 + checksum: 10c0/5c0c73a33946dab65908d5cd1325df4efa290efb77f940b60f40448b5ab9a87d3ea665ef9bcf00df4209705050ecf2f7ecc649f44d6dfa5905bb50f15717e78d languageName: node linkType: hard @@ -3063,7 +3073,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.18": +"magic-string@npm:^0.30.19": version: 0.30.19 resolution: "magic-string@npm:0.30.19" dependencies: @@ -3236,6 +3246,8 @@ __metadata: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc checksum: 10c0/83590c11d359ce7e4ced14f6ea9dd7a691d5ce6843fe2dc520fc27e29ae1c535118478d03e7f172609c41b1ef1b8da6b8dd2d2acd6cd79cac1abbdbd5b99f2c4 + languageName: node + linkType: hard "node-fetch@npm:^2.7.0": version: 2.7.0 @@ -3252,8 +3264,8 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 11.4.2 - resolution: "node-gyp@npm:11.4.2" + version: 11.5.0 + resolution: "node-gyp@npm:11.5.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" @@ -3267,14 +3279,14 @@ __metadata: which: "npm:^5.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10c0/0bfd3e96770ed70f07798d881dd37b4267708966d868a0e585986baac487d9cf5831285579fd629a83dc4e434f53e6416ce301097f2ee464cb74d377e4d8bdbe + checksum: 10c0/31ff49586991b38287bb15c3d529dd689cfc32f992eed9e6997b9d712d5d21fe818a8b1bbfe3b76a7e33765c20210c5713212f4aa329306a615b87d8a786da3a languageName: node linkType: hard "node-releases@npm:^2.0.21": - version: 2.0.21 - resolution: "node-releases@npm:2.0.21" - checksum: 10c0/0eb94916eeebbda9d51da6a9ea47428a12b2bb0dd94930c949632b0c859356abf53b2e5a2792021f96c5fda4f791a8e195f2375b78ae7dba8d8bc3141baa1469 + version: 2.0.25 + resolution: "node-releases@npm:2.0.25" + checksum: 10c0/d4aeb1e04578d96e54d6c40540122e6240671b971887f04aca07b6805752a78de1f1c1522f3fa3843706bf8acf6de2cb35f104914957f269e328b41a9fa9fd2f languageName: node linkType: hard @@ -3378,8 +3390,8 @@ __metadata: linkType: hard "pino-pretty@npm:^13.1.1": - version: 13.1.1 - resolution: "pino-pretty@npm:13.1.1" + version: 13.1.2 + resolution: "pino-pretty@npm:13.1.2" dependencies: colorette: "npm:^2.0.7" dateformat: "npm:^4.6.3" @@ -3396,7 +3408,7 @@ __metadata: strip-json-comments: "npm:^5.0.2" bin: pino-pretty: bin.js - checksum: 10c0/845c07afd3d73cb96ad2049cfa7fca12b8280a51e30d6db8b490857690637556bb8e7f05b2fa640b3e4a7edd9b1369110042d670fda743ef98fe3be29876c8c7 + checksum: 10c0/4d8e7472e37bdb6e0d6d7d34f25f65ced46c0f64a9579bb805602321caf1c0b10359f89a1ee9742bea875f411a02ce7c19730f7a1e5387dfcfd10ff5c9804709 languageName: node linkType: hard @@ -3408,9 +3420,10 @@ __metadata: linkType: hard "pino@npm:^9.0.0": - version: 9.12.0 - resolution: "pino@npm:9.12.0" + version: 9.14.0 + resolution: "pino@npm:9.14.0" dependencies: + "@pinojs/redact": "npm:^0.4.0" atomic-sleep: "npm:^1.0.0" on-exit-leak-free: "npm:^2.1.0" pino-abstract-transport: "npm:^2.0.0" @@ -3419,12 +3432,11 @@ __metadata: quick-format-unescaped: "npm:^4.0.3" real-require: "npm:^0.2.0" safe-stable-stringify: "npm:^2.3.1" - slow-redact: "npm:^0.3.0" sonic-boom: "npm:^4.0.1" thread-stream: "npm:^3.0.0" bin: pino: bin.js - checksum: 10c0/5cfe093e972a8471a90f7f380c01379eed3fd937038acb97d1de9180f097c044855ca89a2e70baa699aec3e8dcaec037d03e2c90dde235102a3e17b40f54cc1f + checksum: 10c0/9a10d9bf820a585eae9bc270fb4e55c895e48280d54adbbb4063ec061694b22d8809c80203cf5fe9f920a54c832b0b8dfb67cb28a04baa13abebaf261a9c9f3e languageName: node linkType: hard @@ -3495,13 +3507,13 @@ __metadata: linkType: hard "react-dom@npm:^19.1.1": - version: 19.1.1 - resolution: "react-dom@npm:19.1.1" + version: 19.2.0 + resolution: "react-dom@npm:19.2.0" dependencies: - scheduler: "npm:^0.26.0" + scheduler: "npm:^0.27.0" peerDependencies: - react: ^19.1.1 - checksum: 10c0/8c91198510521299c56e4e8d5e3a4508b2734fb5e52f29eeac33811de64e76fe586ad32c32182e2e84e070d98df67125da346c3360013357228172dbcd20bcdd + react: ^19.2.0 + checksum: 10c0/fa2cae05248d01288e91523b590ce4e7635b1e13f1344e225f850d722a8da037bf0782f63b1c1d46353334e0c696909b82e582f8cad607948fde6f7646cc18d9 languageName: node linkType: hard @@ -3548,8 +3560,8 @@ __metadata: linkType: hard "react-router@npm:^7.9.3": - version: 7.9.3 - resolution: "react-router@npm:7.9.3" + version: 7.9.4 + resolution: "react-router@npm:7.9.4" dependencies: cookie: "npm:^1.0.1" set-cookie-parser: "npm:^2.6.0" @@ -3559,7 +3571,7 @@ __metadata: peerDependenciesMeta: react-dom: optional: true - checksum: 10c0/ad77654d53df38b66415d158dfeb42d589e732691da6cb3ce77e8e31cb295a809f2a280e2ea203119d2b9e944992ca87f309db5c6524649cba6fa6539f6c4a83 + checksum: 10c0/c7556b752fa88d2bff600ce3533c962dcbe9ca9bf71f9c4b8e8a21f904856990bcb284844d53eb1dd486adaa7567c7ecf0deb3e518262269ea1ea89bea246be4 languageName: node linkType: hard @@ -3580,9 +3592,9 @@ __metadata: linkType: hard "react@npm:^19.1.1": - version: 19.1.1 - resolution: "react@npm:19.1.1" - checksum: 10c0/8c9769a2dfd02e603af6445058325e6c8a24b47b185d0e461f66a6454765ddcaecb3f0a90184836c68bb509f3c38248359edbc42f0d07c23eb500a5c30c87b4e + version: 19.2.0 + resolution: "react@npm:19.2.0" + checksum: 10c0/1b6d64eacb9324725bfe1e7860cb7a6b8a34bc89a482920765ebff5c10578eb487e6b46b2f0df263bd27a25edbdae2c45e5ea5d81ae61404301c1a7192c38330 languageName: node linkType: hard @@ -3636,31 +3648,31 @@ __metadata: linkType: hard "rollup@npm:^4.43.0": - version: 4.52.3 - resolution: "rollup@npm:4.52.3" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.52.3" - "@rollup/rollup-android-arm64": "npm:4.52.3" - "@rollup/rollup-darwin-arm64": "npm:4.52.3" - "@rollup/rollup-darwin-x64": "npm:4.52.3" - "@rollup/rollup-freebsd-arm64": "npm:4.52.3" - "@rollup/rollup-freebsd-x64": "npm:4.52.3" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.52.3" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.52.3" - "@rollup/rollup-linux-arm64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-arm64-musl": "npm:4.52.3" - "@rollup/rollup-linux-loong64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-ppc64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-riscv64-musl": "npm:4.52.3" - "@rollup/rollup-linux-s390x-gnu": "npm:4.52.3" - "@rollup/rollup-linux-x64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-x64-musl": "npm:4.52.3" - "@rollup/rollup-openharmony-arm64": "npm:4.52.3" - "@rollup/rollup-win32-arm64-msvc": "npm:4.52.3" - "@rollup/rollup-win32-ia32-msvc": "npm:4.52.3" - "@rollup/rollup-win32-x64-gnu": "npm:4.52.3" - "@rollup/rollup-win32-x64-msvc": "npm:4.52.3" + version: 4.52.5 + resolution: "rollup@npm:4.52.5" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.52.5" + "@rollup/rollup-android-arm64": "npm:4.52.5" + "@rollup/rollup-darwin-arm64": "npm:4.52.5" + "@rollup/rollup-darwin-x64": "npm:4.52.5" + "@rollup/rollup-freebsd-arm64": "npm:4.52.5" + "@rollup/rollup-freebsd-x64": "npm:4.52.5" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.52.5" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.52.5" + "@rollup/rollup-linux-arm64-gnu": "npm:4.52.5" + "@rollup/rollup-linux-arm64-musl": "npm:4.52.5" + "@rollup/rollup-linux-loong64-gnu": "npm:4.52.5" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.52.5" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.52.5" + "@rollup/rollup-linux-riscv64-musl": "npm:4.52.5" + "@rollup/rollup-linux-s390x-gnu": "npm:4.52.5" + "@rollup/rollup-linux-x64-gnu": "npm:4.52.5" + "@rollup/rollup-linux-x64-musl": "npm:4.52.5" + "@rollup/rollup-openharmony-arm64": "npm:4.52.5" + "@rollup/rollup-win32-arm64-msvc": "npm:4.52.5" + "@rollup/rollup-win32-ia32-msvc": "npm:4.52.5" + "@rollup/rollup-win32-x64-gnu": "npm:4.52.5" + "@rollup/rollup-win32-x64-msvc": "npm:4.52.5" "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -3712,7 +3724,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10c0/5a7a3a2e8c7558df5652ecc126e0d9133df4d58c5a001777377202b52517fa48b43be5e21a2cbab6d85975b765991af72666b5132813da6e86ea47ae963b4e71 + checksum: 10c0/faf1697b305d13a149bb64a2bb7378344becc7c8580f56225c4c00adbf493d82480a44b3e3b1cc82a3ac5d1d4cab6dfc89e6635443895a2dc488969075f5b94d languageName: node linkType: hard @@ -3748,17 +3760,17 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.26.0": - version: 0.26.0 - resolution: "scheduler@npm:0.26.0" - checksum: 10c0/5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356 +"scheduler@npm:^0.27.0": + version: 0.27.0 + resolution: "scheduler@npm:0.27.0" + checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452 languageName: node linkType: hard "secure-json-parse@npm:^4.0.0": - version: 4.0.0 - resolution: "secure-json-parse@npm:4.0.0" - checksum: 10c0/1a298cf00e1de91e833cee5eb406d6e77fb2f7eca9bef3902047d49e7f5d3e6c21b5de61ff73466c831e716430bfe87d732a6e645a7dabb5f1e8a8e4d3e15eb4 + version: 4.1.0 + resolution: "secure-json-parse@npm:4.1.0" + checksum: 10c0/52b3f8125ea974db1333a5b63e6a1df550c36c0d5f9a263911d6732812bd02e938b30be324dcbbb9da3ef9bf5a84849e0dd911f56544003d3c09e8eee12504de languageName: node linkType: hard @@ -3772,11 +3784,11 @@ __metadata: linkType: hard "semver@npm:^7.3.5, semver@npm:^7.6.0": - version: 7.7.2 - resolution: "semver@npm:7.7.2" + version: 7.7.3 + resolution: "semver@npm:7.7.3" bin: semver: bin/semver.js - checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea + checksum: 10c0/4afe5c986567db82f44c8c6faef8fe9df2a9b1d98098fc1721f57c696c4c21cebd572f297fc21002f81889492345b8470473bc6f4aff5fb032a6ea59ea2bc45e languageName: node linkType: hard @@ -3810,13 +3822,6 @@ __metadata: languageName: node linkType: hard -"slow-redact@npm:^0.3.0": - version: 0.3.0 - resolution: "slow-redact@npm:0.3.0" - checksum: 10c0/bb2f77830f64fb01079849e0c6433c15e782b88cccb82d4b0d62ce216307cf514ea3f92e9b2c6ae1b1d613ac7743305d5f0324e94c9dc8e41908939456248f9a - languageName: node - linkType: hard - "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -3941,17 +3946,17 @@ __metadata: languageName: node linkType: hard -"tailwindcss@npm:4.1.13, tailwindcss@npm:^4.1.13": - version: 4.1.13 - resolution: "tailwindcss@npm:4.1.13" - checksum: 10c0/2b80b4b11463818fd16063b7cc13fd0f6e18d7e3c3e54bbdc98742981be807884addb1dd657bc6816cb4085197b7d583f5064f619e1039a54221ffa36b7ed4c0 +"tailwindcss@npm:4.1.15, tailwindcss@npm:^4.1.13": + version: 4.1.15 + resolution: "tailwindcss@npm:4.1.15" + checksum: 10c0/9023538f33c5d49003a19f68297d1b7d158fc9963a4c4023c588930665efbb192f020ad9f6566b007c2ce14458baeceb24337270c29eaa92ed753a8493594e43 languageName: node linkType: hard "tapable@npm:^2.2.0": - version: 2.2.3 - resolution: "tapable@npm:2.2.3" - checksum: 10c0/e57fd8e2d756c317f8726a1bec8f2c904bc42e37fcbd4a78211daeab89f42c734b6a20e61774321f47be9a421da628a0c78b62d36c5ed186f4d5232d09ae15f2 + version: 2.3.0 + resolution: "tapable@npm:2.3.0" + checksum: 10c0/cb9d67cc2c6a74dedc812ef3085d9d681edd2c1fa18e4aef57a3c0605fdbe44e6b8ea00bd9ef21bc74dd45314e39d31227aa031ebf2f5e38164df514136f2681 languageName: node linkType: hard @@ -3994,8 +3999,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": - "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -4003,7 +4006,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.8.0" +"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.4.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -4065,13 +4068,6 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~7.13.0": - version: 7.13.0 - resolution: "undici-types@npm:7.13.0" - checksum: 10c0/44bbb0935425291351bfd8039571f017295b5d6dc5727045d0a4fea8c6ffe73a6703b48ce010f9cb539b9041a75b463f8cfe1e7309cab7486452505fb0d66151 - languageName: node - linkType: hard - "undici-types@npm:~7.14.0": version: 7.14.0 resolution: "undici-types@npm:7.14.0" @@ -4152,8 +4148,8 @@ __metadata: linkType: hard "vite@npm:^7.1.7": - version: 7.1.7 - resolution: "vite@npm:7.1.7" + version: 7.1.11 + resolution: "vite@npm:7.1.11" dependencies: esbuild: "npm:^0.25.0" fdir: "npm:^6.5.0" @@ -4202,7 +4198,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/3f6bd61a65aaa81368f4dda804f0e23b103664724218ccb5a0b1a0c7e284df498107b57ced951dc40ae4c5d472435bc8fb5c836414e729ee7e102809eaf6ff80 + checksum: 10c0/c4aa7f47b1fb07f734ed6f4f605d73e5acf7ff9754d75b4adbfbdddf0e520413019834620c1f7b4a207bce7e1d20a2636c584db2b1b17f5a3ba2cd23d47e50ab languageName: node linkType: hard @@ -4210,6 +4206,7 @@ __metadata: version: 0.0.0-use.local resolution: "web@workspace:packages/web" dependencies: + "@deep-sea-stories/common": "workspace:*" "@fishjam-cloud/react-client": "npm:^0.20.0" "@radix-ui/react-dialog": "npm:^1.1.15" "@radix-ui/react-label": "npm:^2.1.7" @@ -4228,7 +4225,6 @@ __metadata: backend: "workspace:*" class-variance-authority: "npm:^0.7.1" clsx: "npm:^2.1.1" - common: "workspace:*" globals: "npm:^16.4.0" lucide-react: "npm:^0.544.0" next-themes: "npm:^0.4.6" @@ -4333,8 +4329,8 @@ __metadata: linkType: hard "zod@npm:^4.1.11": - version: 4.1.11 - resolution: "zod@npm:4.1.11" - checksum: 10c0/ce6a4c4acfbf51d7dd0f2669c82f207d62a1f00264eef608994b94eb99d86a74c99f59b0dd3e61ef82909ee136631378b709e0908f0a02a2d5c21d0c497de5db + version: 4.1.12 + resolution: "zod@npm:4.1.12" + checksum: 10c0/b64c1feb19e99d77075261eaf613e0b2be4dfcd3551eff65ad8b4f2a079b61e379854d066f7d447491fcf193f45babd8095551a9d47973d30b46b6d8e2c46774 languageName: node linkType: hard From 6e4574c2d7d7756bc0eaf8f8424af40ddc5a27c6 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Tue, 21 Oct 2025 13:04:31 +0200 Subject: [PATCH 50/65] choosing and starting game, agent audio working --- .../packages/backend/package.json | 1 + .../backend/src/controllers/stories.ts | 6 +- deep-sea-stories/packages/backend/src/main.ts | 6 + deep-sea-stories/packages/common/src/index.ts | 2 + deep-sea-stories/packages/common/src/types.ts | 5 + .../packages/web/src/components/PeerTile.tsx | 9 ++ .../web/src/components/RoomControls.tsx | 16 ++- .../src/components/StorySelectionPanel.tsx | 135 ++++++++++++++++++ .../packages/web/src/views/GameView.tsx | 4 + .../packages/web/src/views/HomeView.tsx | 33 ++++- .../packages/web/src/views/JoinView.tsx | 29 +++- .../packages/web/src/views/RoomView.tsx | 6 +- deep-sea-stories/yarn.lock | 18 +++ 13 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 deep-sea-stories/packages/common/src/types.ts create mode 100644 deep-sea-stories/packages/web/src/components/StorySelectionPanel.tsx diff --git a/deep-sea-stories/packages/backend/package.json b/deep-sea-stories/packages/backend/package.json index b84e1c7..e701675 100644 --- a/deep-sea-stories/packages/backend/package.json +++ b/deep-sea-stories/packages/backend/package.json @@ -5,6 +5,7 @@ "type": "module", "dependencies": { "@elevenlabs/elevenlabs-js": "^2.19.0", + "@fastify/cors": "^11.1.0", "@fishjam-cloud/js-server-sdk": "^0.22.0", "@trpc/server": "^11.6.0", "@types/nunjucks": "^3.2.6", diff --git a/deep-sea-stories/packages/backend/src/controllers/stories.ts b/deep-sea-stories/packages/backend/src/controllers/stories.ts index b0752b5..074fffb 100644 --- a/deep-sea-stories/packages/backend/src/controllers/stories.ts +++ b/deep-sea-stories/packages/backend/src/controllers/stories.ts @@ -31,5 +31,9 @@ export const startStory = publicProcedure }); export const getStories = publicProcedure.query(() => { - return stories.map((s) => s.title); + return stories.map((s) => ({ + id: s.id, + title: s.title, + front: s.front, + })); }); diff --git a/deep-sea-stories/packages/backend/src/main.ts b/deep-sea-stories/packages/backend/src/main.ts index c977f36..b37c6ec 100644 --- a/deep-sea-stories/packages/backend/src/main.ts +++ b/deep-sea-stories/packages/backend/src/main.ts @@ -3,6 +3,7 @@ import { fastifyTRPCPlugin, } from '@trpc/server/adapters/fastify'; import Fastify from 'fastify'; +import cors from '@fastify/cors'; import { CONFIG } from './config.js'; import { createContext } from './context.js'; import { type AppRouter, appRouter } from './router.js'; @@ -12,6 +13,11 @@ const fastify = Fastify({ logger: { transport: { target: 'pino-pretty' } }, }); +await fastify.register(cors, { + origin: true, + credentials: true, +}); + fastify.register(fastifyTRPCPlugin, { prefix: '/api/v1', trpcOptions: { diff --git a/deep-sea-stories/packages/common/src/index.ts b/deep-sea-stories/packages/common/src/index.ts index b7aa838..2e2d0e9 100644 --- a/deep-sea-stories/packages/common/src/index.ts +++ b/deep-sea-stories/packages/common/src/index.ts @@ -4,3 +4,5 @@ export type { JoinEvent, TranscriptionEvent, } from './events.js'; + +export type { StoryData } from './types'; diff --git a/deep-sea-stories/packages/common/src/types.ts b/deep-sea-stories/packages/common/src/types.ts new file mode 100644 index 0000000..c4a5a98 --- /dev/null +++ b/deep-sea-stories/packages/common/src/types.ts @@ -0,0 +1,5 @@ +export interface StoryData { + id: number; + title: string; + front: string; +} diff --git a/deep-sea-stories/packages/web/src/components/PeerTile.tsx b/deep-sea-stories/packages/web/src/components/PeerTile.tsx index e5537ed..49d5b7d 100644 --- a/deep-sea-stories/packages/web/src/components/PeerTile.tsx +++ b/deep-sea-stories/packages/web/src/components/PeerTile.tsx @@ -3,22 +3,30 @@ import { cn } from '@/lib/utils'; export type PeerTileProps = { stream?: MediaStream | null; + audioStream?: MediaStream | null; name: string; } & HTMLAttributes; export const PeerTile: FC = ({ stream, + audioStream, name, className, ...props }) => { const videoRef = useRef(null); + const audioRef = useRef(null); useEffect(() => { if (!videoRef.current) return; videoRef.current.srcObject = stream ?? null; }, [stream]); + useEffect(() => { + if (!audioRef.current) return; + audioRef.current.srcObject = audioStream ?? null; + }, [audioStream]); + return (
= ({ ) : (
{name}
)} +
); }; diff --git a/deep-sea-stories/packages/web/src/components/RoomControls.tsx b/deep-sea-stories/packages/web/src/components/RoomControls.tsx index 0b6d0b9..c1eca8b 100644 --- a/deep-sea-stories/packages/web/src/components/RoomControls.tsx +++ b/deep-sea-stories/packages/web/src/components/RoomControls.tsx @@ -1,10 +1,13 @@ import { Check } from 'lucide-react'; import type { FC } from 'react'; +import { useState } from 'react'; import CopyButton from './CopyButton'; import HowItWorks from './HowItWorks'; import HowToPlay from './HowToPlay'; +import StorySelectionPanel from './StorySelectionPanel'; import { Button } from './ui/button'; import { toast } from './ui/sonner'; +import { useTRPCClient } from '@/contexts/trpc'; export type RoomControlsProps = { roomId: string; @@ -12,6 +15,8 @@ export type RoomControlsProps = { const RoomControls: FC = ({ roomId }) => { const url = `https://dss.fishjam.io/${roomId}`; + const [isStoryPanelOpen, setIsStoryPanelOpen] = useState(false); + useTRPCClient().getStories.query(); return (
@@ -19,7 +24,11 @@ const RoomControls: FC = ({ roomId }) => { Deep Sea Stories
-
@@ -34,6 +43,11 @@ const RoomControls: FC = ({ roomId }) => { {url} + setIsStoryPanelOpen(false)} + roomId={roomId} + />
); }; diff --git a/deep-sea-stories/packages/web/src/components/StorySelectionPanel.tsx b/deep-sea-stories/packages/web/src/components/StorySelectionPanel.tsx new file mode 100644 index 0000000..5a04c29 --- /dev/null +++ b/deep-sea-stories/packages/web/src/components/StorySelectionPanel.tsx @@ -0,0 +1,135 @@ +import { Check } from 'lucide-react'; +import type { FC } from 'react'; +import { useEffect, useState } from 'react'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from './ui/dialog'; +import { Button } from './ui/button'; +import { useTRPCClient } from '@/contexts/trpc'; +import { toast } from './ui/sonner'; +import type { StoryData } from '@deep-sea-stories/common'; + +export type StorySelectionPanelProps = { + isOpen: boolean; + onClose: () => void; + roomId: string; + onStorySelected?: (storyIndex: number) => void; +}; + +const StorySelectionPanel: FC = ({ + isOpen, + onClose, + roomId, + onStorySelected, +}) => { + const trpcClient = useTRPCClient(); + const [selectedStoryId, setSelectedStoryId] = useState(null); + const [isStarting, setIsStarting] = useState(false); + const [stories, setStories] = useState([]); + const [isLoadingStories, setIsLoadingStories] = useState(false); + + useEffect(() => { + if (!isOpen) return; + + const fetchStories = async () => { + setIsLoadingStories(true); + try { + const fetchedStories = await trpcClient.getStories.query(); + setStories(fetchedStories); + } catch (error) { + console.error('Failed to fetch stories:', error); + toast('Failed to load stories', Check); + } finally { + setIsLoadingStories(false); + } + }; + + fetchStories(); + }, [isOpen, trpcClient]); + + const handleStartStory = async () => { + if (!selectedStoryId) return; + + setIsStarting(true); + try { + await trpcClient.startStory.mutate({ + roomId, + storyId: selectedStoryId, + }); + toast('Story started successfully', Check); + onStorySelected?.(selectedStoryId); + onClose(); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to start story'; + toast(`Error: ${errorMessage}`, Check); + } finally { + setIsStarting(false); + } + }; + + return ( + + + + Choose a Story + + Select a mystery story to play with your friends + + + +
+ {isLoadingStories ? ( +
+ Loading stories... +
+ ) : ( + stories.map((story) => ( + + )) + )} +
+ + {selectedStoryId && stories.length > 0 && ( +
+

Preview

+

+ {stories.find((s: StoryData) => s.id === selectedStoryId)?.front} +

+
+ )} + +
+ + +
+
+
+ ); +}; + +export default StorySelectionPanel; diff --git a/deep-sea-stories/packages/web/src/views/GameView.tsx b/deep-sea-stories/packages/web/src/views/GameView.tsx index 5ff0383..0d8127b 100644 --- a/deep-sea-stories/packages/web/src/views/GameView.tsx +++ b/deep-sea-stories/packages/web/src/views/GameView.tsx @@ -34,6 +34,10 @@ const GameView: FC = ({ roomId }) => { stream={ peer.customVideoTracks[0]?.stream ?? peer.cameraTrack?.stream } + audioStream={ + peer.tracks[0]?.stream ?? + peer.microphoneTrack?.stream + } /> ))} diff --git a/deep-sea-stories/packages/web/src/views/HomeView.tsx b/deep-sea-stories/packages/web/src/views/HomeView.tsx index ca071f6..afbe202 100644 --- a/deep-sea-stories/packages/web/src/views/HomeView.tsx +++ b/deep-sea-stories/packages/web/src/views/HomeView.tsx @@ -1,16 +1,39 @@ import Footer from '@/components/Footer'; -import LinkButton from '@/components/LinkButton'; import TitleBar from '@/components/TitleBar'; -import { generateDeepSeaSlug } from '@/lib/utils'; +import { useTRPCClient } from '@/contexts/trpc'; +import { useNavigate } from 'react-router'; +import { Button } from '@/components/ui/button'; +import { useState } from 'react'; export default function HomeView() { + const navigate = useNavigate(); + const trpcClient = useTRPCClient(); + const [isLoading, setIsLoading] = useState(false); + + const handleCreateRoom = async () => { + setIsLoading(true); + try { + const room = await trpcClient.createRoom.mutate(); + navigate(`/${room.id}`); + } catch (error) { + console.error('Failed to create room:', error); + } finally { + setIsLoading(false); + } + }; + return ( <>
- - Create a game room - +
diff --git a/deep-sea-stories/packages/web/src/views/JoinView.tsx b/deep-sea-stories/packages/web/src/views/JoinView.tsx index 8e450dc..197ac6b 100644 --- a/deep-sea-stories/packages/web/src/views/JoinView.tsx +++ b/deep-sea-stories/packages/web/src/views/JoinView.tsx @@ -1,5 +1,6 @@ import { useCamera, + useConnection, useInitializeDevices, useMicrophone, } from '@fishjam-cloud/react-client'; @@ -10,11 +11,19 @@ import { DeviceSelect } from '@/components/DeviceSelect'; import { PeerTile } from '@/components/PeerTile'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; +import { useTRPCClient } from '@/contexts/trpc'; -const JoinView: FC = () => { +interface JoinViewProps { + roomId: string; +} + + +const JoinView: FC = ({ roomId }) => { const { initializeDevices } = useInitializeDevices(); const wasCameraTurnedOff = useRef(false); + const { joinRoom } = useConnection(); const [name, setName] = useState(''); + const trpcClient = useTRPCClient(); const { isCameraOn, @@ -38,6 +47,20 @@ const JoinView: FC = () => { initAndTurnOnCamera(); }, [initAndTurnOnCamera]); + const handleEnterRoom = useCallback(async () => { + if (!roomId) return; + + try { + const { token } = await trpcClient.createPeer.mutate({ roomId }); + await joinRoom({ + peerToken: token, + peerMetadata: { name }, + }); + } catch (error) { + console.error('Failed to join room:', error); + } + }, [trpcClient, roomId, joinRoom, name]); + return ( <>
@@ -79,7 +102,9 @@ const JoinView: FC = () => {

nRLGCIC37AR9@X0*Y>0HL7 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

- +
); diff --git a/deep-sea-stories/packages/web/src/views/RoomView.tsx b/deep-sea-stories/packages/web/src/views/RoomView.tsx index d97bce2..e7e87eb 100644 --- a/deep-sea-stories/packages/web/src/views/RoomView.tsx +++ b/deep-sea-stories/packages/web/src/views/RoomView.tsx @@ -8,5 +8,9 @@ export default function RoomView() { const { peerStatus } = useConnection(); const isConnected = peerStatus === 'connected'; - return !isConnected ? : ; + return isConnected ? ( + + ) : ( + + ); } diff --git a/deep-sea-stories/yarn.lock b/deep-sea-stories/yarn.lock index ba6382e..cc552ad 100644 --- a/deep-sea-stories/yarn.lock +++ b/deep-sea-stories/yarn.lock @@ -553,6 +553,16 @@ __metadata: languageName: node linkType: hard +"@fastify/cors@npm:^11.1.0": + version: 11.1.0 + resolution: "@fastify/cors@npm:11.1.0" + dependencies: + fastify-plugin: "npm:^5.0.0" + toad-cache: "npm:^3.7.0" + checksum: 10c0/3e6051c94a6e35fc7029ab9b31f3baed3e370072605a18a53d7d2e28975a74480d522f049b3f23229881ea483b4146ffe3cd3e90894c9c12ae09eaba6250dfc6 + languageName: node + linkType: hard + "@fastify/error@npm:^4.0.0": version: 4.2.0 resolution: "@fastify/error@npm:4.2.0" @@ -1969,6 +1979,7 @@ __metadata: resolution: "backend@workspace:packages/backend" dependencies: "@elevenlabs/elevenlabs-js": "npm:^2.19.0" + "@fastify/cors": "npm:^11.1.0" "@fishjam-cloud/js-server-sdk": "npm:^0.22.0" "@trpc/server": "npm:^11.6.0" "@tsconfig/node24": "npm:^24.0.1" @@ -2509,6 +2520,13 @@ __metadata: languageName: node linkType: hard +"fastify-plugin@npm:^5.0.0": + version: 5.1.0 + resolution: "fastify-plugin@npm:5.1.0" + checksum: 10c0/61b330b8cb03a3581b796d745137499a782934abcf65dbf9a41d07248520cfd220b3ae8b16afeaf81af712e68e1ac24352895132cfeb2b372c66662c0170f365 + languageName: node + linkType: hard + "fastify@npm:^5.6.1": version: 5.6.1 resolution: "fastify@npm:5.6.1" From 9ead6810d8bb9622c3f8d7fc8e834b0d11de4c6f Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Tue, 21 Oct 2025 14:29:18 +0200 Subject: [PATCH 51/65] format, lint --- deep-sea-stories/packages/web/src/components/PeerTile.tsx | 8 +++++++- .../packages/web/src/components/RoomControls.tsx | 2 +- .../packages/web/src/components/StorySelectionPanel.tsx | 1 + deep-sea-stories/packages/web/src/views/GameView.tsx | 5 +---- deep-sea-stories/packages/web/src/views/JoinView.tsx | 1 - 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/deep-sea-stories/packages/web/src/components/PeerTile.tsx b/deep-sea-stories/packages/web/src/components/PeerTile.tsx index 49d5b7d..89a0075 100644 --- a/deep-sea-stories/packages/web/src/components/PeerTile.tsx +++ b/deep-sea-stories/packages/web/src/components/PeerTile.tsx @@ -47,7 +47,13 @@ export const PeerTile: FC = ({ ) : (
{name}
)} -