From da54ec6ee3e0d4725cd10103453e025e377e21b4 Mon Sep 17 00:00:00 2001 From: Last2014 Date: Thu, 2 Oct 2025 04:48:08 +0900 Subject: [PATCH] =?UTF-8?q?=E3=82=B5=E3=82=A4=E3=83=B3=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=83=BB=E3=82=B5=E3=82=A4=E3=83=B3=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=81=BE=E3=81=A7=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + files/.gitignore | 3 + files/peas.svg | 96 + locales/en.yaml | 86 + locales/ja.yaml | 86 + package.json | 30 + packages/web/.gitignore | 14 + packages/web/config/.gitignore | 2 + packages/web/config/config.d.ts | 13 + packages/web/config/example.config.ts | 17 + packages/web/package.json | 39 + packages/web/pnpm-lock.yaml | 2406 ++++++++++++++++++ packages/web/pnpm-workspace.yaml | 5 + packages/web/public/.gitignore | 1 + packages/web/public/js/mailverify.js | 45 + packages/web/public/js/signin.js | 48 + packages/web/public/js/signup.js | 52 + packages/web/src/components/help.tsx | 56 + packages/web/src/components/iconify.tsx | 26 + packages/web/src/components/turnstile.tsx | 37 + packages/web/src/lib/database.ts | 46 + packages/web/src/lib/locale.ts | 52 + packages/web/src/lib/mailer.ts | 67 + packages/web/src/lib/mailverify.ts | 76 + packages/web/src/lib/path.ts | 16 + packages/web/src/lib/toComponent.tsx | 3 + packages/web/src/lib/token.ts | 30 + packages/web/src/lib/turnstile.ts | 27 + packages/web/src/main.ts | 59 + packages/web/src/routes/api/info.ts | 65 + packages/web/src/routes/api/mailverify.ts | 101 + packages/web/src/routes/api/main.ts | 20 + packages/web/src/routes/api/notfound.ts | 12 + packages/web/src/routes/api/signin.ts | 123 + packages/web/src/routes/api/signup.ts | 135 + packages/web/src/routes/pages/home.tsx | 33 + packages/web/src/routes/pages/index.tsx | 155 ++ packages/web/src/routes/pages/layout.tsx | 73 + packages/web/src/routes/pages/mailverify.tsx | 141 + packages/web/src/routes/pages/main.ts | 23 + packages/web/src/routes/pages/notfound.tsx | 33 + packages/web/src/routes/pages/signin.tsx | 165 ++ packages/web/src/routes/pages/signup.tsx | 201 ++ packages/web/tailwind.config.ts | 15 + packages/web/tailwind.init.css | 2 + packages/web/tsconfig.json | 25 + packages/web/types/api/info.d.ts | 31 + packages/web/types/api/scope.d.ts | 5 + pnpm-lock.yaml | 506 ++++ scripts/peas.sql | 111 + scripts/setup.ts | 215 ++ tsconfig.json | 25 + 52 files changed, 5655 insertions(+) create mode 100644 .gitignore create mode 100644 files/.gitignore create mode 100644 files/peas.svg create mode 100644 locales/en.yaml create mode 100644 locales/ja.yaml create mode 100644 package.json create mode 100644 packages/web/.gitignore create mode 100644 packages/web/config/.gitignore create mode 100644 packages/web/config/config.d.ts create mode 100644 packages/web/config/example.config.ts create mode 100644 packages/web/package.json create mode 100644 packages/web/pnpm-lock.yaml create mode 100644 packages/web/pnpm-workspace.yaml create mode 100644 packages/web/public/.gitignore create mode 100644 packages/web/public/js/mailverify.js create mode 100644 packages/web/public/js/signin.js create mode 100644 packages/web/public/js/signup.js create mode 100644 packages/web/src/components/help.tsx create mode 100644 packages/web/src/components/iconify.tsx create mode 100644 packages/web/src/components/turnstile.tsx create mode 100644 packages/web/src/lib/database.ts create mode 100644 packages/web/src/lib/locale.ts create mode 100644 packages/web/src/lib/mailer.ts create mode 100644 packages/web/src/lib/mailverify.ts create mode 100644 packages/web/src/lib/path.ts create mode 100644 packages/web/src/lib/toComponent.tsx create mode 100644 packages/web/src/lib/token.ts create mode 100644 packages/web/src/lib/turnstile.ts create mode 100644 packages/web/src/main.ts create mode 100644 packages/web/src/routes/api/info.ts create mode 100644 packages/web/src/routes/api/mailverify.ts create mode 100644 packages/web/src/routes/api/main.ts create mode 100644 packages/web/src/routes/api/notfound.ts create mode 100644 packages/web/src/routes/api/signin.ts create mode 100644 packages/web/src/routes/api/signup.ts create mode 100644 packages/web/src/routes/pages/home.tsx create mode 100644 packages/web/src/routes/pages/index.tsx create mode 100644 packages/web/src/routes/pages/layout.tsx create mode 100644 packages/web/src/routes/pages/mailverify.tsx create mode 100644 packages/web/src/routes/pages/main.ts create mode 100644 packages/web/src/routes/pages/notfound.tsx create mode 100644 packages/web/src/routes/pages/signin.tsx create mode 100644 packages/web/src/routes/pages/signup.tsx create mode 100644 packages/web/tailwind.config.ts create mode 100644 packages/web/tailwind.init.css create mode 100644 packages/web/tsconfig.json create mode 100644 packages/web/types/api/info.d.ts create mode 100644 packages/web/types/api/scope.d.ts create mode 100644 pnpm-lock.yaml create mode 100644 scripts/peas.sql create mode 100644 scripts/setup.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a4908c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +node_modules diff --git a/files/.gitignore b/files/.gitignore new file mode 100644 index 0000000..b47eb38 --- /dev/null +++ b/files/.gitignore @@ -0,0 +1,3 @@ +* +!/.gitignore +!/peas.svg diff --git a/files/peas.svg b/files/peas.svg new file mode 100644 index 0000000..482da52 --- /dev/null +++ b/files/peas.svg @@ -0,0 +1,96 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/locales/en.yaml b/locales/en.yaml new file mode 100644 index 0000000..74278c2 --- /dev/null +++ b/locales/en.yaml @@ -0,0 +1,86 @@ +PeasAboutTitle: About Peas +PeasAboutText: | + Peas is a SNS designed for sharing profiles.
+ You can register and share your user profile.
+ You can freely create profile sections suitable for use at school or work and also change the privacy settings.
+ It also supports printing QR codes making sharing easy. +ServerAboutTitle: About this server +or: or +Start: Get started now +Signin: Sign In +Signup: Sign Up +email: Email +password: Password +username: Username +help: Help +idHelp: An alphanumeric ID consisting of 3 to 20 characters and beginning with @ +mailHelp: Use an email address that can be received +passwordHelp: Use a password of at least 8 characters +signinError: Sign in failed +mailVerify: Mail Verify +code: Code +submit: Submit +Home: Home +codeCharacterCount: Please enter a 6-digit code +emailVerificationSuccess: | + Email verification successful. + Please log in. +connectionError: Connection Error +accountCreateSuccess: | + Your account has been successfully created. + We have sent a confirmation email to the email address you registered. + Please click the confirmation email to activate your account. +sameUsername: That username is already taken +sameEmail: This email address is already in use. +termsAgreement: Please agree to the Terms of Service and Privacy Policy +bodyRequired: Form contents have not been submitted +passwordCharacterLimit: Please make your password at least 8 characters long. +usernameRestriction: Please make your username an alphanumeric ID with at least 3 characters. +userCreationFailed: Failed to create the user. +terms: Terms of Service +privacypolicy: Privacy Policy +agreeRule: I agree to the Terms of Use and Privacy Policy +userCount: User Count +communityCount: Community Count +loading: Loading +topPeasCredit: This server uses Peas({0}) an open-source software. +notFound: The page you are looking for could not be found +notFoundAbout: The specified page was not found on this server. +backtoHome: Return to home +error: An error occurred +mailverifyText: | + Hello {0}. + Email authentication is required for {1}. + By authenticating your email address, you will be able to use the {1} features. + Please visit {2}. +serverName: Server name +serverDescription: Server description +serverIconURL: Server icon image URL +Q_origin: Origin to use +Q_port: Port to broadcast to +Q_db_host: MariaDB host name +Q_db_port: MariaDB port +Q_db_user: MariaDB user +Q_db_pass: MariaDB password +Q_db_db: MariaDB database name +Q_turnstile_is_enabled: Do you want to enable Cloudflare Turnstile? +Q_turnstile_sitekey: Turnstile site key +Q_turnstile_secret: Turnstile secret key +Q_smtp_host: SMTP server hostname +Q_smtp_port: SMTP server port +Q_smtp_user: SMTP server user +Q_smtp_pass: SMTP server password +Q_smtp_secure: Do you use encryption for communications to the SMTP server? +CLISETUP_success: ✔Setup complete +CLI_config_file_write_success: The configuration file was written successfully. +ERR_input_lack: Insufficient input +ERR_turnstile_request_failed: An error occurred on the server while authenticating Turnstile +ERR_turnstile_failed: Turnstile authentication failed +ERR_username_duplicate: That username is already in use +ERR_email_duplicate: That email is already in use +ERR_account_create_failed: Account creation failed +ERR_length_different: Invalid character count +ERR_code_invalid: Incorrect code +ERR_code_not_found: Code not found +ERR_user_not_found: User not found +ERR_password_invalid: Incorrect password diff --git a/locales/ja.yaml b/locales/ja.yaml new file mode 100644 index 0000000..d213883 --- /dev/null +++ b/locales/ja.yaml @@ -0,0 +1,86 @@ +PeasAboutTitle: Peasについて +PeasAboutText: | + Peasはプロフィール共有を目的としたSNSです。
+ ユーザーのプロフィールを登録し、共有することが出来ます。
+ 学校や職場で使用できるようなプロフィール欄も自由に作成でき、公開設定も変更できます。
+ QRコードの印刷にも対応していて共有にも最適です。 +ServerAboutTitle: このサーバーについて +or: または +Start: 今すぐ始める +Signin: サインイン +Signup: サインアップ +email: メールアドレス +password: パスワード +username: ユーザー名 +help: ヘルプ +idHelp: 3文字以上20文字以下で@から始まる英数字のID +mailHelp: メールアドレスは受信できるものを使用してください +passwordHelp: 8文字以上15文字以下のパスワードを使用してください +signinError: サインインに失敗しました +mailVerify: メール認証 +code: コード +submit: 送信 +Home: ホーム +codeCharacterCount: コードは6桁で入力してください +emailVerificationSuccess: | + メール認証に成功しました。 + ログインしてください。 +connectionError: 通信エラー +accountCreateSuccess: | + アカウントの作成に成功しました。 + ご登録いただいたメールアドレスに確認用メールを送信しました。 + 確認メールをクリックしてアカウントを有効化してください。 +sameUsername: 同じユーザー名が既に使用されています +sameEmail: 同じメールアドレスが既に使用されています +termsAgreement: 利用規約とプライバシーポリシーに同意してください +bodyRequired: フォーム内容が送信されていません +passwordCharacterLimit: パスワードは8文字以上にしてください +usernameRestriction: ユーザー名は3文字以上の英数字のIDにしてください +userCreationFailed: ユーザーの作成に失敗しました +terms: 利用規約 +privacypolicy: プライバシーポリシー +agreeRule: 利用規約及びプライバシーポリシーに同意する +userCount: ユーザー数 +communityCount: 投稿数 +loading: 読み込み中 +topPeasCredit: このサーバーはオープンソースソフトウェアのPeas({0})を使用しています。 +notFound: お探しのページが見つかりませんでした +notFoundAbout: このサーバー上に指定されたページが見つかりません。 +backtoHome: ホームに戻る +error: エラーが発生しました +mailverifyText: | + {0}さんこんにちは。 + {1}ではメール認証が必要となっています。 + メール認証をすることで{1}の機能を利用することができます。 + {2} にアクセスしてください。 +serverName: サーバー名 +serverDescription: サーバー説明 +serverIconURL: サーバーアイコン画像のURL +Q_origin: 使用するオリジン +Q_port: 配信するポート +Q_db_host: MariaDBのホスト名 +Q_db_port: MariaDBのポート +Q_db_user: MariaDBのユーザー +Q_db_pass: MariaDBのパスワード +Q_db_db: MariaDBのデータベース名 +Q_turnstile_is_enabled: Cloudflare Turnstileを有効化しますか? +Q_turnstile_sitekey: Turnstileのサイトキー +Q_turnstile_secret: Turnstileのシークレットキー +Q_smtp_host: SMTPサーバーのホスト名 +Q_smtp_port: SMTPサーバーのポート +Q_smtp_user: SMTPサーバーのユーザー +Q_smtp_pass: SMTPサーバーのパスワード +Q_smtp_secure: SMTPサーバーへの通信に暗号化を使用しますか? +CLISETUP_success: ✔ セットアップが完了しました +CLI_config_file_write_success: 設定ファイルの書き込みに成功しました +ERR_input_lack: 入力が不足しています +ERR_turnstile_request_failed: Turnstileの認証中にサーバーでエラーが発生しました +ERR_turnstile_failed: Turnstileの認証ができませんでした +ERR_username_duplicate: そのユーザー名は既に使用されています +ERR_email_duplicate: そのメールアドレスは既に使用されています +ERR_account_create_failed: アカウントの作成に失敗しました +ERR_length_different: 文字数が正しくありません +ERR_code_invalid: コードが正しくありません +ERR_code_not_found: コードが見つかりません +ERR_user_not_found: ユーザーが見つかりません +ERR_password_invalid: パスワードが異なります diff --git a/package.json b/package.json new file mode 100644 index 0000000..e0e9023 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "peas", + "version": "1.0.0", + "private": true, + "description": "Peas is a SNS designed for sharing profiles.", + "scripts": { + "build:locale": "tsc" + }, + "keywords": [ + "sns", + "profile" + ], + "author": { + "name": "Last2014", + "email": "info@last2014.com", + "url": "https://last2014.com" + }, + "contributors": [], + "license": "AGPL-3.0-later", + "packageManager": "pnpm@10.17.0", + "type": "module", + "dependencies": { + "@inquirer/prompts": "^7.8.6", + "@types/node": "^24.5.2", + "fs": "0.0.1-security", + "mysql2": "^3.15.1", + "typescript": "^5.9.2", + "yaml": "^2.8.1" + } +} diff --git a/packages/web/.gitignore b/packages/web/.gitignore new file mode 100644 index 0000000..60c2539 --- /dev/null +++ b/packages/web/.gitignore @@ -0,0 +1,14 @@ +# modules +node_modules/ + +# logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# dist +/dist diff --git a/packages/web/config/.gitignore b/packages/web/config/.gitignore new file mode 100644 index 0000000..e7eebdd --- /dev/null +++ b/packages/web/config/.gitignore @@ -0,0 +1,2 @@ +!* +/peas.config.ts diff --git a/packages/web/config/config.d.ts b/packages/web/config/config.d.ts new file mode 100644 index 0000000..ffc9045 --- /dev/null +++ b/packages/web/config/config.d.ts @@ -0,0 +1,13 @@ +export default interface ConfigType { + server: { + port: number; + origin: string; + }, + database: { + host: string; + port: number; + user: string; + pass: string; + db: string; + }, +} diff --git a/packages/web/config/example.config.ts b/packages/web/config/example.config.ts new file mode 100644 index 0000000..12c624b --- /dev/null +++ b/packages/web/config/example.config.ts @@ -0,0 +1,17 @@ +import type ConfigType from "./config"; + +const Config: ConfigType = { + server: { + port: 3000, + origin: "https://peas.example.com", + }, + database: { + host: "db.example.com", + port: 3306, + user: "peas", + pass: "DatabasePassword", + db: "peas", + }, +} + +export default Config; diff --git a/packages/web/package.json b/packages/web/package.json new file mode 100644 index 0000000..f504317 --- /dev/null +++ b/packages/web/package.json @@ -0,0 +1,39 @@ +{ + "name": "web", + "type": "module", + "main": "dist/src/main.js", + "scripts": { + "build": "pnpm run \"/^build:.*/\"", + "build:ts": "tsc", + "build:css": "tailwindcss -i ./tailwind.init.css -o ./public/tailwind.css -m", + "start": "node .", + "dev": "pnpm run dev:build:css && pnpm run dev:start", + "dev:build:css": "pnpm run build:css", + "dev:start": "tsx --no-cache src/main.ts -tsx-develop" + }, + "dependencies": { + "@hono/node-server": "^1.19.3", + "@tailwindcss/cli": "^4.1.13", + "@types/bcrypt": "^6.0.0", + "@types/nodemailer": "^7.0.2", + "bcrypt": "^6.0.0", + "daisyui": "^5.1.25", + "fs": "0.0.1-security", + "globals": "^16.4.0", + "hono": "^4.9.8", + "jiti": "^2.5.1", + "mysql2": "^3.15.0", + "nodemailer": "^7.0.6", + "path": "^0.12.7", + "tailwindcss": "^4.1.13", + "ua-parser-js": "^2.0.5", + "url": "^0.11.4", + "uuid": "^13.0.0" + }, + "devDependencies": { + "@types/node": "^20.11.17", + "tsx": "^4.7.1", + "typescript": "^5.8.3" + }, + "packageManager": "pnpm@10.17.1" +} diff --git a/packages/web/pnpm-lock.yaml b/packages/web/pnpm-lock.yaml new file mode 100644 index 0000000..5fa5eac --- /dev/null +++ b/packages/web/pnpm-lock.yaml @@ -0,0 +1,2406 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@hono/node-server': + specifier: ^1.19.3 + version: 1.19.3(hono@4.9.8) + '@tailwindcss/cli': + specifier: ^4.1.13 + version: 4.1.13 + '@types/bcrypt': + specifier: ^6.0.0 + version: 6.0.0 + '@types/nodemailer': + specifier: ^7.0.2 + version: 7.0.2 + bcrypt: + specifier: ^6.0.0 + version: 6.0.0 + daisyui: + specifier: ^5.1.25 + version: 5.1.25 + fs: + specifier: 0.0.1-security + version: 0.0.1-security + globals: + specifier: ^16.4.0 + version: 16.4.0 + hono: + specifier: ^4.9.8 + version: 4.9.8 + jiti: + specifier: ^2.5.1 + version: 2.5.1 + mysql2: + specifier: ^3.15.0 + version: 3.15.0 + nodemailer: + specifier: ^7.0.6 + version: 7.0.6 + path: + specifier: ^0.12.7 + version: 0.12.7 + tailwindcss: + specifier: ^4.1.13 + version: 4.1.13 + ua-parser-js: + specifier: ^2.0.5 + version: 2.0.5 + url: + specifier: ^0.11.4 + version: 0.11.4 + uuid: + specifier: ^13.0.0 + version: 13.0.0 + devDependencies: + '@types/node': + specifier: ^20.11.17 + version: 20.19.17 + tsx: + specifier: ^4.7.1 + version: 4.20.5 + typescript: + specifier: ^5.8.3 + version: 5.9.2 + +packages: + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-sesv2@3.899.0': + resolution: {integrity: sha512-aMs3QgB9lWaKKrnx9KhIopoeXLNzI/sqdp5M56j30jlBD4vqdcCzW2OwFAAs26QzUgNKOOSY+iLZcE9DUDdIvg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-sso@3.899.0': + resolution: {integrity: sha512-EKz/iiVDv2OC8/3ONcXG3+rhphx9Heh7KXQdsZzsAXGVn6mWtrHQLrWjgONckmK4LrD07y4+5WlJlGkMxSMA5A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/core@3.899.0': + resolution: {integrity: sha512-Enp5Zw37xaRlnscyaelaUZNxVqyE3CTS8gjahFbW2bbzVtRD2itHBVgq8A3lvKiFb7Feoxa71aTe0fQ1I6AhQQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-env@3.899.0': + resolution: {integrity: sha512-wXQ//KQ751EFhUbdfoL/e2ZDaM8l2Cff+hVwFcj32yiZyeCMhnoLRMQk2euAaUOugqPY5V5qesFbHhISbIedtw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-http@3.899.0': + resolution: {integrity: sha512-/rRHyJFdnPrupjt/1q/PxaO6O26HFsguVUJSUeMeGUWLy0W8OC3slLFDNh89CgTqnplCyt1aLFMCagRM20HjNQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-ini@3.899.0': + resolution: {integrity: sha512-B8oFNFTDV0j1yiJiqzkC2ybml+theNnmsLrTLBhJbnBLWkxEcmVGKVIMnATW9BUCBhHmEtDiogdNIzSwP8tbMw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-node@3.899.0': + resolution: {integrity: sha512-nHBnZ2ZCOqTGJ2A9xpVj8iK6+WV+j0JNv3XGEkIuL4mqtGEPJlEex/0mD/hqc1VF8wZzojji2OQ3892m1mUOSA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-process@3.899.0': + resolution: {integrity: sha512-1PWSejKcJQUKBNPIqSHlEW4w8vSjmb+3kNJqCinJybjp5uP5BJgBp6QNcb8Nv30VBM0bn3ajVd76LCq4ZshQAw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-sso@3.899.0': + resolution: {integrity: sha512-URlMbo74CAhIGrhzEP2fw5F5Tt6MRUctA8aa88MomlEHCEbJDsMD3nh6qoXxwR3LyvEBFmCWOZ/1TWmAjMsSdA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.899.0': + resolution: {integrity: sha512-UEn5o5FMcbeFPRRkJI6VCrgdyR9qsLlGA7+AKCYuYADsKbvJGIIQk6A2oD82vIVvLYD3TtbTLDLsF7haF9mpbw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-host-header@3.893.0': + resolution: {integrity: sha512-qL5xYRt80ahDfj9nDYLhpCNkDinEXvjLe/Qen/Y/u12+djrR2MB4DRa6mzBCkLkdXDtf0WAoW2EZsNCfGrmOEQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-logger@3.893.0': + resolution: {integrity: sha512-ZqzMecjju5zkBquSIfVfCORI/3Mge21nUY4nWaGQy+NUXehqCGG4W7AiVpiHGOcY2cGJa7xeEkYcr2E2U9U0AA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.893.0': + resolution: {integrity: sha512-H7Zotd9zUHQAr/wr3bcWHULYhEeoQrF54artgsoUGIf/9emv6LzY89QUccKIxYd6oHKNTrTyXm9F0ZZrzXNxlg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.899.0': + resolution: {integrity: sha512-/3/EIRSwQ5CNOSTHx96gVGzzmTe46OxcPG5FTgM6i9ZD+K/Q3J/UPGFL5DPzct5fXiSLvD1cGQitWHStVDjOVQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-user-agent@3.899.0': + resolution: {integrity: sha512-6EsVCC9j1VIyVyLOg+HyO3z9L+c0PEwMiHe3kuocoMf8nkfjSzJfIl6zAtgAXWgP5MKvusTP2SUbS9ezEEHZ+A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/nested-clients@3.899.0': + resolution: {integrity: sha512-ySXXsFO0RH28VISEqvCuPZ78VAkK45/+OCIJgPvYpcCX9CVs70XSvMPXDI46I49mudJ1s4H3IUKccYSEtA+jaw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/region-config-resolver@3.893.0': + resolution: {integrity: sha512-/cJvh3Zsa+Of0Zbg7vl9wp/kZtdb40yk/2+XcroAMVPO9hPvmS9r/UOm6tO7FeX4TtkRFwWaQJiTZTgSdsPY+Q==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.899.0': + resolution: {integrity: sha512-wV51Jogxhd7dI4Q2Y1ASbkwTsRT3G8uwWFDCwl+WaErOQAzofKlV6nFJQlfgjMk4iEn2gFOIWqJ8fMTGShRK/A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/token-providers@3.899.0': + resolution: {integrity: sha512-Ovu1nWr8HafYa/7DaUvvPnzM/yDUGDBqaiS7rRzv++F5VwyFY37+z/mHhvRnr+PbNWo8uf22a121SNue5uwP2w==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/types@3.893.0': + resolution: {integrity: sha512-Aht1nn5SnA0N+Tjv0dzhAY7CQbxVtmq1bBR6xI0MhG7p2XYVh1wXuKTzrldEvQWwA3odOYunAfT9aBiKZx9qIg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-arn-parser@3.893.0': + resolution: {integrity: sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-endpoints@3.895.0': + resolution: {integrity: sha512-MhxBvWbwxmKknuggO2NeMwOVkHOYL98pZ+1ZRI5YwckoCL3AvISMnPJgfN60ww6AIXHGpkp+HhpFdKOe8RHSEg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-locate-window@3.893.0': + resolution: {integrity: sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-user-agent-browser@3.893.0': + resolution: {integrity: sha512-PE9NtbDBW6Kgl1bG6A5fF3EPo168tnkj8TgMcT0sg4xYBWsBpq0bpJZRh+Jm5Bkwiw9IgTCLjEU7mR6xWaMB9w==} + + '@aws-sdk/util-user-agent-node@3.899.0': + resolution: {integrity: sha512-CiP0UAVQWLg2+8yciUBzVLaK5Fr7jBQ7wVu+p/O2+nlCOD3E3vtL1KZ1qX/d3OVpVSVaMAdZ9nbyewGV9hvjjg==} + engines: {node: '>=18.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/xml-builder@3.894.0': + resolution: {integrity: sha512-E6EAMc9dT1a2DOdo4zyOf3fp5+NJ2wI+mcm7RaW1baFIWDwcb99PpvWoV7YEiK7oaBDshuOEGWKUSYXdW+JYgA==} + engines: {node: '>=18.0.0'} + + '@aws/lambda-invoke-store@0.0.1': + resolution: {integrity: sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==} + engines: {node: '>=18.0.0'} + + '@esbuild/aix-ppc64@0.25.10': + resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.10': + resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.10': + resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.10': + resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.10': + resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.10': + resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.10': + resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.10': + resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.10': + resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.10': + resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.10': + resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.10': + resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.10': + resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.10': + resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.10': + resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.10': + resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.10': + resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.10': + resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.10': + resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.10': + resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.10': + resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.10': + resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.10': + resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.10': + resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.10': + resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.10': + resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@hono/node-server@1.19.3': + resolution: {integrity: sha512-Fjyxfux0rMPXMSob79OmddfpK5ArJa2xLkLCV+zamHkbeXQtSNKOi0keiBKyHZ/hCRKjigjmKGp4AJnDFq8PUw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@smithy/abort-controller@4.1.1': + resolution: {integrity: sha512-vkzula+IwRvPR6oKQhMYioM3A/oX/lFCZiwuxkQbRhqJS2S4YRY2k7k/SyR2jMf3607HLtbEwlRxi0ndXHMjRg==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.2.2': + resolution: {integrity: sha512-IT6MatgBWagLybZl1xQcURXRICvqz1z3APSCAI9IqdvfCkrA7RaQIEfgC6G/KvfxnDfQUDqFV+ZlixcuFznGBQ==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.13.0': + resolution: {integrity: sha512-BI6ALLPOKnPOU1Cjkc+1TPhOlP3JXSR/UH14JmnaLq41t3ma+IjuXrKfhycVjr5IQ0XxRh2NnQo3olp+eCVrGg==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.1.2': + resolution: {integrity: sha512-JlYNq8TShnqCLg0h+afqe2wLAwZpuoSgOyzhYvTgbiKBWRov+uUve+vrZEQO6lkdLOWPh7gK5dtb9dS+KGendg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.2.1': + resolution: {integrity: sha512-5/3wxKNtV3wO/hk1is+CZUhL8a1yy/U+9u9LKQ9kZTkMsHaQjJhc3stFfiujtMnkITjzWfndGA2f7g9Uh9vKng==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.1.1': + resolution: {integrity: sha512-H9DIU9WBLhYrvPs9v4sYvnZ1PiAI0oc8CgNQUJ1rpN3pP7QADbTOUjchI2FB764Ub0DstH5xbTqcMJu1pnVqxA==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.1.1': + resolution: {integrity: sha512-1AqLyFlfrrDkyES8uhINRlJXmHA2FkG+3DY8X+rmLSqmFwk3DJnvhyGzyByPyewh2jbmV+TYQBEfngQax8IFGg==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.1.0': + resolution: {integrity: sha512-ePTYUOV54wMogio+he4pBybe8fwg4sDvEVDBU8ZlHOZXbXK3/C0XfJgUCu6qAZcawv05ZhZzODGUerFBPsPUDQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.1.1': + resolution: {integrity: sha512-9wlfBBgTsRvC2JxLJxv4xDGNBrZuio3AgSl0lSFX7fneW2cGskXTYpFxCdRYD2+5yzmsiTuaAJD1Wp7gWt9y9w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.2.5': + resolution: {integrity: sha512-DdOIpssQ5LFev7hV6GX9TMBW5ChTsQBxqgNW1ZGtJNSAi5ksd5klwPwwMY0ejejfEzwXXGqxgVO3cpaod4veiA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.3.1': + resolution: {integrity: sha512-aH2bD1bzb6FB04XBhXA5mgedEZPKx3tD/qBuYCAKt5iieWvWO1Y2j++J9uLqOndXb9Pf/83Xka/YjSnMbcPchA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.1.1': + resolution: {integrity: sha512-lh48uQdbCoj619kRouev5XbWhCwRKLmphAif16c4J6JgJ4uXjub1PI6RL38d3BLliUvSso6klyB/LTNpWSNIyg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.1.1': + resolution: {integrity: sha512-ygRnniqNcDhHzs6QAPIdia26M7e7z9gpkIMUe/pK0RsrQ7i5MblwxY8078/QCnGq6AmlUUWgljK2HlelsKIb/A==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.2.2': + resolution: {integrity: sha512-SYGTKyPvyCfEzIN5rD8q/bYaOPZprYUPD2f5g9M7OjaYupWOoQFYJ5ho+0wvxIRf471i2SR4GoiZ2r94Jq9h6A==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.2.1': + resolution: {integrity: sha512-REyybygHlxo3TJICPF89N2pMQSf+p+tBJqpVe1+77Cfi9HBPReNjTgtZ1Vg73exq24vkqJskKDpfF74reXjxfw==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.1.1': + resolution: {integrity: sha512-gm3ZS7DHxUbzC2wr8MUCsAabyiXY0gaj3ROWnhSx/9sPMc6eYLMM4rX81w1zsMaObj2Lq3PZtNCC1J6lpEY7zg==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.2.1': + resolution: {integrity: sha512-T8SlkLYCwfT/6m33SIU/JOVGNwoelkrvGjFKDSDtVvAXj/9gOT78JVJEas5a+ETjOu4SVvpCstKgd0PxSu/aHw==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.1.1': + resolution: {integrity: sha512-J9b55bfimP4z/Jg1gNo+AT84hr90p716/nvxDkPGCD4W70MPms0h8KF50RDRgBGZeL83/u59DWNqJv6tEP/DHA==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.1.1': + resolution: {integrity: sha512-63TEp92YFz0oQ7Pj9IuI3IgnprP92LrZtRAkE3c6wLWJxfy/yOPRt39IOKerVr0JS770olzl0kGafXlAXZ1vng==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.1.2': + resolution: {integrity: sha512-Kqd8wyfmBWHZNppZSMfrQFpc3M9Y/kjyN8n8P4DqJJtuwgK1H914R471HTw7+RL+T7+kI1f1gOnL7Vb5z9+NgQ==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.2.0': + resolution: {integrity: sha512-OQTfmIEp2LLuWdxa8nEEPhZmiOREO6bcB6pjs0AySf4yiZhl6kMOfqmcwcY8BaBPX+0Tb+tG7/Ia/6mwpoZ7Pw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.2.1': + resolution: {integrity: sha512-M9rZhWQLjlQVCCR37cSjHfhriGRN+FQ8UfgrYNufv66TJgk+acaggShl3KS5U/ssxivvZLlnj7QH2CUOKlxPyA==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.6.5': + resolution: {integrity: sha512-6J2hhuWu7EjnvLBIGltPCqzNswL1cW/AkaZx6i56qLsQ0ix17IAhmDD9aMmL+6CN9nCJODOXpBTCQS6iKAA7/g==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.5.0': + resolution: {integrity: sha512-RkUpIOsVlAwUIZXO1dsz8Zm+N72LClFfsNqf173catVlvRZiwPy0x2u0JLEA4byreOPKDZPGjmPDylMoP8ZJRg==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.1.1': + resolution: {integrity: sha512-bx32FUpkhcaKlEoOMbScvc93isaSiRM75pQ5IgIBaMkT7qMlIibpPRONyx/0CvrXHzJLpOn/u6YiDX2hcvs7Dg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.1.0': + resolution: {integrity: sha512-RUGd4wNb8GeW7xk+AY5ghGnIwM96V0l2uzvs/uVHf+tIuVX2WSvynk5CxNoBCsM2rQRSZElAo9rt3G5mJ/gktQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.1.0': + resolution: {integrity: sha512-V2E2Iez+bo6bUMOTENPr6eEmepdY8Hbs+Uc1vkDKgKNA/brTJqOW/ai3JO1BGj9GbCeLqw90pbbH7HFQyFotGQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.1.0': + resolution: {integrity: sha512-BOI5dYjheZdgR9XiEM3HJcEMCXSoqbzu7CzIgYrx0UtmvtC3tC2iDGpJLsSRFffUpy8ymsg2ARMP5fR8mtuUQQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.1.0': + resolution: {integrity: sha512-N6yXcjfe/E+xKEccWEKzK6M+crMrlwaCepKja0pNnlSkm6SjAeLKKA++er5Ba0I17gvKfN/ThV+ZOx/CntKTVw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.1.0': + resolution: {integrity: sha512-swXz2vMjrP1ZusZWVTB/ai5gK+J8U0BWvP10v9fpcFvg+Xi/87LHvHfst2IgCs1i0v4qFZfGwCmeD/KNCdJZbQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.1.5': + resolution: {integrity: sha512-FGBhlmFZVSRto816l6IwrmDcQ9pUYX6ikdR1mmAhdtSS1m77FgADukbQg7F7gurXfAvloxE/pgsrb7SGja6FQA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.1.5': + resolution: {integrity: sha512-Gwj8KLgJ/+MHYjVubJF0EELEh9/Ir7z7DFqyYlwgmp4J37KE+5vz6b3pWUnSt53tIe5FjDfVjDmHGYKjwIvW0Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.1.2': + resolution: {integrity: sha512-+AJsaaEGb5ySvf1SKMRrPZdYHRYSzMkCoK16jWnIMpREAnflVspMIDeCVSZJuj+5muZfgGpNpijE3mUNtjv01Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.1.0': + resolution: {integrity: sha512-1LcueNN5GYC4tr8mo14yVYbh/Ur8jHhWOxniZXii+1+ePiIbsLZ5fEI0QQGtbRRP5mOhmooos+rLmVASGGoq5w==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.1.1': + resolution: {integrity: sha512-CGmZ72mL29VMfESz7S6dekqzCh8ZISj3B+w0g1hZFXaOjGTVaSqfAEFAq8EGp8fUL+Q2l8aqNmt8U1tglTikeg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.1.2': + resolution: {integrity: sha512-NCgr1d0/EdeP6U5PSZ9Uv5SMR5XRRYoVr1kRVtKZxWL3tixEL3UatrPIMFZSKwHlCcp2zPLDvMubVDULRqeunA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.3.2': + resolution: {integrity: sha512-Ka+FA2UCC/Q1dEqUanCdpqwxOFdf5Dg2VXtPtB1qxLcSGh5C1HdzklIt18xL504Wiy9nNUKwDMRTVCbKGoK69g==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.1.0': + resolution: {integrity: sha512-b0EFQkq35K5NHUYxU72JuoheM6+pytEVUGlTwiFxWFpmddA+Bpz3LgsPRIpBk8lnPE47yT7AF2Egc3jVnKLuPg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.1.0': + resolution: {integrity: sha512-mEu1/UIXAdNYuBcyEPbjScKi/+MQVXNIuY/7Cm5XLIWe319kDrT5SizBE95jqtmEXoDbGoZxKLCMttdZdqTZKQ==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.0.0': + resolution: {integrity: sha512-OlA/yZHh0ekYFnbUkmYBDQPE6fGfdrvgz39ktp8Xf+FA6BfxLejPTMDOG0Nfk5/rDySAz1dRbFf24zaAFYVXlQ==} + engines: {node: '>=18.0.0'} + + '@tailwindcss/cli@4.1.13': + resolution: {integrity: sha512-KEu/iL4CYBzGza/2yZBLXqjCCZB/eRWkRLP8Vg2kkEWk4usC8HLGJW0QAhLS7U5DsAWumsisxgabuppE6NinLw==} + hasBin: true + + '@tailwindcss/node@4.1.13': + resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} + + '@tailwindcss/oxide-android-arm64@4.1.13': + resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.13': + resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.13': + resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.13': + resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.13': + resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==} + engines: {node: '>= 10'} + + '@types/bcrypt@6.0.0': + resolution: {integrity: sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==} + + '@types/node@20.19.17': + resolution: {integrity: sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==} + + '@types/nodemailer@7.0.2': + resolution: {integrity: sha512-Zo6uOA9157WRgBk/ZhMpTQ/iCWLMk7OIs/Q9jvHarMvrzUUP/MDdPHL2U1zpf57HrrWGv4nYQn5uIxna0xY3xw==} + + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + + bcrypt@6.0.0: + resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==} + engines: {node: '>= 18'} + + bowser@2.12.1: + resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + daisyui@5.1.25: + resolution: {integrity: sha512-LYOGVIzTCCucEFkKmdj0fxbHHPZ83fpkYD7jXYF3/7UwrUu68TtXkIdGtEXadzeqUT361hCe6cj5tBB/7mvszw==} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + detect-europe-js@0.1.2: + resolution: {integrity: sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + detect-libc@2.1.1: + resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.10: + resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} + engines: {node: '>=18'} + hasBin: true + + fast-xml-parser@5.2.5: + resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} + hasBin: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + fs@0.0.1-security: + resolution: {integrity: sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.10.1: + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hono@4.9.8: + resolution: {integrity: sha512-JW8Bb4RFWD9iOKxg5PbUarBYGM99IcxFl2FPBo2gSJO11jjUDqlP1Bmfyqt8Z/dGhIQ63PMA9LdcLefXyIasyg==} + engines: {node: '>=16.9.0'} + + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + + is-standalone-pwa@0.1.1: + resolution: {integrity: sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==} + + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lru.min@1.1.2: + resolution: {integrity: sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mysql2@3.15.0: + resolution: {integrity: sha512-tT6pomf5Z/I7Jzxu8sScgrYBMK9bUFWd7Kbo6Fs1L0M13OOIJ/ZobGKS3Z7tQ8Re4lj+LnLXIQVZZxa3fhYKzA==} + engines: {node: '>= 8.0'} + + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-addon-api@8.5.0: + resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} + engines: {node: ^18 || ^20 || >= 21} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + nodemailer@7.0.6: + resolution: {integrity: sha512-F44uVzgwo49xboqbFgBGkRaiMgtoBrBEWCVincJPK9+S9Adkzt/wXCLKbf7dxucmxfTI5gHGB+bEmdyzN6QKjw==} + engines: {node: '>=6.0.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + + strnum@2.1.1: + resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + + tailwindcss@4.1.13: + resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} + + tapable@2.2.3: + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + engines: {node: '>=6'} + + tar@7.5.1: + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + engines: {node: '>=18'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.5: + resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==} + engines: {node: '>=18.0.0'} + hasBin: true + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + ua-is-frozen@0.1.2: + resolution: {integrity: sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==} + + ua-parser-js@2.0.5: + resolution: {integrity: sha512-sZErtx3rhpvZQanWW5umau4o/snfoLqRcQwQIZ54377WtRzIecnIKvjpkd5JwPcSUMglGnbIgcsQBGAbdi3S9Q==} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici@7.16.0: + resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + engines: {node: '>=20.18.1'} + + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + hasBin: true + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + +snapshots: + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.893.0 + '@aws-sdk/util-locate-window': 3.893.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.893.0 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-sesv2@3.899.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.899.0 + '@aws-sdk/credential-provider-node': 3.899.0 + '@aws-sdk/middleware-host-header': 3.893.0 + '@aws-sdk/middleware-logger': 3.893.0 + '@aws-sdk/middleware-recursion-detection': 3.893.0 + '@aws-sdk/middleware-user-agent': 3.899.0 + '@aws-sdk/region-config-resolver': 3.893.0 + '@aws-sdk/signature-v4-multi-region': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@aws-sdk/util-endpoints': 3.895.0 + '@aws-sdk/util-user-agent-browser': 3.893.0 + '@aws-sdk/util-user-agent-node': 3.899.0 + '@smithy/config-resolver': 4.2.2 + '@smithy/core': 3.13.0 + '@smithy/fetch-http-handler': 5.2.1 + '@smithy/hash-node': 4.1.1 + '@smithy/invalid-dependency': 4.1.1 + '@smithy/middleware-content-length': 4.1.1 + '@smithy/middleware-endpoint': 4.2.5 + '@smithy/middleware-retry': 4.3.1 + '@smithy/middleware-serde': 4.1.1 + '@smithy/middleware-stack': 4.1.1 + '@smithy/node-config-provider': 4.2.2 + '@smithy/node-http-handler': 4.2.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/url-parser': 4.1.1 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-body-length-node': 4.1.0 + '@smithy/util-defaults-mode-browser': 4.1.5 + '@smithy/util-defaults-mode-node': 4.1.5 + '@smithy/util-endpoints': 3.1.2 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-retry': 4.1.2 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.899.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.899.0 + '@aws-sdk/middleware-host-header': 3.893.0 + '@aws-sdk/middleware-logger': 3.893.0 + '@aws-sdk/middleware-recursion-detection': 3.893.0 + '@aws-sdk/middleware-user-agent': 3.899.0 + '@aws-sdk/region-config-resolver': 3.893.0 + '@aws-sdk/types': 3.893.0 + '@aws-sdk/util-endpoints': 3.895.0 + '@aws-sdk/util-user-agent-browser': 3.893.0 + '@aws-sdk/util-user-agent-node': 3.899.0 + '@smithy/config-resolver': 4.2.2 + '@smithy/core': 3.13.0 + '@smithy/fetch-http-handler': 5.2.1 + '@smithy/hash-node': 4.1.1 + '@smithy/invalid-dependency': 4.1.1 + '@smithy/middleware-content-length': 4.1.1 + '@smithy/middleware-endpoint': 4.2.5 + '@smithy/middleware-retry': 4.3.1 + '@smithy/middleware-serde': 4.1.1 + '@smithy/middleware-stack': 4.1.1 + '@smithy/node-config-provider': 4.2.2 + '@smithy/node-http-handler': 4.2.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/url-parser': 4.1.1 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-body-length-node': 4.1.0 + '@smithy/util-defaults-mode-browser': 4.1.5 + '@smithy/util-defaults-mode-node': 4.1.5 + '@smithy/util-endpoints': 3.1.2 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-retry': 4.1.2 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.899.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@aws-sdk/xml-builder': 3.894.0 + '@smithy/core': 3.13.0 + '@smithy/node-config-provider': 4.2.2 + '@smithy/property-provider': 4.1.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/signature-v4': 5.2.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/property-provider': 4.1.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/fetch-http-handler': 5.2.1 + '@smithy/node-http-handler': 4.2.1 + '@smithy/property-provider': 4.1.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/util-stream': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/credential-provider-env': 3.899.0 + '@aws-sdk/credential-provider-http': 3.899.0 + '@aws-sdk/credential-provider-process': 3.899.0 + '@aws-sdk/credential-provider-sso': 3.899.0 + '@aws-sdk/credential-provider-web-identity': 3.899.0 + '@aws-sdk/nested-clients': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/credential-provider-imds': 4.1.2 + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.899.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.899.0 + '@aws-sdk/credential-provider-http': 3.899.0 + '@aws-sdk/credential-provider-ini': 3.899.0 + '@aws-sdk/credential-provider-process': 3.899.0 + '@aws-sdk/credential-provider-sso': 3.899.0 + '@aws-sdk/credential-provider-web-identity': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/credential-provider-imds': 4.1.2 + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.899.0': + dependencies: + '@aws-sdk/client-sso': 3.899.0 + '@aws-sdk/core': 3.899.0 + '@aws-sdk/token-providers': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/nested-clients': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-host-header@3.893.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.893.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.893.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@aws/lambda-invoke-store': 0.0.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-s3@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@aws-sdk/util-arn-parser': 3.893.0 + '@smithy/core': 3.13.0 + '@smithy/node-config-provider': 4.2.2 + '@smithy/protocol-http': 5.2.1 + '@smithy/signature-v4': 5.2.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/util-config-provider': 4.1.0 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-stream': 4.3.2 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@aws-sdk/util-endpoints': 3.895.0 + '@smithy/core': 3.13.0 + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.899.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.899.0 + '@aws-sdk/middleware-host-header': 3.893.0 + '@aws-sdk/middleware-logger': 3.893.0 + '@aws-sdk/middleware-recursion-detection': 3.893.0 + '@aws-sdk/middleware-user-agent': 3.899.0 + '@aws-sdk/region-config-resolver': 3.893.0 + '@aws-sdk/types': 3.893.0 + '@aws-sdk/util-endpoints': 3.895.0 + '@aws-sdk/util-user-agent-browser': 3.893.0 + '@aws-sdk/util-user-agent-node': 3.899.0 + '@smithy/config-resolver': 4.2.2 + '@smithy/core': 3.13.0 + '@smithy/fetch-http-handler': 5.2.1 + '@smithy/hash-node': 4.1.1 + '@smithy/invalid-dependency': 4.1.1 + '@smithy/middleware-content-length': 4.1.1 + '@smithy/middleware-endpoint': 4.2.5 + '@smithy/middleware-retry': 4.3.1 + '@smithy/middleware-serde': 4.1.1 + '@smithy/middleware-stack': 4.1.1 + '@smithy/node-config-provider': 4.2.2 + '@smithy/node-http-handler': 4.2.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/url-parser': 4.1.1 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-body-length-node': 4.1.0 + '@smithy/util-defaults-mode-browser': 4.1.5 + '@smithy/util-defaults-mode-node': 4.1.5 + '@smithy/util-endpoints': 3.1.2 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-retry': 4.1.2 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.893.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@smithy/node-config-provider': 4.2.2 + '@smithy/types': 4.5.0 + '@smithy/util-config-provider': 4.1.0 + '@smithy/util-middleware': 4.1.1 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.899.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/protocol-http': 5.2.1 + '@smithy/signature-v4': 5.2.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.899.0': + dependencies: + '@aws-sdk/core': 3.899.0 + '@aws-sdk/nested-clients': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.893.0': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/util-arn-parser@3.893.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.895.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@smithy/types': 4.5.0 + '@smithy/url-parser': 4.1.1 + '@smithy/util-endpoints': 3.1.2 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.893.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.893.0': + dependencies: + '@aws-sdk/types': 3.893.0 + '@smithy/types': 4.5.0 + bowser: 2.12.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.899.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.899.0 + '@aws-sdk/types': 3.893.0 + '@smithy/node-config-provider': 4.2.2 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.894.0': + dependencies: + '@smithy/types': 4.5.0 + fast-xml-parser: 5.2.5 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.0.1': {} + + '@esbuild/aix-ppc64@0.25.10': + optional: true + + '@esbuild/android-arm64@0.25.10': + optional: true + + '@esbuild/android-arm@0.25.10': + optional: true + + '@esbuild/android-x64@0.25.10': + optional: true + + '@esbuild/darwin-arm64@0.25.10': + optional: true + + '@esbuild/darwin-x64@0.25.10': + optional: true + + '@esbuild/freebsd-arm64@0.25.10': + optional: true + + '@esbuild/freebsd-x64@0.25.10': + optional: true + + '@esbuild/linux-arm64@0.25.10': + optional: true + + '@esbuild/linux-arm@0.25.10': + optional: true + + '@esbuild/linux-ia32@0.25.10': + optional: true + + '@esbuild/linux-loong64@0.25.10': + optional: true + + '@esbuild/linux-mips64el@0.25.10': + optional: true + + '@esbuild/linux-ppc64@0.25.10': + optional: true + + '@esbuild/linux-riscv64@0.25.10': + optional: true + + '@esbuild/linux-s390x@0.25.10': + optional: true + + '@esbuild/linux-x64@0.25.10': + optional: true + + '@esbuild/netbsd-arm64@0.25.10': + optional: true + + '@esbuild/netbsd-x64@0.25.10': + optional: true + + '@esbuild/openbsd-arm64@0.25.10': + optional: true + + '@esbuild/openbsd-x64@0.25.10': + optional: true + + '@esbuild/openharmony-arm64@0.25.10': + optional: true + + '@esbuild/sunos-x64@0.25.10': + optional: true + + '@esbuild/win32-arm64@0.25.10': + optional: true + + '@esbuild/win32-ia32@0.25.10': + optional: true + + '@esbuild/win32-x64@0.25.10': + optional: true + + '@hono/node-server@1.19.3(hono@4.9.8)': + dependencies: + hono: 4.9.8 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + + '@smithy/abort-controller@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/config-resolver@4.2.2': + dependencies: + '@smithy/node-config-provider': 4.2.2 + '@smithy/types': 4.5.0 + '@smithy/util-config-provider': 4.1.0 + '@smithy/util-middleware': 4.1.1 + tslib: 2.8.1 + + '@smithy/core@3.13.0': + dependencies: + '@smithy/middleware-serde': 4.1.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-stream': 4.3.2 + '@smithy/util-utf8': 4.1.0 + '@smithy/uuid': 1.0.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.1.2': + dependencies: + '@smithy/node-config-provider': 4.2.2 + '@smithy/property-provider': 4.1.1 + '@smithy/types': 4.5.0 + '@smithy/url-parser': 4.1.1 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.2.1': + dependencies: + '@smithy/protocol-http': 5.2.1 + '@smithy/querystring-builder': 4.1.1 + '@smithy/types': 4.5.0 + '@smithy/util-base64': 4.1.0 + tslib: 2.8.1 + + '@smithy/hash-node@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + '@smithy/util-buffer-from': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.1.1': + dependencies: + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.2.5': + dependencies: + '@smithy/core': 3.13.0 + '@smithy/middleware-serde': 4.1.1 + '@smithy/node-config-provider': 4.2.2 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + '@smithy/url-parser': 4.1.1 + '@smithy/util-middleware': 4.1.1 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.3.1': + dependencies: + '@smithy/node-config-provider': 4.2.2 + '@smithy/protocol-http': 5.2.1 + '@smithy/service-error-classification': 4.1.2 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-retry': 4.1.2 + '@smithy/uuid': 1.0.0 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.1.1': + dependencies: + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.2.2': + dependencies: + '@smithy/property-provider': 4.1.1 + '@smithy/shared-ini-file-loader': 4.2.0 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.2.1': + dependencies: + '@smithy/abort-controller': 4.1.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/querystring-builder': 4.1.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.2.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + '@smithy/util-uri-escape': 4.1.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.1.2': + dependencies: + '@smithy/types': 4.5.0 + + '@smithy/shared-ini-file-loader@4.2.0': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.2.1': + dependencies: + '@smithy/is-array-buffer': 4.1.0 + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + '@smithy/util-hex-encoding': 4.1.0 + '@smithy/util-middleware': 4.1.1 + '@smithy/util-uri-escape': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/smithy-client@4.6.5': + dependencies: + '@smithy/core': 3.13.0 + '@smithy/middleware-endpoint': 4.2.5 + '@smithy/middleware-stack': 4.1.1 + '@smithy/protocol-http': 5.2.1 + '@smithy/types': 4.5.0 + '@smithy/util-stream': 4.3.2 + tslib: 2.8.1 + + '@smithy/types@4.5.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.1.1': + dependencies: + '@smithy/querystring-parser': 4.1.1 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.1.0': + dependencies: + '@smithy/util-buffer-from': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.1.0': + dependencies: + '@smithy/is-array-buffer': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.1.5': + dependencies: + '@smithy/property-provider': 4.1.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + bowser: 2.12.1 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.1.5': + dependencies: + '@smithy/config-resolver': 4.2.2 + '@smithy/credential-provider-imds': 4.1.2 + '@smithy/node-config-provider': 4.2.2 + '@smithy/property-provider': 4.1.1 + '@smithy/smithy-client': 4.6.5 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.1.2': + dependencies: + '@smithy/node-config-provider': 4.2.2 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.1.1': + dependencies: + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.1.2': + dependencies: + '@smithy/service-error-classification': 4.1.2 + '@smithy/types': 4.5.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.3.2': + dependencies: + '@smithy/fetch-http-handler': 5.2.1 + '@smithy/node-http-handler': 4.2.1 + '@smithy/types': 4.5.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-buffer-from': 4.1.0 + '@smithy/util-hex-encoding': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.1.0': + dependencies: + '@smithy/util-buffer-from': 4.1.0 + tslib: 2.8.1 + + '@smithy/uuid@1.0.0': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/cli@4.1.13': + dependencies: + '@parcel/watcher': 2.5.1 + '@tailwindcss/node': 4.1.13 + '@tailwindcss/oxide': 4.1.13 + enhanced-resolve: 5.18.3 + mri: 1.2.0 + picocolors: 1.1.1 + tailwindcss: 4.1.13 + + '@tailwindcss/node@4.1.13': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + magic-string: 0.30.19 + source-map-js: 1.2.1 + tailwindcss: 4.1.13 + + '@tailwindcss/oxide-android-arm64@4.1.13': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.13': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.13': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + optional: true + + '@tailwindcss/oxide@4.1.13': + dependencies: + detect-libc: 2.1.1 + tar: 7.5.1 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-x64': 4.1.13 + '@tailwindcss/oxide-freebsd-x64': 4.1.13 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.13 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-x64-musl': 4.1.13 + '@tailwindcss/oxide-wasm32-wasi': 4.1.13 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 + + '@types/bcrypt@6.0.0': + dependencies: + '@types/node': 20.19.17 + + '@types/node@20.19.17': + dependencies: + undici-types: 6.21.0 + + '@types/nodemailer@7.0.2': + dependencies: + '@aws-sdk/client-sesv2': 3.899.0 + '@types/node': 20.19.17 + transitivePeerDependencies: + - aws-crt + + aws-ssl-profiles@1.1.2: {} + + bcrypt@6.0.0: + dependencies: + node-addon-api: 8.5.0 + node-gyp-build: 4.8.4 + + bowser@2.12.1: {} + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chownr@3.0.0: {} + + daisyui@5.1.25: {} + + denque@2.1.0: {} + + detect-europe-js@0.1.2: {} + + detect-libc@1.0.3: {} + + detect-libc@2.1.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.3 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + esbuild@0.25.10: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 + + fast-xml-parser@5.2.5: + dependencies: + strnum: 2.1.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + fs@0.0.1-security: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.10.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + globals@16.4.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hono@4.9.8: {} + + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.3: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-property@1.0.2: {} + + is-standalone-pwa@0.1.1: {} + + jiti@2.5.1: {} + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.1.1 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + long@5.3.2: {} + + lru-cache@7.18.3: {} + + lru.min@1.1.2: {} + + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minipass@7.1.2: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.2 + + mri@1.2.0: {} + + mysql2@3.15.0: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.0 + long: 5.3.2 + lru.min: 1.1.2 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + + node-addon-api@7.1.1: {} + + node-addon-api@8.5.0: {} + + node-gyp-build@4.8.4: {} + + nodemailer@7.0.6: {} + + object-inspect@1.13.4: {} + + path@0.12.7: + dependencies: + process: 0.11.10 + util: 0.10.4 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + process@0.11.10: {} + + punycode@1.4.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + resolve-pkg-maps@1.0.0: {} + + safer-buffer@2.1.2: {} + + seq-queue@0.0.5: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + source-map-js@1.2.1: {} + + sqlstring@2.3.3: {} + + strnum@2.1.1: {} + + tailwindcss@4.1.13: {} + + tapable@2.2.3: {} + + tar@7.5.1: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tslib@2.8.1: {} + + tsx@4.20.5: + dependencies: + esbuild: 0.25.10 + get-tsconfig: 4.10.1 + optionalDependencies: + fsevents: 2.3.3 + + typescript@5.9.2: {} + + ua-is-frozen@0.1.2: {} + + ua-parser-js@2.0.5: + dependencies: + detect-europe-js: 0.1.2 + is-standalone-pwa: 0.1.1 + ua-is-frozen: 0.1.2 + undici: 7.16.0 + + undici-types@6.21.0: {} + + undici@7.16.0: {} + + url@0.11.4: + dependencies: + punycode: 1.4.1 + qs: 6.14.0 + + util@0.10.4: + dependencies: + inherits: 2.0.3 + + uuid@13.0.0: {} + + yallist@5.0.0: {} diff --git a/packages/web/pnpm-workspace.yaml b/packages/web/pnpm-workspace.yaml new file mode 100644 index 0000000..0bad36e --- /dev/null +++ b/packages/web/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +onlyBuiltDependencies: + - '@parcel/watcher' + - '@tailwindcss/oxide' + - bcrypt + - esbuild diff --git a/packages/web/public/.gitignore b/packages/web/public/.gitignore new file mode 100644 index 0000000..a4d59cf --- /dev/null +++ b/packages/web/public/.gitignore @@ -0,0 +1 @@ +tailwind.css diff --git a/packages/web/public/js/mailverify.js b/packages/web/public/js/mailverify.js new file mode 100644 index 0000000..e25af4f --- /dev/null +++ b/packages/web/public/js/mailverify.js @@ -0,0 +1,45 @@ +const form = document.querySelector("form"); +form.addEventListener("submit", async (e) => { + e.preventDefault(); + + document.getElementsByName("code")[0].disable = ""; + document.getElementsByName("submit")[0].disable = ""; + + let error = ""; + + const infoReq = await fetch("/api/info", { + method: "POST", + cache: "no-store", + }); + if (!infoReq.ok) { + error = "通信エラーが発生しました"; + } + const infoRes = await infoReq.json(); + + const code = document.getElementsByName("code")[0].value; + let turnstile; + if (infoRes.botprotection.turnstile === true) { + turnstile = document.getElementsByName("cf-turnstile-response")[0].value; + } + + const req = await fetch("/api/mailverify", { + method: "POST", + cache: "no-store", + headers: { + 'Content-Type': "application/json", + }, + body: JSON.stringify({ + code: code, + turnstile: turnstile ?? undefined, + }), + }); + if (!req.ok) { + error = "通信エラーが発生しました"; + } + const res = await req.json(); + if (res.success === true) { + location.href = "/signin"; + } else { + location.replace(`/mailverify?error=${res.error}&code=${document.getElementsByName("code")[0].value}`); + } +}) diff --git a/packages/web/public/js/signin.js b/packages/web/public/js/signin.js new file mode 100644 index 0000000..4016384 --- /dev/null +++ b/packages/web/public/js/signin.js @@ -0,0 +1,48 @@ +const form = document.querySelector("form"); +form.addEventListener("submit", async (e) => { + e.preventDefault(); + + document.getElementsByName("username")[0].disable = ""; + document.getElementsByName("password")[0].disable = ""; + document.getElementsByName("submit")[0].disable = ""; + + let error = ""; + + const infoReq = await fetch("/api/info", { + method: "POST", + cache: "no-store", + }); + if (!infoReq.ok) { + error = "通信エラーが発生しました"; + } + const infoRes = await infoReq.json(); + + const username = document.getElementsByName("username")[0].value; + const password = document.getElementsByName("password")[0].value; + let turnstile; + if (infoRes.botprotection.turnstile === true) { + turnstile = document.getElementsByName("cf-turnstile-response")[0].value; + } + + const req = await fetch("/api/signin", { + method: "POST", + cache: "no-store", + headers: { + 'Content-Type': "application/json", + }, + body: JSON.stringify({ + username: username, + password: password, + turnstile: turnstile ?? undefined, + }), + }); + if (!req.ok) { + error = "通信エラーが発生しました"; + } + const res = await req.json(); + if (res.success === true) { + location.href = "/home"; + } else { + location.replace(`/signin?error=${res.error}`); + } +}); diff --git a/packages/web/public/js/signup.js b/packages/web/public/js/signup.js new file mode 100644 index 0000000..9ad6a86 --- /dev/null +++ b/packages/web/public/js/signup.js @@ -0,0 +1,52 @@ +const form = document.querySelector("form"); +form.addEventListener("submit", async (e) => { + e.preventDefault(); + + document.getElementsByName("username")[0].disable = ""; + document.getElementsByName("email")[0].disable = ""; + document.getElementsByName("password")[0].disable = ""; + document.getElementsByName("agreeRule")[0].disable = ""; + document.getElementsByName("submit")[0].disable = ""; + + let error = ""; + + const infoReq = await fetch("/api/info", { + method: "POST", + cache: "no-store", + }); + if (!infoReq.ok) { + error = "通信エラーが発生しました"; + } + const infoRes = await infoReq.json(); + + const username = document.getElementsByName("username")[0].value; + const email = document.getElementsByName("email")[0].value; + const password = document.getElementsByName("password")[0].value; + let turnstile; + if (infoRes.botprotection.turnstile === true) { + turnstile = document.getElementsByName("cf-turnstile-response")[0].value; + } + + const req = await fetch("/api/signup", { + method: "POST", + cache: "no-store", + headers: { + 'Content-Type': "application/json", + }, + body: JSON.stringify({ + username: username, + email: email, + password: password, + turnstile: turnstile ?? undefined, + }), + }); + if (!req.ok) { + error = "通信エラーが発生しました"; + } + const res = await req.json(); + if (res.success === true) { + location.href = "/signin"; + } else { + location.replace(`/signup?error=${res.error}`) + } +}); diff --git a/packages/web/src/components/help.tsx b/packages/web/src/components/help.tsx new file mode 100644 index 0000000..56cac89 --- /dev/null +++ b/packages/web/src/components/help.tsx @@ -0,0 +1,56 @@ +import { Locale } from "../lib/locale.js"; +import Icon from "./iconify.js"; + +const Help = (props: { + text: string; + lang: string; +}) => { + return ( +
+
+ +
+
+
+

+ {Locale({ text: "help" }, props.lang)} +

+

+ {props.text} +

+
+
+
+ ); +}; + +export default Help; diff --git a/packages/web/src/components/iconify.tsx b/packages/web/src/components/iconify.tsx new file mode 100644 index 0000000..87f88bf --- /dev/null +++ b/packages/web/src/components/iconify.tsx @@ -0,0 +1,26 @@ +import type { JSX, DOMAttributes } from "hono/jsx"; + +const Icon = async (props: { + icon: string; + color?: string; +} & DOMAttributes) => { + const { icon, color, ...rest } = props; + const iconColor = color === undefined ? "" : `?color=${color}`; + const url = `https://api.iconify.design/${icon}.svg${iconColor}`; + + const req = await fetch(url, { + method: "GET" + }); + if (!req.ok) { + return (<>); + } + const res = await req.text(); + + return ( + + ); +}; + +export default Icon; diff --git a/packages/web/src/components/turnstile.tsx b/packages/web/src/components/turnstile.tsx new file mode 100644 index 0000000..5fb9c47 --- /dev/null +++ b/packages/web/src/components/turnstile.tsx @@ -0,0 +1,37 @@ +import { html } from "hono/html"; +import type { HtmlEscapedString } from "hono/utils/html"; + +const Turnstile = (props: { + sitekey: string; + button: HtmlEscapedString | Promise; +}) => { + return ( +
+ {html``} + +
+ + {html``} + +
+ ); +}; + +export default Turnstile; diff --git a/packages/web/src/lib/database.ts b/packages/web/src/lib/database.ts new file mode 100644 index 0000000..31d7988 --- /dev/null +++ b/packages/web/src/lib/database.ts @@ -0,0 +1,46 @@ +import mysql from "mysql2/promise"; +import Config from "../../config/peas.config.js"; + +const option = (connectionLimit: number = 10) => { + return { + host: Config.database.host, + port: Config.database.port, + user: Config.database.user, + password: Config.database.pass, + database: Config.database.db, + waitForConnections: true, + connectionLimit: connectionLimit, + multipleStatements: true, + } +}; + +const verify = async (option: { + host: string; + port: number; + user: string; + password: string; + database: string; + waitForConnections: boolean; + connectionLimit?: number; +}) => { + option.connectionLimit = option.connectionLimit ?? 10; + let connection; + + try { + connection = await mysql.createConnection(option); + } catch (err) { + console.error("Error: Could not connect to MariaDB"); + console.error(err); + process.exit(); + } finally { + if (connection) { + await connection.end(); + } + } +}; + +export { verify, option }; + +const pool = mysql.createPool(option()); + +export default pool; diff --git a/packages/web/src/lib/locale.ts b/packages/web/src/lib/locale.ts new file mode 100644 index 0000000..bc56269 --- /dev/null +++ b/packages/web/src/lib/locale.ts @@ -0,0 +1,52 @@ +import * as fs from "fs"; +import { parse as yamlParse } from "yaml"; + +export const supportedLanguages = [ + "en", + "ja", +]; + +import { getDirname } from "./path.js"; +const dirname = getDirname(import.meta.url); + +export function Check() { + let error = false; + for (let i = 0; i < supportedLanguages.length; i++) { + if (!fs.existsSync(`${dirname}../../../../locales/${supportedLanguages[i]}.yaml`)) { + error = true; + console.error(`Error: ${supportedLanguages[i]} language pack not found`); + } + } + return error; +} + +export function Locale({ + text, data = [], + variables = {} +}: { + text: string; + data?: string[]; +} & { + variables?: Record; +}, lang: string) { + if (supportedLanguages.indexOf(lang) === -1) { + return "__ERROR:LANG_NOT_SUPPORT"; + } + + const yaml = fs.readFileSync(`${dirname}../../../../locales/${lang}.yaml`, "utf-8"); + const localeData = yamlParse(yaml); + + let message = localeData[text]; + + data.forEach((value, index) => { + message = message.replace(new RegExp('\\{' + index + '\\}', 'g'), value); + }); + + if (variables) { + Object.keys(variables).forEach(key => { + message = message.replace(new RegExp('\\{' + key + '\\}', 'g'), variables[key]); + }); + } + + return message; +} diff --git a/packages/web/src/lib/mailer.ts b/packages/web/src/lib/mailer.ts new file mode 100644 index 0000000..1475445 --- /dev/null +++ b/packages/web/src/lib/mailer.ts @@ -0,0 +1,67 @@ +import * as nodemailer from "nodemailer"; +import type SMTPTransport from "nodemailer/lib/smtp-transport"; +import pool from "./database.js"; +import type { RowDataPacket } from "mysql2"; + +export interface EmailMessage { + to: string | string[]; + subject: string; + text?: string; + html?: string; +} + +export async function createTransporter() { + const [host] = await pool.execute( + "SELECT value FROM config WHERE name = 'smtp_host'" + ); + const [port] = await pool.execute( + "SELECT value FROM config WHERE name = 'smtp_port'" + ); + const [secure] = await pool.execute( + "SELECT value FROM config WHERE name = 'smtp_secure'" + ); + const [user] = await pool.execute( + "SELECT value FROM config WHERE name = 'smtp_user'" + ); + const [password] = await pool.execute( + "SELECT value FROM config WHERE name = 'smtp_password'" + ); + + const transporter = nodemailer.createTransport({ + host: host[0].value, + port: Number(port[0].value), + secure: secure[0].value === "1" ? true : false, + auth: { + user: user[0].value, + pass: password[0].value, + }, + debug: process.argv.includes("-tsx-develop"), + } as SMTPTransport.Options); + + try { + await transporter.verify(); + } catch (error) { + throw error; + } + + return transporter; +} + +export async function sendMail(message: EmailMessage): Promise { + const [user] = await pool.execute( + "SELECT value FROM config WHERE name = 'smtp_user'" + ); + + try { + const transporter = await createTransporter(); + await transporter.sendMail({ + from: user[0].value, + to: Array.isArray(message.to) ? message.to.join(",") : message.to, + subject: message.subject, + text: message.text, + html: message.html, + }); + } catch (error) { + throw error; + } +} diff --git a/packages/web/src/lib/mailverify.ts b/packages/web/src/lib/mailverify.ts new file mode 100644 index 0000000..f8c8e1c --- /dev/null +++ b/packages/web/src/lib/mailverify.ts @@ -0,0 +1,76 @@ +import pool from "./database.js"; +import type { RowDataPacket } from "mysql2"; +import { sendMail } from "./mailer.js"; +import Config from "../../config/peas.config.js"; +import type InfoAPI from "../../types/api/info.js"; +import { Locale } from "./locale.js"; + +async function createCode(maxAttempts = 10) { + for (let i = 0; i < maxAttempts; i++) { + const code = Math.floor(100000 + Math.random() * 900000).toString(); + const [existingCodes] = await pool.execute( + "SELECT * FROM mailverifiedcode WHERE code = ?", + [code], + ); + if (existingCodes.length === 0) { + return code; + } + } +} + +export default async function MailVerifySend(user: string, email: string, lang: string) { + const [userData] = await pool.execute( + "SELECT * FROM mailverifiedcode WHERE user = ?", + [user], + ); + + if (user === undefined) { + return "user_not_found"; + } + + const code = await createCode(); + + const [existingCodes] = await pool.execute( + "SELECT * FROM mailverifiedcode WHERE user = ?", + [user], + ); + + let row: RowDataPacket[] = []; + + if (existingCodes.length !== 0) { + [row] = await pool.execute( + "UPDATE `mailverifiedcode` SET `code` = ?, `time` = current_timestamp(3) WHERE `mailverifiedcode`.`user` = ?", + [code, user], + ); + } else { + [row] = await pool.execute( + "INSERT INTO `mailverifiedcode` (`code`, `user`, `email`, `time`, `num`) VALUES (?, ?, ?, current_timestamp(3), NULL);", + [code, user, email], + ); + } + + if ((row as RowDataPacket).affectedRows === 1) { + const infoReq = await fetch(`${Config.server.origin}/api/info`, { + method: "POST", + cache: "no-store", + }); + if (!infoReq.ok) { + return "network_error"; + } + const infoRes: InfoAPI = await infoReq.json(); + + await sendMail({ + to: email, + subject: `【${infoRes.server.name}】メール認証`, + text: Locale({ text: "mailverifyText", data: [ + user, + infoRes.server.name, + `${Config.server.origin}/mailverify?code=${code}` + ]}, lang), + }); + + return true; + } else { + return "save_failed"; + } +} diff --git a/packages/web/src/lib/path.ts b/packages/web/src/lib/path.ts new file mode 100644 index 0000000..84155a8 --- /dev/null +++ b/packages/web/src/lib/path.ts @@ -0,0 +1,16 @@ +import { fileURLToPath } from "url"; +import { dirname } from "path"; + +const getDirname = (moduleUrl: string) => { + const basicDirname = dirname( + fileURLToPath(moduleUrl) + ) + "/"; + + if (process.argv.includes("-tsx-develop")) { + return basicDirname; + } else { + return basicDirname + "../"; + } +}; + +export { getDirname }; diff --git a/packages/web/src/lib/toComponent.tsx b/packages/web/src/lib/toComponent.tsx new file mode 100644 index 0000000..c38dddc --- /dev/null +++ b/packages/web/src/lib/toComponent.tsx @@ -0,0 +1,3 @@ +export default function toComponent(message: string) { + return ; +} diff --git a/packages/web/src/lib/token.ts b/packages/web/src/lib/token.ts new file mode 100644 index 0000000..3fb7062 --- /dev/null +++ b/packages/web/src/lib/token.ts @@ -0,0 +1,30 @@ +import { randomBytes } from "crypto"; +import pool from "./database.js"; +import type { RowDataPacket } from "mysql2"; +import type scope from "../../types/api/scope"; + +export async function createAPIToken( + user: string, + scope: scope[], + name: string, +) { + const token = randomBytes(32).toString("hex"); + + const [insert] = await pool.execute( + "INSERT INTO `token` (`user`, `scope`, `name`, `token`) VALUES (?, ?, ?, ?);", + [user, scope.join(","), name, token], + ); + + return token; +} + +export async function getScopeAPIToken(token: string) { + const [tokenData] = await pool.execute( + "SELECT * FROM `token` WHERE token = ?", + [token] + ); + + const scope: scope[] = tokenData[0].scope.split(","); + + return scope; +} diff --git a/packages/web/src/lib/turnstile.ts b/packages/web/src/lib/turnstile.ts new file mode 100644 index 0000000..6894bb7 --- /dev/null +++ b/packages/web/src/lib/turnstile.ts @@ -0,0 +1,27 @@ +import pool from "./database.js"; +import type { RowDataPacket } from "mysql2"; + +export async function isEnabled() { + const [isEnabled] = await pool.execute( + "SELECT value FROM config WHERE name = 'turnstile_isEnabled'" + ); + + if (isEnabled[0].value === "1") { + return true; + } else { + return false; + } +} + +export async function getKeys() { + if (!isEnabled()) { + return []; + } + const [Sitekey] = await pool.execute( + "SELECT value FROM config WHERE name = 'turnstile_sitekey'" + ); + const [Secret] = await pool.execute( + "SELECT value FROM config WHERE name = 'turnstile_secret'" + ); + return [Sitekey[0].value, Secret[0].value]; +} diff --git a/packages/web/src/main.ts b/packages/web/src/main.ts new file mode 100644 index 0000000..168e9c5 --- /dev/null +++ b/packages/web/src/main.ts @@ -0,0 +1,59 @@ +import { serve } from "@hono/node-server"; +import { Hono } from "hono"; + +const app = new Hono(); + +// Checks +/// Locale Data Check +import { Check as LocaleDataCheck } from "./lib/locale.js"; +LocaleDataCheck(); + +/// Database Connect Check +import { verify as DBCheck, option as DBOption } from "./lib/database.js"; +DBCheck(DBOption(0)); + +// Middleware +/// Language +import { languageDetector } from "hono/language" +app.use(languageDetector({ + lookupCookie: "lang", + caches: ["cookie"], + cookieOptions: { + path: "/", + sameSite: "Lax", + maxAge: 86400 * 365, + }, + supportedLanguages: ["en", "ja"], + fallbackLanguage: "ja", +})) + +// Routing +/// API +import API from "./routes/api/main.js"; +app.route("/api", API); + +/// Static +import { serveStatic } from "@hono/node-server/serve-static"; +import { getDirname } from "./lib/path.js"; + +//// Hono/Public +app.use("*", serveStatic({ + root: `${getDirname(import.meta.url)}../public`, +})); + +//// Project Root/Files +app.use("*", serveStatic({ + root: `${getDirname(import.meta.url)}../../../files`, +})); + +/// Pages +import Pages from "./routes/pages/main.js"; +app.route("/", Pages); + +// Server +serve({ + fetch: app.fetch, + port: 3000 +}, (info) => { + console.log(`Server is running on http://${info.address}:${info.port}`); +}); diff --git a/packages/web/src/routes/api/info.ts b/packages/web/src/routes/api/info.ts new file mode 100644 index 0000000..dcd245c --- /dev/null +++ b/packages/web/src/routes/api/info.ts @@ -0,0 +1,65 @@ +import { Hono } from "hono"; +import pool from "../../lib/database.js"; +import type { RowDataPacket } from "mysql2"; +import { readFileSync } from "fs"; +import { getDirname } from "../../lib/path.js"; +import { getKeys as TurnstileKeys, isEnabled as Turnstile } from "../../lib/turnstile.js"; + +const infoAPI = new Hono(); + +infoAPI.post("/", async (c) => { + const packageJson = JSON.parse(readFileSync( + `${getDirname(import.meta.url)}/../../../../../package.json`, + "utf-8")); + const version = packageJson.version; + const author = packageJson.author; + const contributors = packageJson.contributors; + + const [IconURL] = await pool.execute( + "SELECT value FROM config WHERE name = 'server_icon'" + ); + + const [serverName] = await pool.execute( + "SELECT value FROM config WHERE name = 'server_name'" + ); + + const [serverDescription] = await pool.execute( + "SELECT value FROM config WHERE name = 'server_description'" + ); + + const [users] = await pool.execute( + "SELECT COUNT(*) AS count FROM users" + ); + + const [communitys] = await pool.execute( + "SELECT COUNT(*) AS count FROM community" + ); + + return c.json({ + success: true, + + server: { + icon: IconURL[0].value, + name: serverName[0].value, + description: serverDescription[0].value, + }, + + botprotection: { + turnstile: await Turnstile(), + }, + + software: { + version: version, + name: "Peas", + author: author, + contributors: contributors, + }, + + counts: { + user: users[0].count, + community: communitys[0].count, + }, + }); +}); + +export default infoAPI; diff --git a/packages/web/src/routes/api/mailverify.ts b/packages/web/src/routes/api/mailverify.ts new file mode 100644 index 0000000..a35c8f3 --- /dev/null +++ b/packages/web/src/routes/api/mailverify.ts @@ -0,0 +1,101 @@ +import { Hono } from "hono"; +import type { RowDataPacket } from "mysql2"; +import pool from "../../lib/database.js"; +import { getKeys as TurnstileKeys, isEnabled as Turnstile } from "../../lib/turnstile.js"; +import { v4 as uuid } from "uuid"; +import { getConnInfo } from "@hono/node-server/conninfo"; + +const Check = new Hono(); + +Check.post("/", async (c) => { + const body = await c.req.json(); + + if (body.code === undefined) { + return c.json({ + success: false, + error: "input_lack", + }, 400); + } + + if ( + await Turnstile() && + body.turnstile === undefined + ) { + return c.json({ + success: false, + error: "input_lack", + }, 400); + } + + if (await Turnstile()) { + const sendData = new FormData(); + const ip = getConnInfo(c).remote.address; + if (ip !== undefined) { + sendData.append("remoteip", ip); + } + sendData.append("secret", (await TurnstileKeys())[1]); + sendData.append("response", body.turnstile); + sendData.append("idempotency_key", uuid()) + + try { + const req = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", { + method: "POST", + cache: "no-store", + body: sendData, + }); + if (!req.ok) { + return c.json({ + success: false, + error: "turnstile_request_failed", + }, 500); + } + const res = await req.json(); + if (res.success === false) { + return c.json({ + success: false, + error: "turnstile_failed", + }, 400); + } + } catch (err) { + return c.json({ + success: false, + error: "turnstile_request_failed", + }, 500); + } + } + + const [rows] = await pool.execute( + "SELECT * FROM mailverifiedcode WHERE code = ?", + [body.code], + ); + + if (rows.length === 0) { + return c.json({ + success: false, + error: "code_not_found", + }, 400); + } else { + if (rows[0].code === body.code) { + await pool.query( + "UPDATE `users` SET `mailverified` = 1 WHERE `users`.`id` = ?", + [rows[0].user], + ); + + await pool.query( + "DELETE FROM `mailverifiedcode` WHERE (`user` = ?)", + [rows[0].user], + ); + + return c.json({ + success: true, + }); + } else { + return c.json({ + success: false, + error: "code_invalid", + }); + } + } +}); + +export default Check; diff --git a/packages/web/src/routes/api/main.ts b/packages/web/src/routes/api/main.ts new file mode 100644 index 0000000..88da13f --- /dev/null +++ b/packages/web/src/routes/api/main.ts @@ -0,0 +1,20 @@ +import { Hono } from "hono"; + +const API = new Hono(); + +import infoAPI from "./info.js"; +API.route("/info", infoAPI); + +import SignUpAPI from "./signup.js"; +API.route("/signup", SignUpAPI); + +import SignInAPI from "./signin.js"; +API.route("/signin", SignInAPI); + +import mailverifyAPI from "./mailverify.js"; +API.route("/mailverify", mailverifyAPI); + +import NotFound from "./notfound.js"; +API.route("*", NotFound); + +export default API; diff --git a/packages/web/src/routes/api/notfound.ts b/packages/web/src/routes/api/notfound.ts new file mode 100644 index 0000000..b9ccfb3 --- /dev/null +++ b/packages/web/src/routes/api/notfound.ts @@ -0,0 +1,12 @@ +import { Hono } from "hono"; + +const NotFound = new Hono(); + +NotFound.all("/", (c) => { + return c.json({ + success: false, + error: "not_found", + }, 404); +}); + +export default NotFound; diff --git a/packages/web/src/routes/api/signin.ts b/packages/web/src/routes/api/signin.ts new file mode 100644 index 0000000..02f97e5 --- /dev/null +++ b/packages/web/src/routes/api/signin.ts @@ -0,0 +1,123 @@ +import { Hono } from "hono"; +import pool from "../../lib/database.js"; +import type { RowDataPacket } from "mysql2"; +import { getKeys as TurnstileKeys, isEnabled as Turnstile } from "../../lib/turnstile.js"; +import { getConnInfo } from "@hono/node-server/conninfo"; +import { compareSync as passwordHashCheck } from "bcrypt"; +import { v4 as uuid } from "uuid"; +import MailVerifySend from "../../lib/mailverify.js"; +import { createAPIToken } from "src/lib/token.js"; +import { UAParser } from "ua-parser-js"; +import { setCookie } from "hono/cookie"; + +const SignInAPI = new Hono(); + +SignInAPI.post("/", async (c) => { + const body = await c.req.json(); + if ( + body.username === undefined || + body.password === undefined + ) { + return c.json({ + success: false, + error: "input_lack", + }, 400); + } + + if ( + body.username.length < 3 || + body.username.length > 15 || + body.password.length < 8 || + body.password.length > 15 + ) { + return c.json({ + success: false, + error: "length_different", + }, 400); + } + + if ( + await Turnstile() && + body.turnstile === undefined + ) { + return c.json({ + success: false, + error: "input_lack", + }, 400); + } + + if (await Turnstile()) { + const sendData = new FormData(); + const ip = getConnInfo(c).remote.address; + if (ip !== undefined) { + sendData.append("remoteip", ip); + } + sendData.append("secret", (await TurnstileKeys())[1]); + sendData.append("response", body.turnstile); + sendData.append("idempotency_key", uuid()) + + try { + const req = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", { + method: "POST", + cache: "no-store", + body: sendData, + }); + if (!req.ok) { + return c.json({ + success: false, + error: "turnstile_request_failed", + }, 500); + } + const res = await req.json(); + if (res.success === false) { + return c.json({ + success: false, + error: "turnstile_failed", + }, 400); + } + } catch (err) { + return c.json({ + success: false, + error: "turnstile_request_failed", + }, 500); + } + } + + const [user] = await pool.execute( + "SELECT * FROM users WHERE id = ?", + [body.username], + ); + + if (user === undefined) { + return c.json({ + success: false, + error: "user_not_found", + }, 400); + } + + if (passwordHashCheck(body.password, user[0].password)) { + const token = await createAPIToken( + body.username, + ["client"], + "Peas Client" + ); + + setCookie(c, "token", token, { + path: "/", + sameSite: "Lax", + maxAge: 86400 * 365, + }); + + return c.json({ + success: true, + token: token, + }); + } else { + return c.json({ + success: false, + error: "password_invalid", + }, 400); + } +}); + +export default SignInAPI; diff --git a/packages/web/src/routes/api/signup.ts b/packages/web/src/routes/api/signup.ts new file mode 100644 index 0000000..d29878e --- /dev/null +++ b/packages/web/src/routes/api/signup.ts @@ -0,0 +1,135 @@ +import { Hono } from "hono"; +import pool from "../../lib/database.js"; +import type { RowDataPacket } from "mysql2"; +import { getKeys as TurnstileKeys, isEnabled as Turnstile } from "../../lib/turnstile.js"; +import { getConnInfo } from "@hono/node-server/conninfo"; +import { hash as generatePasswordHash } from "bcrypt"; +import { v4 as uuid } from "uuid"; +import MailVerifySend from "../../lib/mailverify.js"; + +const SignUpAPI = new Hono(); + +SignUpAPI.post("/", async (c) => { + const body = await c.req.json(); + if ( + body.username === undefined || + body.email === undefined || + body.password === undefined + ) { + return c.json({ + success: false, + error: "input_lack", + }, 400); + } + + if ( + body.username.length < 3 || + body.username.length > 15 || + body.password.length < 8 || + body.password.length > 15 + ) { + return c.json({ + success: false, + error: "length_different", + }, 400); + } + + if ( + await Turnstile() && + body.turnstile === undefined + ) { + return c.json({ + success: false, + error: "input_lack", + }, 400); + } + + if (await Turnstile()) { + const sendData = new FormData(); + const ip = getConnInfo(c).remote.address; + if (ip !== undefined) { + sendData.append("remoteip", ip); + } + sendData.append("secret", (await TurnstileKeys())[1]); + sendData.append("response", body.turnstile); + sendData.append("idempotency_key", uuid()) + + try { + const req = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", { + method: "POST", + cache: "no-store", + body: sendData, + }); + if (!req.ok) { + return c.json({ + success: false, + error: "turnstile_request_failed", + }, 500); + } + const res = await req.json(); + if (res.success === false) { + return c.json({ + success: false, + error: "turnstile_failed", + }, 400); + } + } catch (err) { + return c.json({ + success: false, + error: "turnstile_request_failed", + }, 500); + } + } + + const [duplicateUsers] = await pool.execute( + "SELECT * FROM users WHERE id = ?", + [body.username], + ); + + const [duplicateEmails] = await pool.execute( + "SELECT * FROM users WHERE email = ?", + [body.email], + ); + + if (duplicateUsers.length > 0) { + return c.json({ + success: false, + error: "username_duplicate", + }, 400); + } + + if (duplicateEmails.length > 0) { + return c.json({ + success: false, + error: "email_duplicate", + }, 400); + } + + const passwordHash = await generatePasswordHash(body.password, 10); + + const [result] = await pool.execute( + "INSERT INTO `users` (`id`, `password`, `email`, `mailverified`, `time`) VALUES (?, ?, ?, '0', current_timestamp(3))", + [body.username, passwordHash, body.email], + ); + + if ((result as RowDataPacket).affectedRows === 1) { + const send = await MailVerifySend(body.username, body.email, c.get("language")); + if (send === true) { + return c.json({ + success: true, + }, 201); + } else { + return c.json({ + success: false, + error: send, + }, 500); + } + } else { + return c.json({ + success: false, + error: "account_create_failed", + }, 500); + } +}); + +export default SignUpAPI; diff --git a/packages/web/src/routes/pages/home.tsx b/packages/web/src/routes/pages/home.tsx new file mode 100644 index 0000000..4b133cd --- /dev/null +++ b/packages/web/src/routes/pages/home.tsx @@ -0,0 +1,33 @@ +import { Hono } from "hono"; +import { Layout } from "./layout.js"; +import type InfoAPI from "../../../types/api/info"; +import Config from "../../../config/peas.config.js"; +import { getCookie } from "hono/cookie"; +import { Locale } from "../../lib/locale.js"; + +const Home = new Hono(); + +Home.get("/", async (c) => { + if (getCookie(c, "token") === undefined) return c.redirect("/signin"); + + const InfoReq = await fetch(`${Config.server.origin}/api/info`, { + method: "POST", + cache: "no-store", + }); + if (!InfoReq.ok) { + return c.status(500); + } + + const InfoRes: InfoAPI = await InfoReq.json(); + + return c.html( + + + + ); +}) + +export default Home; diff --git a/packages/web/src/routes/pages/index.tsx b/packages/web/src/routes/pages/index.tsx new file mode 100644 index 0000000..7338691 --- /dev/null +++ b/packages/web/src/routes/pages/index.tsx @@ -0,0 +1,155 @@ +import { Hono } from "hono"; +import { Layout } from "./layout.js"; +import type InfoAPI from "../../../types/api/info"; +import Config from "../../../config/peas.config.js"; +import Icon from "../../components/iconify.js"; +import { Locale } from "../../lib/locale.js"; +import toComponent from "../../lib/toComponent.js"; +import { getCookie } from "hono/cookie"; +import { getScopeAPIToken } from "../../lib/token.js"; + +const Index = new Hono(); + +Index.get("/", async (c) => { + if (getCookie(c, "token") !== undefined) { + const scope = await getScopeAPIToken(getCookie(c, "token") ?? ""); + if (scope !== undefined) return c.redirect("/home"); + } + + const InfoReq = await fetch(`${Config.server.origin}/api/info`, { + method: "POST", + cache: "no-store", + }); + if (!InfoReq.ok) { + return c.status(500); + } + + const InfoRes: InfoAPI = await InfoReq.json(); + + return c.html( + +
+

+ + {InfoRes.server.name} +

+ +
+

+ + {Locale({ text: "PeasAboutTitle" }, c.get("language"))} +

+ {toComponent(Locale({ text: "PeasAboutText" }, c.get("language")))} +
+ +
+

+ + {Locale({ text: "ServerAboutTitle" }, c.get("language"))} +

+ {toComponent(InfoRes.server.description)} + +
+
+ {Locale({ text: "userCount" }, c.get("language"))} +
+ {InfoRes.counts.user} +
+ +
+ {Locale({ text: "communityCount" }, c.get("language"))} +
+ {InfoRes.counts.community} +
+
+ + {Locale({ text: "topPeasCredit", data: [InfoRes.software.version] }, c.get("language"))} +
+ + +
+
+ ); +}); + +export default Index; diff --git a/packages/web/src/routes/pages/layout.tsx b/packages/web/src/routes/pages/layout.tsx new file mode 100644 index 0000000..b2a7973 --- /dev/null +++ b/packages/web/src/routes/pages/layout.tsx @@ -0,0 +1,73 @@ +import type { FC } from "hono/jsx"; +import Config from "../../../config/peas.config.js"; +import type InfoAPI from "../../../types/api/info"; + +interface Option { + title: string; + description?: string; + noindex?: boolean; + noai?: boolean; + noimageai?: boolean; + children?: any; +}; + +const Layout: FC