From 27c5cce24b700ddd019af745863d4501078ec6c0 Mon Sep 17 00:00:00 2001
From: Pop star <141120325+popstar7@users.noreply.github.com>
Date: Thu, 21 Nov 2024 14:47:57 -0500
Subject: [PATCH] Initialize sitemap2
---
.eslintignore | 13 +
.eslintrc.cjs | 48 +
.github/workflows/build.yml | 23 +
.github/workflows/format.yml | 30 +
.github/workflows/linting.yml | 26 +
.github/workflows/tests.yml | 23 +
.gitignore | 10 +
.npmrc | 2 +
.prettierignore | 6 +
.prettierrc | 7 +
.vscode/settings.json | 13 +
LICENSE | 21 +
README.md | 330 +
SECURITY.md | 7 +
database_migration.sql | 73 +
email_docs.md | 45 +
local_env_template | 12 +
package-lock.json | 6468 +++++++++++++++++
package.json | 54 +
postcss.config.js | 6 +
src/DatabaseDefinitions.ts | 121 +
src/ambient.d.ts | 12 +
src/app.css | 21 +
src/app.d.ts | 21 +
src/app.html | 15 +
src/config.ts | 4 +
src/hooks.server.ts | 54 +
src/index.test.ts | 7 +
src/lib/build_index.ts | 77 +
src/lib/emails/welcome_email_html.svelte | 292 +
src/lib/emails/welcome_email_text.svelte | 18 +
src/lib/index.js | 1 +
src/lib/mailer.test.ts | 121 +
src/lib/mailer.ts | 175 +
.../(admin)/account/(menu)/+layout.svelte | 142 +
.../(admin)/account/(menu)/+page.server.ts | 11 +
.../(admin)/account/(menu)/+page.svelte | 88 +
.../account/(menu)/billing/+page.server.ts | 44 +
.../account/(menu)/billing/+page.svelte | 57 +
.../(menu)/billing/manage/+page.server.ts | 39 +
.../account/(menu)/settings/+page.svelte | 75 +
.../(menu)/settings/change_email/+page.svelte | 34 +
.../change_email_subscription/+page.svelte | 26 +
.../settings/change_password/+page.svelte | 109 +
.../settings/delete_account/+page.svelte | 37 +
.../(menu)/settings/edit_profile/+page.svelte | 46 +
.../settings/reset_password/+page.svelte | 37 +
.../(menu)/settings/settings_module.svelte | 157 +
src/routes/(admin)/account/+layout.server.ts | 20 +
src/routes/(admin)/account/+layout.svelte | 21 +
src/routes/(admin)/account/+layout.ts | 57 +
.../(admin)/account/api/+page.server.ts | 334 +
.../(admin)/account/api/page.server.test.ts | 123 +
.../account/create_profile/+page.svelte | 120 +
.../(admin)/account/create_profile/+page.ts | 13 +
.../(admin)/account/select_plan/+page.svelte | 22 +
.../(admin)/account/sign_out/+page.svelte | 18 +
.../account/subscribe/[slug]/+page.server.ts | 64 +
.../account/subscription_helpers.server.ts | 130 +
src/routes/(marketing)/+layout.svelte | 111 +
src/routes/(marketing)/+page.svelte | 431 ++
src/routes/(marketing)/+page.ts | 1 +
.../(marketing)/auth/callback/+server.js | 27 +
.../(marketing)/blog/(posts)/+layout.svelte | 71 +
.../blog/(posts)/awesome_post/+page.svelte | 26 +
.../(posts)/example_blog_post/+page.svelte | 26 +
.../+page.svelte | 35 +
src/routes/(marketing)/blog/+layout.ts | 1 +
src/routes/(marketing)/blog/+page.svelte | 47 +
src/routes/(marketing)/blog/posts.ts | 52 +
.../(marketing)/blog/rss.xml/+server.ts | 37 +
.../(marketing)/contact_us/+page.server.ts | 78 +
.../(marketing)/contact_us/+page.svelte | 156 +
.../(marketing)/login/+layout.server.ts | 19 +
src/routes/(marketing)/login/+layout.svelte | 21 +
src/routes/(marketing)/login/+layout.ts | 20 +
src/routes/(marketing)/login/+page.svelte | 16 +
.../login/current_password_error/+page.svelte | 19 +
.../login/forgot_password/+page.server.ts | 1 +
.../login/forgot_password/+page.svelte | 26 +
src/routes/(marketing)/login/login_config.ts | 30 +
.../(marketing)/login/sign_in/+page.server.ts | 1 +
.../(marketing)/login/sign_in/+page.svelte | 63 +
.../(marketing)/login/sign_up/+page.server.ts | 1 +
.../(marketing)/login/sign_up/+page.svelte | 25 +
src/routes/(marketing)/pricing/+page.svelte | 215 +
src/routes/(marketing)/pricing/+page.ts | 1 +
.../(marketing)/pricing/pricing_module.svelte | 60 +
.../(marketing)/pricing/pricing_plans.ts | 43 +
src/routes/(marketing)/search/+page.server.ts | 1 +
src/routes/(marketing)/search/+page.svelte | 156 +
.../(marketing)/search/api.json/+server.ts | 14 +
src/routes/(marketing)/sitemap.xml/+server.ts | 14 +
src/routes/+error.svelte | 16 +
src/routes/+layout.svelte | 21 +
static/favicon.png | Bin 0 -> 5420 bytes
static/images/cm_logo.svg | 1 +
static/images/example-home.png | Bin 0 -> 31320 bytes
static/images/rss.svg | 1 +
static/robots.txt | 3 +
.../migrations/20240730010101_initial.sql | 72 +
...731051052_add_unsubscribed_to_profiles.sql | 2 +
svelte.config.js | 15 +
tailwind.config.js | 28 +
tsconfig.json | 18 +
vite.config.ts | 24 +
106 files changed, 12026 insertions(+)
create mode 100644 .eslintignore
create mode 100644 .eslintrc.cjs
create mode 100644 .github/workflows/build.yml
create mode 100644 .github/workflows/format.yml
create mode 100644 .github/workflows/linting.yml
create mode 100644 .github/workflows/tests.yml
create mode 100644 .gitignore
create mode 100644 .npmrc
create mode 100644 .prettierignore
create mode 100644 .prettierrc
create mode 100644 .vscode/settings.json
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 SECURITY.md
create mode 100644 database_migration.sql
create mode 100644 email_docs.md
create mode 100644 local_env_template
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 postcss.config.js
create mode 100644 src/DatabaseDefinitions.ts
create mode 100644 src/ambient.d.ts
create mode 100644 src/app.css
create mode 100644 src/app.d.ts
create mode 100644 src/app.html
create mode 100644 src/config.ts
create mode 100644 src/hooks.server.ts
create mode 100644 src/index.test.ts
create mode 100644 src/lib/build_index.ts
create mode 100644 src/lib/emails/welcome_email_html.svelte
create mode 100644 src/lib/emails/welcome_email_text.svelte
create mode 100644 src/lib/index.js
create mode 100644 src/lib/mailer.test.ts
create mode 100644 src/lib/mailer.ts
create mode 100644 src/routes/(admin)/account/(menu)/+layout.svelte
create mode 100644 src/routes/(admin)/account/(menu)/+page.server.ts
create mode 100644 src/routes/(admin)/account/(menu)/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/billing/+page.server.ts
create mode 100644 src/routes/(admin)/account/(menu)/billing/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/billing/manage/+page.server.ts
create mode 100644 src/routes/(admin)/account/(menu)/settings/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/change_email/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/change_email_subscription/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/change_password/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/delete_account/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/edit_profile/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/reset_password/+page.svelte
create mode 100644 src/routes/(admin)/account/(menu)/settings/settings_module.svelte
create mode 100644 src/routes/(admin)/account/+layout.server.ts
create mode 100644 src/routes/(admin)/account/+layout.svelte
create mode 100644 src/routes/(admin)/account/+layout.ts
create mode 100644 src/routes/(admin)/account/api/+page.server.ts
create mode 100644 src/routes/(admin)/account/api/page.server.test.ts
create mode 100644 src/routes/(admin)/account/create_profile/+page.svelte
create mode 100644 src/routes/(admin)/account/create_profile/+page.ts
create mode 100644 src/routes/(admin)/account/select_plan/+page.svelte
create mode 100644 src/routes/(admin)/account/sign_out/+page.svelte
create mode 100644 src/routes/(admin)/account/subscribe/[slug]/+page.server.ts
create mode 100644 src/routes/(admin)/account/subscription_helpers.server.ts
create mode 100644 src/routes/(marketing)/+layout.svelte
create mode 100644 src/routes/(marketing)/+page.svelte
create mode 100644 src/routes/(marketing)/+page.ts
create mode 100644 src/routes/(marketing)/auth/callback/+server.js
create mode 100644 src/routes/(marketing)/blog/(posts)/+layout.svelte
create mode 100644 src/routes/(marketing)/blog/(posts)/awesome_post/+page.svelte
create mode 100644 src/routes/(marketing)/blog/(posts)/example_blog_post/+page.svelte
create mode 100644 src/routes/(marketing)/blog/(posts)/how_we_built_our_41kb_saas_website/+page.svelte
create mode 100644 src/routes/(marketing)/blog/+layout.ts
create mode 100644 src/routes/(marketing)/blog/+page.svelte
create mode 100644 src/routes/(marketing)/blog/posts.ts
create mode 100644 src/routes/(marketing)/blog/rss.xml/+server.ts
create mode 100644 src/routes/(marketing)/contact_us/+page.server.ts
create mode 100644 src/routes/(marketing)/contact_us/+page.svelte
create mode 100644 src/routes/(marketing)/login/+layout.server.ts
create mode 100644 src/routes/(marketing)/login/+layout.svelte
create mode 100644 src/routes/(marketing)/login/+layout.ts
create mode 100644 src/routes/(marketing)/login/+page.svelte
create mode 100644 src/routes/(marketing)/login/current_password_error/+page.svelte
create mode 100644 src/routes/(marketing)/login/forgot_password/+page.server.ts
create mode 100644 src/routes/(marketing)/login/forgot_password/+page.svelte
create mode 100644 src/routes/(marketing)/login/login_config.ts
create mode 100644 src/routes/(marketing)/login/sign_in/+page.server.ts
create mode 100644 src/routes/(marketing)/login/sign_in/+page.svelte
create mode 100644 src/routes/(marketing)/login/sign_up/+page.server.ts
create mode 100644 src/routes/(marketing)/login/sign_up/+page.svelte
create mode 100644 src/routes/(marketing)/pricing/+page.svelte
create mode 100644 src/routes/(marketing)/pricing/+page.ts
create mode 100644 src/routes/(marketing)/pricing/pricing_module.svelte
create mode 100644 src/routes/(marketing)/pricing/pricing_plans.ts
create mode 100644 src/routes/(marketing)/search/+page.server.ts
create mode 100644 src/routes/(marketing)/search/+page.svelte
create mode 100644 src/routes/(marketing)/search/api.json/+server.ts
create mode 100644 src/routes/(marketing)/sitemap.xml/+server.ts
create mode 100644 src/routes/+error.svelte
create mode 100644 src/routes/+layout.svelte
create mode 100644 static/favicon.png
create mode 100644 static/images/cm_logo.svg
create mode 100644 static/images/example-home.png
create mode 100644 static/images/rss.svg
create mode 100644 static/robots.txt
create mode 100644 supabase/migrations/20240730010101_initial.sql
create mode 100644 supabase/migrations/20240731051052_add_unsubscribed_to_profiles.sql
create mode 100644 svelte.config.js
create mode 100644 tailwind.config.js
create mode 100644 tsconfig.json
create mode 100644 vite.config.ts
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..3897265
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,13 @@
+.DS_Store
+node_modules
+/build
+/.svelte-kit
+/package
+.env
+.env.*
+!.env.example
+
+# Ignore files for PNPM, NPM and YARN
+pnpm-lock.yaml
+package-lock.json
+yarn.lock
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 0000000..1a5c8ae
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,48 @@
+module.exports = {
+ root: true,
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:svelte/recommended",
+ "prettier",
+ ],
+ parser: "@typescript-eslint/parser",
+ plugins: ["@typescript-eslint"],
+ parserOptions: {
+ sourceType: "module",
+ ecmaVersion: 2020,
+ extraFileExtensions: [".svelte"],
+ },
+ overrides: [
+ {
+ files: ["*.svelte"],
+ parser: "svelte-eslint-parser",
+ parserOptions: {
+ parser: {
+ // Specify a parser for each lang.
+ ts: "@typescript-eslint/parser",
+ js: "espree",
+ typescript: "@typescript-eslint/parser",
+ },
+ },
+ },
+ {
+ // Apply to all test files. Proper type checking in tests with mocks can be tedious and counterproductive.
+ files: ["**/*.test.ts", "**/*.spec.ts"],
+ rules: {
+ "@typescript-eslint/no-explicit-any": "off",
+ },
+ },
+ ],
+ env: {
+ browser: true,
+ es2017: true,
+ node: true,
+ },
+ rules: {
+ "no-undef": "off",
+ // no-undef has been turned off because of this:
+ // basically, it causes issues and TS does those checks so it's redundant
+ // https://typescript-eslint.io/linting/troubleshooting#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
+ },
+}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..92c4e7b
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,23 @@
+name: Build
+
+on: [push, pull_request]
+
+env:
+ PUBLIC_SUPABASE_URL: "https://fake_test_url.supabase.co"
+ PUBLIC_SUPABASE_ANON_KEY: "fake_anon_key"
+ PRIVATE_SUPABASE_SERVICE_ROLE: "fake_service_role"
+ PRIVATE_STRIPE_API_KEY: "fake_strip_api_key"
+
+jobs:
+ build_and_test:
+ name: Build
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: NPM install
+ run: npm install
+
+ - name: SvelteKit Build
+ run: npm run build
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
new file mode 100644
index 0000000..a9474b8
--- /dev/null
+++ b/.github/workflows/format.yml
@@ -0,0 +1,30 @@
+name: Format Check
+
+on: [push, pull_request]
+
+env:
+ PUBLIC_SUPABASE_URL: "https://fake_test_url.supabase.co"
+ PUBLIC_SUPABASE_ANON_KEY: "fake_anon_key"
+ PRIVATE_SUPABASE_SERVICE_ROLE: "fake_service_role"
+ PRIVATE_STRIPE_API_KEY: "fake_strip_api_key"
+
+jobs:
+ build_and_test:
+ name: Code Format Check
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-go@v5
+
+ - name: NPM install
+ run: npm install
+
+ - name: Check Code Format
+ run: npm run format_check
+
+ - name: Download go misspell utility
+ run: go install github.com/client9/misspell/cmd/misspell@latest
+
+ - name: Run misspell to fine misspelled words
+ run: misspell -error ./src README.md
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
new file mode 100644
index 0000000..b263147
--- /dev/null
+++ b/.github/workflows/linting.yml
@@ -0,0 +1,26 @@
+name: Linting
+
+on: [push, pull_request]
+
+env:
+ PUBLIC_SUPABASE_URL: "https://fake_test_url.supabase.co"
+ PUBLIC_SUPABASE_ANON_KEY: "fake_anon_key"
+ PRIVATE_SUPABASE_SERVICE_ROLE: "fake_service_role"
+ PRIVATE_STRIPE_API_KEY: "fake_strip_api_key"
+
+jobs:
+ build_and_test:
+ name: Linting and Typechecking
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: NPM install
+ run: npm install
+
+ - name: Linting
+ run: npm run lint
+
+ - name: Typechecking
+ run: npm run check
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..6a3eeae
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,23 @@
+name: Tests
+
+on: [push, pull_request]
+
+env:
+ PUBLIC_SUPABASE_URL: "https://fake_test_url.supabase.co"
+ PUBLIC_SUPABASE_ANON_KEY: "fake_anon_key"
+ PRIVATE_SUPABASE_SERVICE_ROLE: "fake_service_role"
+ PRIVATE_STRIPE_API_KEY: "fake_strip_api_key"
+
+jobs:
+ build_and_test:
+ name: Tests
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: NPM install
+ run: npm install
+
+ - name: Tests
+ run: npm run test_run
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6635cf5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.DS_Store
+node_modules
+/build
+/.svelte-kit
+/package
+.env
+.env.*
+!.env.example
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..0c05da4
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,2 @@
+engine-strict=true
+resolution-mode=highest
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..78e9e45
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,6 @@
+**/.svelte-kit/
+**/node_modules/
+**/package-lock.json
+
+# Don't format plaintext email templates, the new lines are important
+src/lib/emails/*_text.svelte
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..0367da2
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "plugins": ["prettier-plugin-svelte"],
+ "useTabs": false,
+ "tabWidth": 2,
+ "semi": false,
+ "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..78afa4d
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,13 @@
+{
+ "editor.formatOnSave": true,
+ "[svelte]": {
+ "editor.defaultFormatter": "svelte.svelte-vscode"
+ },
+ "[typescript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "[javascript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "eslint.validate": ["javascript", "javascriptreact", "typescript", "svelte"]
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..421f6cd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Chesterfield Laboratoires Inc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d4c4ae2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,330 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Demo & Homepage •
+ Quick Start Guide •
+ Issues
+
+
+
+
+# SaaS Starter: A SvelteKit Boilerplate/Template
+
+- [Feature Rich](#features): user auth, user dashboard, marketing site, blog engine, billing/subscriptions, pricing page, search, emails, and more.
+- [Lightning Performance](#performance--best-practices): fast pre-rendered pages which score 100/100 on Google PageSpeed.
+- [Delighful Developer Experience](#tech-stack): tools you'll love working with, including SvelteKit, Tailwind, DaisyUI, Postgres, and Supabase.
+- Extensible: all the tools you need to make additional marketing pages, UI components, user dashboards, admin portals, database backends, API endpoints, and more.
+- [Hosting](#suggested-hosting-stack): Our suggested hosting stack is free to host, cheap to scale, easy to manage, and includes automatic deployments.
+- [MIT Open Source](https://github.com/CriticalMoments/CMSaasStarter/blob/main/LICENSE)
+- [Fully Functional Demo](https://saasstarter.work)
+- [Quick Start](#quick-start): Full docs from `git clone` to deployment.
+
+Created by the folks at [Critical Moments](https://criticalmoments.io)! Check out our website site for an example deployment of SaaS Starter.
+
+**Make mobile apps?** Improve conversion rates and ratings with [Critical Moments](https://criticalmoments.io).
+
+## Demo
+
+You can explore all the features using our fully functional demo [saasstarter.work](https://saasstarter.work).
+
+[![Try it Now](https://img.shields.io/badge/Try_it_Now-37a779?style=for-the-badge "Try it Now")](https://saasstarter.work)
+
+See [criticalmoments.io](https://criticalmoments.io) for an example of what’s possible after this template has design, content, and functionality added.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Features
+
+Everything you need to get started for a SaaS company:
+
+- User Authentication: Sign up, sign out, forgot password, email verification, and oAuth. Powered by Supabase Auth. GDPR cookie warning for European users.
+- Marketing Page with SEO optimization
+- Blog engine with rich formatting, RSS and SEO optimization.
+- User Dashboard with user profile, user settings, update email/password, billing, and more
+- Subscriptions powered by Stripe Checkout
+- Pricing page
+- Emails: send emails to users, including template support
+- Search: lightning fast site search, without a backend
+- Contact-us form
+- Billing portal: self serve to change card, upgrade, cancel, or download receipts
+- Onboarding flow after signup: collect user data, and select a payment plan
+- Style toolkit: theming and UI components
+- Responsive: designed for mobile and desktop.
+- Extensible: all the tools you need to make additional marketing pages, UI components, admin portals, database backends, API endpoints, and more.
+- Sitemap
+
+## Introduction Blog Post
+
+What to learn why we picked the technologies we did, and how to keep your fork lightning fast as you add content? Check out [our blog post](https://criticalmoments.io/blog/how_we_built_our_marketing_page) on the process. Yes, it's hosted on a SaaS Starter fork!
+
+## Tech Stack
+
+- Web Framework: SvelteKit
+- CSS / Styling
+ - Framework: TailwindCSS
+ - Component library: DaisyUI
+- Suggested Hosting Stack
+ - Host + CDN: Cloudflare Pages
+ - Serverless compute: Cloudflare Workers
+ - Authentication: Supabase Auth
+ - Database: Supabase Postgres
+- Payments
+ - Stripe Checkout
+ - Stripe Portal
+
+## Suggested Hosting Stack
+
+**There’s no cost for using this template**. The costs below reflect our suggested hosting stack.
+
+- **$0/mo** — Supabase free tier, Cloudflare free tier.
+ - Pros:
+ - Free!
+ - Can scale to thousands of users.
+ - Unlimited static page requests.
+ - 100k serverless functions/day.
+ - Cons:
+ - Does not include database backups. The frugal among you could hook up pgdump backups on lambda/S3 for a few cents per month.
+ - Will auto-pause your database when not in use for 7 days.
+ - Who it’s for:
+ - This tier is perfectly functional for a hobby project, or pre-revenue company (up to 50,000 monthly active users). It’s easy to scale up once revenue starts, but it’s also fine to keep at this scale indefinitely.
+- **$30/mo** - Supabase Pro, Cloudfare [Workers Paid](https://www.cloudflare.com/plans/developer-platform/)
+ - Pros:
+ - Database backups.
+ - Never pauses database.
+ - Over 1M serverless functions per day, with linear pricing for additional invocations.
+ - Cons:
+ - none
+ - Who it’s for:
+ - I suggest moving to this once you have paid customers or investors.
+
+## Performance / Best Practices
+
+The selected tech stack creates lightning fast websites.
+
+- Pre-rendering (static generation) for marketing pages, pricing and blog
+- Instant navigation: the best of CSR + SSR in one. SSR your first page for fastest possible initial load times. For subsequent pages, the content is pre-loaded and rendered with CSR, for instant rendering.
+- CDN optimized, for high edge-cache hit ratios
+- Edge-functions for dynamic APIs/pages
+- Svelte and Tailwind compile out unused HTML, CSS and JS at deploy time for smaller pages
+- Linting to find accessibility and syntax issues
+
+The result is a perfect Google PageSpeed Insights score in all categories!
+
+
+
+# Quick Start
+
+## Create a Copy of the Template
+
+To get started, create your own copy of the project for development. There are two options:
+
+- "Use this template": use this Github button if you want to build your own project using CMSaasStarter as a starter template and you aren't planning on contributing work back to the public open source project. See [Github Docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template).
+- "Fork": use this button if you want contribute some or all of your work back to the public open source project. It will keep the full commit history, and be easier to create PRs back to CMSaasStarter.
+
+## Setup Local Development
+
+On your development machine:
+
+```
+git pull [Your Repo Created Above]
+cd CMSaasStarter ## or your repo name if different
+npm install
+## Create an env file. You'll replace the values in this in later steps.
+cp local_env_template .env.local
+## Run the project locally in dev mode, and launch the browser
+npm run dev -- --open
+```
+
+**Note:** some features won't work until you complete the rest of the setup steps below!
+
+## Developer Tools
+
+The repo includes [CI scripts](https://aws.amazon.com/devops/continuous-integration/) designed for [GitHub Actions](https://github.com/features/actions). These confirm you don’t break your [build](https://github.com/CriticalMoments/CMSaasStarter/blob/main/.github/workflows/build.yml), you use [proper code formatting](https://github.com/CriticalMoments/CMSaasStarter/blob/main/.github/workflows/format.yml), and [code linting and typechecking passes](https://github.com/CriticalMoments/CMSaasStarter/blob/main/.github/workflows/linting.yml). Github disables CI on new repos by default, so be sure to go into the Github Actions page for your repo and enable workflows.
+
+You can manually run these scripts yourself; `npm run build` for the build, `npm run format_check` to check formatting, `npm run lint` for the linting, `npm run check` for typechecking, and `npm run test` for testing (if you add tests).
+
+Installing extensions in your editor can automatically format-on-save, show linting/type issues inline, and run your test cases:
+
+- Svelte for Svelte and accessibility issues: [VSCode](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) or [other editors](https://sveltesociety.dev/tools#editor-support)
+- ESLint for type checking and linting: [VSCode](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [other editors](https://eslint.org/docs/latest/use/integrations)
+- Vitest for testing if you add tests: [VSCode](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) or [other editors](https://vitest.dev/guide/ide)
+
+To catch build, formatting, linting and test issues before you commit changes, we suggest the following local git hook. It will run before you commit, stop you from breaking the build, and show any issues that are found. Add the lines below to an executable git hook script at the location `.git/hooks/pre-commit`.
+
+```
+#!/bin/sh
+set -e
+npm run format_check
+npm run lint
+npm run build
+npm run check
+npm run test_run
+
+# Optional: check for misspelled words. Uncomment line below after installing misspell tool https://github.com/client9/misspell?tab=readme-ov-file#install
+# misspell -error ./src README.md
+```
+
+Finally: if you find build, formatting or linting rules too tedious, you can disable enforcement by deleting the CI files (`.github/workflows/*`) and remove the git hook (`.git/hooks/pre-commit`).
+
+## Setup Supabase Project
+
+- Create a Supabase account
+- Create a new Supabase project in the console
+- Wait for the database to launch
+- Set up your database schema:
+ - For new Supabase projects:
+ - Go to the [SQL Editor](https://supabase.com/dashboard/project/_/sql) page in the Dashboard.
+ - Run the SQL from `database_migration.sql` to create the initial schema.
+ - For existing projects:
+ - Apply migrations from the `supabase/migrations` directory:
+ 1. Go to the Supabase dashboard's SQL Editor.
+ 2. Identify the last migration you applied, then run the SQL content of each subsequent file in chronological order.
+- Enable user signups in the [Supabase console](https://app.supabase.com/project/_/settings/auth): sometimes new signups are disabled by default in Supabase projects
+- Go to the [API Settings](https://supabase.com/dashboard/project/_/settings/api) page in the Dashboard. Find your Project-URL (PUBLIC_SUPABASE_URL), anon (PUBLIC_SUPABASE_ANON_KEY) and service_role (PRIVATE_SUPABASE_SERVICE_ROLE).
+ - For local development: create a `.env.local` file:
+ ```
+ PUBLIC_SUPABASE_URL=https://your-project.supabase.co
+ PUBLIC_SUPABASE_ANON_KEY=your-anon-key
+ PRIVATE_SUPABASE_SERVICE_ROLE=your service_role secret
+ ```
+ - For production, add these two keys to your deployment environment (see below). We suggest you encrypt your service role.
+- Auth Callback
+ - Set your default callback URL for auth in the Supabase Auth console. For example, for the demo page we added: `https://saasstarter.work/auth/callback` . Also add that same URL to the the “allowed redirect URL” list in the Supabase auth console further down the page.
+ - Add a link to the redirect URL allow list which allows parameters to your auth callback. For example we added the following for the demo page: `https://saasstarter.work/auth/callback?*`
+ - Also add any local development URLs you want to use in testing to the list for your dev environment. For example, we added the following for local development: `http://localhost:5173/auth/callback` and `http://localhost:5173/auth/callback?*`.
+ - Test that the "sign up" and "forgot password" emails link back to your domain correctly by checking the have a redirect_to parameter to your `yourdomain.com/auth/callback`. If they link to the base URL or another page, double check you have the config above set correctly.
+- OAuth Logins
+ - Decide which oauth logins you want to support, and set them up in the Supabase Auth console under “Auth Providers”. Be sure to provide them the Supabase callback URL. Also be sure to set any platform specific permissions/settings to retrieve their email as part of the login (for example, for Github it's under `Account Permissions > Email Address > Read Only Access`
+ - Edit `oauthProviders` list in `/src/routes/(marketing)/login/login_config.ts` with the list of providers you chose. If you don’t want any OAuth options, make this an empty array.
+ - Test each provider to ensure you setup the client ID, client secret and callback correctly for each
+- Auth Email SMTP
+ - Supabase has a limit of 4 emails per hour on their development server. You should [Configure a Custom SMTP](https://supabase.com/docs/guides/auth/auth-smtp) sending emails from your own domain.
+ - Customize the email templates in the Supabase Auth console to include your product name and branding
+- Test authentication
+ - Open the `/login` page in your browser, and ensure you can sign up, confirm email, log in, and edit your account.
+
+## Setup Stripe
+
+- Create a Stripe account
+- Create a product and price Tiers
+ - Create your [products](https://stripe.com/docs/api/products) and their [prices](https://stripe.com/docs/api/prices) in the Dashboard or with the Stripe CLI.
+ - SaaS Starter works best if you define each tier as a separate product (eg, `SaaS Starter Free`, `Saas Starter Pro`, `Saas Starter Enterprise`). Include a monthly and annual price for each product if you want to support multiple billing periods.
+ - You do not need to create a free plan in Stripe. The free plan is managed within the app.
+- Setup your environment
+ - Get your [Secret API](https://dashboard.stripe.com/test/apikeys) key, and add it as an environment variable PRIVATE_STRIPE_API_KEY (`.env.local` locally, and Cloudflare environment for prod). Be sure to use test keys for development, and keep your production/live keys secret and secure.
+- Optional: theme your Stripe integration
+ - Change the colors and fonts to match your brand [here](https://dashboard.stripe.com/settings/branding)
+- Update your pricing plan data to align to your stripe data
+ - See `/src/routes/(marketing)/pricing/pricing_plans.ts` and Fill in all fields for each plan. stripe_price_id and stripe_product_id should only be omitted on a single “free” plan. Multiple free plans are not supported.
+ - The product in Stripe can contain several prices for the same product (annual, monthly, etc). The stripe_price_id you choose to put in this json will be the default we use for the checkout experience. However, if you have more prices configured for a product configured, the user can switch between them in the management portal.
+ - Set the `defaultPlanId` to the plan the user will see as their “current plan” after signup, but before subscribing to a paid plan (typically “free”). It should align to the plan with no stripe_price_id.
+ - if you want an item highlighted on `/pricing`, specify that plan ID in `/src/routes/(marketing)/pricing/+page.svelte`
+- Update your portal configuration
+ - Open [stripe portal config](https://dashboard.stripe.com/test/settings/billing/portal) and make the following changes
+ - Disallow editing email under customer information (since we allow editing in primary portal)
+ - Optional: setup a custom domain so Stripe pages use your own domain
+- Repeat steps in production environment
+
+## Deploy
+
+We have two documented options for deploying SaaS Starter: Cloudflare Pages and Vercel. However, it can be hosted anywhere you can host a SvelteKit app.
+
+Our [official demo](https://saasstarter.work) is hosted on Cloudflare Pages, and deployed each time the main branch is updated.
+
+### Deploy To Cloudflare
+
+Cloudflare Pages and Workers is one of the most popular options for deploying SvelteKit and we recommend it. [Follow Cloudflare’s instructions](https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site/#deploy-with-cloudflare-pages) to deploy in a few clicks. Be sure to select “SvelteKit” as framework, and the rest of the defaults will work.
+
+When prompted: add environment variables for your production environment (PUBLIC_SUPABASE_URL,
+PUBLIC_SUPABASE_ANON_KEY, PRIVATE_SUPABASE_SERVICE_ROLE, and PRIVATE_STRIPE_API_KEY).
+
+Optional: enable [Cloudflare Analytics](https://www.cloudflare.com/en-ca/application-services/products/analytics/) for usage metrics.
+
+### Deploy to Vercel
+
+Deploy using Vercel's deploy button:
+
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FCriticalMoments%2FCMSaasStarter&env=PUBLIC_SUPABASE_URL,PUBLIC_SUPABASE_ANON_KEY,PRIVATE_SUPABASE_SERVICE_ROLE,PRIVATE_STRIPE_API_KEY&envDescription=Each%20environment%20variable%20is%20documented%20in%20our%20quick%20start%20guide%3A%20https%3A%2F%2Fgithub.com%2FCriticalMoments%2FCMSaasStarter%3Ftab%3Dreadme-ov-file%23quick-start&envLink=https%3A%2F%2Fgithub.com%2FCriticalMoments%2FCMSaasStarter%3Ftab%3Dreadme-ov-file%23quick-start&demo-title=SaasStarter%20Demo&demo-description=A%20live%20demo%20of%20this%20template%2C%20deployed%20from%20the%20main%20branch.&demo-url=https%3A%2F%2Fsaasstarter.work&demo-image=https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F848343%2F297197975-34944c09-df72-4ac2-9099-01d25d99911b.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NTAwMzMsIm5iZiI6MTcyMTQ0OTczMywicGF0aCI6Ii84NDgzNDMvMjk3MTk3OTc1LTM0OTQ0YzA5LWRmNzItNGFjMi05MDk5LTAxZDI1ZDk5OTExYi5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQwNzIwJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MDcyMFQwNDI4NTNaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0zY2E4ZmY3YjVhMTc3YWE5YmI2MzI3YWE3MWQ2OWIzMjI3MGU2YzhmZDJjNjhlNDJhY2VjMDExMDk5ZjMyM2M4JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZhY3Rvcl9pZD0wJmtleV9pZD0wJnJlcG9faWQ9MCJ9.O8e9x5qFiij0TILjUncTOXjAs5Di2-8221K-N0YttbE)
+
+Here is a demo of of Saas Starter hosted on Vercel: [vercel.saasstarter.work](https://vercel.saasstarter.work)
+
+### Deploy Alternatives
+
+If you prefer another host you can explore alternatives:
+
+- [SvelteKit official adapters](https://kit.svelte.dev/docs/adapters) including Netlify, Vercel, and Node
+- [Community adapters](https://sveltesociety.dev/components#adapters) including Github pages, AppEngine, Azure, and more
+- [Supabase](https://supabase.com/docs/guides/getting-started/quickstarts/sveltekit) if you want one host for everything. Note: they do charge $10 a month for custom domains, unlike Cloudflare.
+
+## Setup Emailer -- Optional
+
+SaaS Starter includes email capabilities for sending emails to users and admins.
+
+These are optional and disabled by default. See [email docs](email_docs.md) for details on how to enable and customize them.
+
+## Add Your Content
+
+After the steps above, you’ll have a working version like the demo page. However, it’s not branded, and doesn’t have your content. The following checklist helps you customize the template to make a SaaS homepage for your company.
+
+- Describe your site with a name, description and base URL in in `src/config.ts:`. These values are used for SEO.
+- Content
+ - Add actual content for marketing homepage
+ - Add actual content for your blog (or delete the blog)
+ - Update all fields in `src/routes/(marketing)/blog/posts.ts`, and replace the post pages under `src/routes/(marketing)/blog/posts` to align to the urls from `posts.ts`.
+ - Alternatively remove the blog by removing the src/routes/(marketing)/blog directory, and remove any links to the blog in the header and footer. You can always bring it back later.
+ - Add any pages you want on top of our boiler plate (about, terms of service, etc). Be sure to add links to them in the header, mobile menu header, and footer as appropriate (`src/routes/(marketing)/+layout.svelte`).
+ - Note: if you add any dynamic content to the main marketing page, pricing page or blog, be sure to set `prerender = false` in the appropriate `+page.ts` file. These are currently pre-rendered and served as static assets for performance reasons, but that will break if you add server side rendering requirements.
+- Update SEO content
+ - Update title and meta description tags for every public page. We include generic ones using your site name (`src/config.ts`), but the more specific these are the better.
+ - This done automatically for blog posts from `posts.ts` metadata
+- Style
+ - Create a new DaisyUI Theme matching your brand or use one of the built in themes from DaisyUI (see `tailwind.config.js`)
+ - Update the marketing page layout `src/routes/(marketing)/+layout.svelte`: customize design, delete unwanted pages from header and footer
+ - Style: make it your own look and feel.
+ - Update the favicon in the `/static/` directory
+ - The Authentication UI should automatically update based on your DaisyUI style, but check out the login in pages, and further design tweaks can be made in `src/routes/(marketing)/login/login_config.ts` (see [Auth UI](https://supabase.com/docs/guides/auth/auth-helpers/auth-ui#customization) for options).
+- Site Search: any [prerendered](https://kit.svelte.dev/docs/page-options#prerender) content will automatically be indexed by the site search. To exclude a page, add it to `excludePaths` in `src/lib/build_index.ts`.
+- Functionality
+ - Add actual SaaS functionality!
+ - Replace the admin dashboard with real content (`/src/routes/(admin)/account/+page.svelte`).
+ - Add API endpoints and database tables as needed to deliver your SaaS product.
+
+## Community Extensions
+
+The open source community is extending and improving SaasStarter!
+
+These extensions are reference implementations of commonly needed features. We don't integrate them into the main branch to keep our dependencies minimal and simplify maintenance. However, if you need them you can cherry pick into your fork/repo:
+
+- Internationalization: [branch](https://github.com/CriticalMoments/CMSaasStarter/tree/extension/internationalization), and [instructions](https://github.com/CriticalMoments/CMSaasStarter/pull/49)
+- Dark mode theme: [branch](https://github.com/CriticalMoments/CMSaasStarter/tree/extension/dark_mode), and [instructions](https://github.com/CriticalMoments/CMSaasStarter/pull/47)
+
+### Icons Credits
+
+Homescreen Icons are from [Solar Broken Line Icons](https://www.svgrepo.com/collection/solar-broken-line-icons/) and [Solar Linear Icons](https://www.svgrepo.com/collection/solar-linear-icons) via CC Attribution License.
+
+# Sponsor
+
+We hope you enjoy SaaS Starter! If you build mobile apps, please check out its sponsor/creator, [Critical Moments](https://criticalmoments.io). We can help improve your mobile app conversions, improve your app rating, and mitigate major bugs and outages.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..240f99e
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,7 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+Please report any vulnerabilities via GitHub: https://github.com/CriticalMoments/CMSaasStarter/security
+
+This allows us to privately fix and publish the fix before public disclosure.
diff --git a/database_migration.sql b/database_migration.sql
new file mode 100644
index 0000000..d1b212e
--- /dev/null
+++ b/database_migration.sql
@@ -0,0 +1,73 @@
+-- Create a table for public profiles
+create table profiles (
+ id uuid references auth.users on delete cascade not null primary key,
+ updated_at timestamp with time zone,
+ full_name text,
+ company_name text,
+ avatar_url text,
+ website text,
+ unsubscribed boolean NOT NULL DEFAULT false
+);
+-- Set up Row Level Security (RLS)
+-- See https://supabase.com/docs/guides/auth/row-level-security for more details.
+alter table profiles
+ enable row level security;
+
+create policy "Profiles are viewable by self." on profiles
+ for select using (auth.uid() = id);
+
+create policy "Users can insert their own profile." on profiles
+ for insert with check (auth.uid() = id);
+
+create policy "Users can update own profile." on profiles
+ for update using (auth.uid() = id);
+
+-- Create Stripe Customer Table
+-- One stripe customer per user (PK enforced)
+-- Limit RLS policies -- mostly only server side access
+create table stripe_customers (
+ user_id uuid references auth.users on delete cascade not null primary key,
+ updated_at timestamp with time zone,
+ stripe_customer_id text unique
+);
+alter table stripe_customers enable row level security;
+
+-- Create a table for "Contact Us" form submissions
+-- Limit RLS policies -- only server side access
+create table contact_requests (
+ id uuid primary key default gen_random_uuid(),
+ updated_at timestamp with time zone,
+ first_name text,
+ last_name text,
+ email text,
+ phone text,
+ company_name text,
+ message_body text
+);
+alter table contact_requests enable row level security;
+
+-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
+-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
+create function public.handle_new_user()
+returns trigger as $$
+begin
+ insert into public.profiles (id, full_name, avatar_url)
+ values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
+ return new;
+end;
+$$ language plpgsql security definer;
+create trigger on_auth_user_created
+ after insert on auth.users
+ for each row execute procedure public.handle_new_user();
+
+-- Set up Storage!
+insert into storage.buckets (id, name)
+ values ('avatars', 'avatars');
+
+-- Set up access controls for storage.
+-- See https://supabase.com/docs/guides/storage#policy-examples for more details.
+create policy "Avatar images are publicly accessible." on storage.objects
+ for select using (bucket_id = 'avatars');
+
+create policy "Anyone can upload an avatar." on storage.objects
+ for insert with check (bucket_id = 'avatars');
diff --git a/email_docs.md b/email_docs.md
new file mode 100644
index 0000000..83c122a
--- /dev/null
+++ b/email_docs.md
@@ -0,0 +1,45 @@
+# Email Setup
+
+SaaS Starter includes email capabilities for sending emails to users, and admins.
+
+There are three types of emails:
+
+- Admin emails: sent to a static admin email address, useful for monitoring app activity like new signups and contact-us form submissions.
+- User emails: sent to the user's email address. For example: a welcome email.
+- Auth emails: verifing the user's email address and magic links. Auth emails are covered in the main README setup docs, and not covered here.
+
+## Set Up Email
+
+To enable email capabilities, set the following environment variables:
+
+**Important**: The template includes a welcome email, which will be enabled once you set your Resend API key. You should customize the email to fit your brand and content or remove it **BEFORE** you enable the email with environment variables. See below.
+
+- `PRIVATE_RESEND_API_KEY`: a https://resend.com API key. Note, you'll need to verify your 'from' domain with them before you can use their service.
+- `PRIVATE_ADMIN_EMAIL`: the email address to which admin emails will be sent. If unset, admin emails will not be sent.
+ - `PRIVATE_FROM_ADMIN_EMAIL`: the email address to use as the from address for admin emails (defaults to `PRIVATE_ADMIN_EMAIL` if not set).
+
+## Customize Welcome Email
+
+SaaS Starter includes a welcome email template that you can customize to fit your brand and content. The email is sent to the user's email address when create their profile.
+
+To customize the email:
+
+- edit the properties like company name, from email, and subject in the call to sendTemplatedEmail in src/routes/(admin)/account/api/+page.server.ts
+- edit the plaintext email content in src/lib/emails/welcome_email_text.svelte
+- edit the html email content in src/lib/emails/welcome_email_html.svelte - don't forget address and preheader text which won't render in a preview, but will in the client's email client.
+
+You can also delete the welcome email by removing the call to sendTemplatedEmail in src/routes/(admin)/account/api/+page.server.ts
+
+## Adding Admin Emails
+
+Anywhere you'd like to be notified of important events, you can sendan admin email.
+
+Simply add a call to sendAdminEmail() in the appropriate place, passing a subject and body.
+
+## Adding Additional User Emails
+
+You can add more user emails. Create a template in src/lib/emails, using the welcome email as a guide. You should have both a plaintext and html version of the email (see welcome_email_text.svelte and welcome_email_html.svelte), although it will work with just one.
+
+When you want to send the email, call sendUserEmail() with the appropriate parameters, including the name of the email template.
+
+You can also use sendTemplatedEmail() to send emails to any email address.
diff --git a/local_env_template b/local_env_template
new file mode 100644
index 0000000..b2a9de9
--- /dev/null
+++ b/local_env_template
@@ -0,0 +1,12 @@
+# Supabase settings
+PUBLIC_SUPABASE_URL='https://REPLACE_ME.supabase.co'
+PUBLIC_SUPABASE_ANON_KEY='REPLACE_ME'
+PRIVATE_SUPABASE_SERVICE_ROLE='REPLACE_ME'
+
+# Stripe settings
+PRIVATE_STRIPE_API_KEY='REPLACE_ME'
+
+# settings for email - optional
+# PRIVATE_ADMIN_EMAIL='your_email@example.com'
+# PRIVATE_FROM_ADMIN_EMAIL='REPLACE_ME'
+# PRIVATE_RESEND_API_KEY='REPLACE_ME'
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..01e4440
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6468 @@
+{
+ "name": "cmsassstarter",
+ "version": "0.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "cmsassstarter",
+ "version": "0.0.1",
+ "dependencies": {
+ "@supabase/auth-helpers-sveltekit": "^0.11.0",
+ "@supabase/auth-ui-svelte": "^0.2.9",
+ "@supabase/supabase-js": "^2.33.0",
+ "resend": "^3.5.0",
+ "stripe": "^13.3.0"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.2.0",
+ "@sveltejs/kit": "^2.0.0",
+ "@sveltejs/vite-plugin-svelte": "^3.1.1",
+ "@tailwindcss/typography": "^0.5.13",
+ "@types/glob": "^8.1.0",
+ "@types/html-to-text": "^9.0.4",
+ "@types/jsdom": "^21.1.7",
+ "@typescript-eslint/eslint-plugin": "^6.20.0",
+ "@typescript-eslint/parser": "^6.19.0",
+ "autoprefixer": "^10.4.15",
+ "daisyui": "^4.7.3",
+ "eslint": "^8.28.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-svelte": "^2.30.0",
+ "fuse.js": "^7.0.0",
+ "html-to-text": "^9.0.5",
+ "jsdom": "^24.1.1",
+ "postcss": "^8.4.31",
+ "prettier": "^3.0.3",
+ "prettier-plugin-svelte": "^3.0.3",
+ "super-sitemap": "^0.15.1",
+ "svelte": "^4.0.5",
+ "svelte-check": "^3.4.3",
+ "tailwindcss": "^3.4.1",
+ "typescript": "^5.0.0",
+ "vite": "^5.0.0",
+ "vitest": "^1.0.0"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
+ "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
+ "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
+ "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
+ "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
+ "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
+ "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
+ "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
+ "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
+ "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
+ "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
+ "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
+ "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
+ "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
+ "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
+ "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
+ "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
+ "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
+ "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
+ "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
+ "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
+ "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
+ "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
+ "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
+ "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+ "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.14",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+ "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.2",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "dev": true
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@one-ini/wasm": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
+ "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.25",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
+ "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ=="
+ },
+ "node_modules/@react-email/render": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/@react-email/render/-/render-0.0.16.tgz",
+ "integrity": "sha512-wDaMy27xAq1cJHtSFptp0DTKPuV2GYhloqia95ub/DH9Dea1aWYsbdM918MOc/b/HvVS3w1z8DWzfAk13bGStQ==",
+ "dependencies": {
+ "html-to-text": "9.0.5",
+ "js-beautify": "^1.14.11",
+ "react-promise-suspense": "0.3.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
+ "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz",
+ "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz",
+ "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz",
+ "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz",
+ "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz",
+ "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz",
+ "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz",
+ "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz",
+ "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz",
+ "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz",
+ "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz",
+ "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz",
+ "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz",
+ "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz",
+ "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz",
+ "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@selderee/plugin-htmlparser2": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
+ "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "selderee": "^0.11.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
+ "node_modules/@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true
+ },
+ "node_modules/@stitches/core": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@stitches/core/-/core-1.2.8.tgz",
+ "integrity": "sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg=="
+ },
+ "node_modules/@supabase/auth-helpers-shared": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.6.3.tgz",
+ "integrity": "sha512-xYQRLFeFkL4ZfwC7p9VKcarshj3FB2QJMgJPydvOY7J5czJe6xSG5/wM1z63RmAzGbCkKg+dzpq61oeSyWiGBQ==",
+ "dependencies": {
+ "jose": "^4.14.4"
+ },
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.19.0"
+ }
+ },
+ "node_modules/@supabase/auth-helpers-sveltekit": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-sveltekit/-/auth-helpers-sveltekit-0.11.0.tgz",
+ "integrity": "sha512-m+AxtRVvEJGtnm9Amnb6c1fG9Z/DP8p3Ov7tRpDkgxNEhA75jJrMiTmBJ1oCy+JlXXuHcQ+RJGQwRHTGcTSq8g==",
+ "dependencies": {
+ "@supabase/auth-helpers-shared": "0.6.3"
+ },
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.19.0",
+ "@sveltejs/kit": "^1.15.4 || ^2.0.0"
+ }
+ },
+ "node_modules/@supabase/auth-js": {
+ "version": "2.64.2",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.64.2.tgz",
+ "integrity": "sha512-s+lkHEdGiczDrzXJ1YWt2y3bxRi+qIUnXcgkpLSrId7yjBeaXBFygNjTaoZLG02KNcYwbuZ9qkEIqmj2hF7svw==",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/auth-ui-shared": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-ui-shared/-/auth-ui-shared-0.1.8.tgz",
+ "integrity": "sha512-ouQ0DjKcEFg+0gZigFIEgu01V3e6riGZPzgVD0MJsCBNsMsiDT74+GgCEIElMUpTGkwSja3xLwdFRFgMNFKcjg==",
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.21.0"
+ }
+ },
+ "node_modules/@supabase/auth-ui-svelte": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-ui-svelte/-/auth-ui-svelte-0.2.9.tgz",
+ "integrity": "sha512-oc+SRS7ykc5FCssoqT0IiK5KF/obwnWko5ePaaMTDwUEQOavv+O8/poAh2lRTKRJCqJMqOOpMS/lUE6pHcma3g==",
+ "dependencies": {
+ "@stitches/core": "^1.2.8",
+ "@supabase/auth-ui-shared": "0.1.8",
+ "svelte": "^3.55.1"
+ },
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.21.0"
+ }
+ },
+ "node_modules/@supabase/auth-ui-svelte/node_modules/svelte": {
+ "version": "3.59.2",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
+ "integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@supabase/functions-js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.3.1.tgz",
+ "integrity": "sha512-QyzNle/rVzlOi4BbVqxLSH828VdGY1RElqGFAj+XeVypj6+PVtMlD21G8SDnsPQDtlqqTtoGRgdMlQZih5hTuw==",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/node-fetch": {
+ "version": "2.6.15",
+ "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz",
+ "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/@supabase/postgrest-js": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.15.2.tgz",
+ "integrity": "sha512-9/7pUmXExvGuEK1yZhVYXPZnLEkDTwxgMQHXLrN5BwPZZm4iUCL1YEyep/Z2lIZah8d8M433mVAUEGsihUj5KQ==",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/realtime-js": {
+ "version": "2.9.5",
+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.9.5.tgz",
+ "integrity": "sha512-TEHlGwNGGmKPdeMtca1lFTYCedrhTAv3nZVoSjrKQ+wkMmaERuCe57zkC5KSWFzLYkb5FVHW8Hrr+PX1DDwplQ==",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14",
+ "@types/phoenix": "^1.5.4",
+ "@types/ws": "^8.5.10",
+ "ws": "^8.14.2"
+ }
+ },
+ "node_modules/@supabase/storage-js": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.5.tgz",
+ "integrity": "sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/supabase-js": {
+ "version": "2.43.2",
+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.43.2.tgz",
+ "integrity": "sha512-F9CljeJBo5aPucNhrLoMnpEHi5yqNZ0vH0/CL4mGy+/Ggr7FUrYErVJisa1NptViqyhs1HGNzzwjOYG6626h8g==",
+ "dependencies": {
+ "@supabase/auth-js": "2.64.2",
+ "@supabase/functions-js": "2.3.1",
+ "@supabase/node-fetch": "2.6.15",
+ "@supabase/postgrest-js": "1.15.2",
+ "@supabase/realtime-js": "2.9.5",
+ "@supabase/storage-js": "2.5.5"
+ }
+ },
+ "node_modules/@sveltejs/adapter-auto": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.1.tgz",
+ "integrity": "sha512-/3xx8ZFCD5UBc/7AbyXkFF3HNCzWAp2xncH8HA4doGjoGQEN7PmwiRx4Y9nOzi4mqDqYYUic0gaIAE2khWWU4Q==",
+ "dev": true,
+ "dependencies": {
+ "import-meta-resolve": "^4.1.0"
+ },
+ "peerDependencies": {
+ "@sveltejs/kit": "^2.0.0"
+ }
+ },
+ "node_modules/@sveltejs/kit": {
+ "version": "2.5.10",
+ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.10.tgz",
+ "integrity": "sha512-OqoyTmFG2cYmCFAdBfW+Qxbg8m23H4dv6KqwEt7ofr/ROcfcIl3Z/VT56L22H9f0uNZyr+9Bs1eh2gedOCK9kA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@types/cookie": "^0.6.0",
+ "cookie": "^0.6.0",
+ "devalue": "^5.0.0",
+ "esm-env": "^1.0.0",
+ "import-meta-resolve": "^4.1.0",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.5",
+ "mrmime": "^2.0.0",
+ "sade": "^1.8.1",
+ "set-cookie-parser": "^2.6.0",
+ "sirv": "^2.0.4",
+ "tiny-glob": "^0.2.9"
+ },
+ "bin": {
+ "svelte-kit": "svelte-kit.js"
+ },
+ "engines": {
+ "node": ">=18.13"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "vite": "^5.0.3"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.1.tgz",
+ "integrity": "sha512-rimpFEAboBBHIlzISibg94iP09k/KYdHgVhJlcsTfn7KMBhc70jFX/GRWkRdFCc2fdnk+4+Bdfej23cMDnJS6A==",
+ "dependencies": {
+ "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
+ "debug": "^4.3.4",
+ "deepmerge": "^4.3.1",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.10",
+ "svelte-hmr": "^0.16.0",
+ "vitefu": "^0.2.5"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20"
+ },
+ "peerDependencies": {
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "vite": "^5.0.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz",
+ "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "vite": "^5.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/typography": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz",
+ "integrity": "sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==",
+ "dev": true,
+ "dependencies": {
+ "lodash.castarray": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.merge": "^4.6.2",
+ "postcss-selector-parser": "6.0.10"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || insiders"
+ }
+ },
+ "node_modules/@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
+ },
+ "node_modules/@types/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "^5.1.2",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/html-to-text": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-9.0.4.tgz",
+ "integrity": "sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==",
+ "dev": true
+ },
+ "node_modules/@types/jsdom": {
+ "version": "21.1.7",
+ "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz",
+ "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/tough-cookie": "*",
+ "parse5": "^7.0.0"
+ }
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true
+ },
+ "node_modules/@types/minimatch": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
+ "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "20.12.12",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz",
+ "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==",
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/phoenix": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.4.tgz",
+ "integrity": "sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA=="
+ },
+ "node_modules/@types/pug": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz",
+ "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
+ "dev": true
+ },
+ "node_modules/@types/semver": {
+ "version": "7.5.8",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
+ "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
+ "dev": true
+ },
+ "node_modules/@types/tough-cookie": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
+ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
+ "dev": true
+ },
+ "node_modules/@types/ws": {
+ "version": "8.5.10",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
+ "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
+ "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.5.1",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/type-utils": "6.21.0",
+ "@typescript-eslint/utils": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
+ "debug": "^4.3.4",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.4",
+ "natural-compare": "^1.4.0",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
+ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
+ "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz",
+ "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "@typescript-eslint/utils": "6.21.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
+ "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
+ "dev": true,
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
+ "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
+ "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@types/json-schema": "^7.0.12",
+ "@types/semver": "^7.5.0",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
+ "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.21.0",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true
+ },
+ "node_modules/@vitest/expect": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz",
+ "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==",
+ "dev": true,
+ "dependencies": {
+ "@vitest/spy": "1.6.0",
+ "@vitest/utils": "1.6.0",
+ "chai": "^4.3.10"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz",
+ "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==",
+ "dev": true,
+ "dependencies": {
+ "@vitest/utils": "1.6.0",
+ "p-limit": "^5.0.0",
+ "pathe": "^1.1.1"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner/node_modules/p-limit": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
+ "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@vitest/runner/node_modules/yocto-queue": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+ "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz",
+ "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==",
+ "dev": true,
+ "dependencies": {
+ "magic-string": "^0.30.5",
+ "pathe": "^1.1.1",
+ "pretty-format": "^29.7.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz",
+ "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==",
+ "dev": true,
+ "dependencies": {
+ "tinyspy": "^2.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz",
+ "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==",
+ "dev": true,
+ "dependencies": {
+ "diff-sequences": "^29.6.3",
+ "estree-walker": "^3.0.3",
+ "loupe": "^2.3.7",
+ "pretty-format": "^29.7.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
+ "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.11.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+ "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
+ "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/array-back": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
+ "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "dev": true
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.4.19",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
+ "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "browserslist": "^4.23.0",
+ "caniuse-lite": "^1.0.30001599",
+ "fraction.js": "^4.3.7",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.0",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
+ "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.23.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
+ "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001587",
+ "electron-to-chromium": "^1.4.668",
+ "node-releases": "^2.0.14",
+ "update-browserslist-db": "^1.0.13"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001621",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz",
+ "integrity": "sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
+ "node_modules/chai": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
+ "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
+ "dev": true,
+ "dependencies": {
+ "assertion-error": "^1.1.0",
+ "check-error": "^1.0.3",
+ "deep-eql": "^4.1.3",
+ "get-func-name": "^2.0.2",
+ "loupe": "^2.3.6",
+ "pathval": "^1.1.1",
+ "type-detect": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/check-error": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
+ "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
+ "dev": true,
+ "dependencies": {
+ "get-func-name": "^2.0.2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/code-red": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
+ "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15",
+ "@types/estree": "^1.0.1",
+ "acorn": "^8.10.0",
+ "estree-walker": "^3.0.3",
+ "periscopic": "^3.1.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/command-line-args": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz",
+ "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^3.1.0",
+ "find-replace": "^3.0.0",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/command-line-usage": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz",
+ "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^4.0.2",
+ "chalk": "^2.4.2",
+ "table-layout": "^1.0.2",
+ "typical": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/array-back": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz",
+ "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/command-line-usage/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/command-line-usage/node_modules/typical": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
+ "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/confbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
+ "dev": true
+ },
+ "node_modules/config-chain": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+ "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+ "dependencies": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-selector-tokenizer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
+ "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+ "dependencies": {
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cssstyle": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
+ "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
+ "dev": true,
+ "dependencies": {
+ "rrweb-cssom": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cssstyle/node_modules/rrweb-cssom": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
+ "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
+ "dev": true
+ },
+ "node_modules/culori": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz",
+ "integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/daisyui": {
+ "version": "4.11.1",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.11.1.tgz",
+ "integrity": "sha512-obT9CUbQdW6eoHwSeT5VwaRrWlwrM4OT5qlfdJ0oQlSIEYhwnEl2+L2fwu5PioLbitwuMdYC2X8I1cyy8Pf6LQ==",
+ "dev": true,
+ "dependencies": {
+ "css-selector-tokenizer": "^0.8",
+ "culori": "^3",
+ "picocolors": "^1",
+ "postcss-js": "^4"
+ },
+ "engines": {
+ "node": ">=16.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/daisyui"
+ }
+ },
+ "node_modules/data-urls": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+ "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
+ "dev": true,
+ "dependencies": {
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/data-urls/node_modules/tr46": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/data-urls/node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/data-urls/node_modules/whatwg-url": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
+ "dev": true,
+ "dependencies": {
+ "tr46": "^5.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+ "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
+ "dev": true
+ },
+ "node_modules/deep-eql": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+ "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/detect-indent": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/devalue": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.0.0.tgz",
+ "integrity": "sha512-gO+/OMXF7488D+u3ue+G7Y4AA3ZmUnB3eHJXmBTgNHvr4ZNzl36A0ZtG+XCRNYCkYx/bFmw4qtkoFLa+wSrwAA=="
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true
+ },
+ "node_modules/diff-sequences": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+ "dev": true,
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/directory-tree": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-3.5.2.tgz",
+ "integrity": "sha512-DsOqeZEHkZnZrVOJG3mE/J9M6J8PulImiC6I1ZpoprVlfno8GvLOPDMkxiJihklLK7B9aVudG463L1+S/kzjiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "command-line-args": "^5.2.0",
+ "command-line-usage": "^6.1.1"
+ },
+ "bin": {
+ "directory-tree": "bin/index.js"
+ },
+ "engines": {
+ "node": ">=10.0"
+ }
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+ "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+ },
+ "node_modules/editorconfig": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
+ "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
+ "dependencies": {
+ "@one-ini/wasm": "0.1.1",
+ "commander": "^10.0.0",
+ "minimatch": "9.0.1",
+ "semver": "^7.5.3"
+ },
+ "bin": {
+ "editorconfig": "bin/editorconfig"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/editorconfig/node_modules/commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/editorconfig/node_modules/minimatch": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
+ "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.777",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.777.tgz",
+ "integrity": "sha512-n02NCwLJ3wexLfK/yQeqfywCblZqLcXphzmid5e8yVPdtEcida7li0A5WQKghHNG0FeOMCzeFOzEbtAh5riXFw==",
+ "dev": true
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es6-promise": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
+ "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
+ "dev": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
+ "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.20.2",
+ "@esbuild/android-arm": "0.20.2",
+ "@esbuild/android-arm64": "0.20.2",
+ "@esbuild/android-x64": "0.20.2",
+ "@esbuild/darwin-arm64": "0.20.2",
+ "@esbuild/darwin-x64": "0.20.2",
+ "@esbuild/freebsd-arm64": "0.20.2",
+ "@esbuild/freebsd-x64": "0.20.2",
+ "@esbuild/linux-arm": "0.20.2",
+ "@esbuild/linux-arm64": "0.20.2",
+ "@esbuild/linux-ia32": "0.20.2",
+ "@esbuild/linux-loong64": "0.20.2",
+ "@esbuild/linux-mips64el": "0.20.2",
+ "@esbuild/linux-ppc64": "0.20.2",
+ "@esbuild/linux-riscv64": "0.20.2",
+ "@esbuild/linux-s390x": "0.20.2",
+ "@esbuild/linux-x64": "0.20.2",
+ "@esbuild/netbsd-x64": "0.20.2",
+ "@esbuild/openbsd-x64": "0.20.2",
+ "@esbuild/sunos-x64": "0.20.2",
+ "@esbuild/win32-arm64": "0.20.2",
+ "@esbuild/win32-ia32": "0.20.2",
+ "@esbuild/win32-x64": "0.20.2"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+ "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+ "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.0",
+ "@humanwhocodes/config-array": "^0.11.14",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-compat-utils": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz",
+ "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "eslint": ">=6.0.0"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+ "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-svelte": {
+ "version": "2.39.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.39.0.tgz",
+ "integrity": "sha512-FXktBLXsrxbA+6ZvJK2z/sQOrUKyzSg3fNWK5h0reSCjr2fjAsc9ai/s/JvSl4Hgvz3nYVtTIMwarZH5RcB7BA==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@jridgewell/sourcemap-codec": "^1.4.15",
+ "debug": "^4.3.4",
+ "eslint-compat-utils": "^0.5.0",
+ "esutils": "^2.0.3",
+ "known-css-properties": "^0.31.0",
+ "postcss": "^8.4.38",
+ "postcss-load-config": "^3.1.4",
+ "postcss-safe-parser": "^6.0.0",
+ "postcss-selector-parser": "^6.0.16",
+ "semver": "^7.6.0",
+ "svelte-eslint-parser": ">=0.36.0 <1.0.0"
+ },
+ "engines": {
+ "node": "^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ota-meshi"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0",
+ "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.112"
+ },
+ "peerDependenciesMeta": {
+ "svelte": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-svelte/node_modules/postcss-selector-parser": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz",
+ "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/eslint/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/esm-env": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
+ "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA=="
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+ "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^8.0.1",
+ "human-signals": "^5.0.0",
+ "is-stream": "^3.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^5.1.0",
+ "onetime": "^6.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.17"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fast-xml-parser": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz",
+ "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/naturalintelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "strnum": "^1.0.5"
+ },
+ "bin": {
+ "fxparser": "src/cli/cli.js"
+ }
+ },
+ "node_modules/fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-replace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
+ "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
+ "dev": true
+ },
+ "node_modules/foreground-child": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
+ "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/fuse.js": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz",
+ "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/get-func-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
+ "dev": true,
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalyzer": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
+ "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globrex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
+ "dev": true,
+ "dependencies": {
+ "whatwg-encoding": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/html-to-text": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
+ "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
+ "dependencies": {
+ "@selderee/plugin-htmlparser2": "^0.11.0",
+ "deepmerge": "^4.3.1",
+ "dom-serializer": "^2.0.0",
+ "htmlparser2": "^8.0.2",
+ "selderee": "^0.11.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "entities": "^4.4.0"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "dev": true,
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+ "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+ "dev": true,
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+ "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=16.17.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/import-meta-resolve": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
+ "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+ "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+ "dev": true
+ },
+ "node_modules/is-reference": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
+ "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+ },
+ "node_modules/jackspeak": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz",
+ "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
+ "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
+ "dev": true,
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/jose": {
+ "version": "4.15.5",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz",
+ "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/js-beautify": {
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz",
+ "integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==",
+ "dependencies": {
+ "config-chain": "^1.1.13",
+ "editorconfig": "^1.0.4",
+ "glob": "^10.3.3",
+ "js-cookie": "^3.0.5",
+ "nopt": "^7.2.0"
+ },
+ "bin": {
+ "css-beautify": "js/bin/css-beautify.js",
+ "html-beautify": "js/bin/html-beautify.js",
+ "js-beautify": "js/bin/js-beautify.js"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/js-beautify/node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/js-beautify/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/js-cookie": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
+ "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz",
+ "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsdom": {
+ "version": "24.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz",
+ "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==",
+ "dev": true,
+ "dependencies": {
+ "cssstyle": "^4.0.1",
+ "data-urls": "^5.0.0",
+ "decimal.js": "^10.4.3",
+ "form-data": "^4.0.0",
+ "html-encoding-sniffer": "^4.0.0",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.5",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.12",
+ "parse5": "^7.1.2",
+ "rrweb-cssom": "^0.7.1",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.1.4",
+ "w3c-xmlserializer": "^5.0.0",
+ "webidl-conversions": "^7.0.0",
+ "whatwg-encoding": "^3.1.1",
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0",
+ "ws": "^8.18.0",
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "canvas": "^2.11.2"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jsdom/node_modules/tr46": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/jsdom/node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/jsdom/node_modules/whatwg-url": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
+ "dev": true,
+ "dependencies": {
+ "tr46": "^5.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/known-css-properties": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.31.0.tgz",
+ "integrity": "sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==",
+ "dev": true
+ },
+ "node_modules/leac": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
+ "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
+ "node_modules/local-pkg": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
+ "dev": true,
+ "dependencies": {
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/locate-character": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.castarray": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
+ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
+ "dev": true
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "peer": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/loose-envify/node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "peer": true
+ },
+ "node_modules/loupe": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
+ "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
+ "dev": true,
+ "dependencies": {
+ "get-func-name": "^2.0.1"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
+ "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
+ "engines": {
+ "node": "14 || >=16.14"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.10",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
+ "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
+ "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mlly": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz",
+ "integrity": "sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.11.3",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.1.0",
+ "ufo": "^1.5.3"
+ }
+ },
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mrmime": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
+ "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
+ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
+ "dev": true
+ },
+ "node_modules/nopt": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
+ "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
+ "dependencies": {
+ "abbrev": "^2.0.0"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
+ "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nwsapi": {
+ "version": "2.2.12",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz",
+ "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==",
+ "dev": true
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+ "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
+ "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+ "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "dev": true,
+ "dependencies": {
+ "entities": "^4.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parseley": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
+ "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
+ "dependencies": {
+ "leac": "^0.6.0",
+ "peberminta": "^0.9.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true
+ },
+ "node_modules/pathval": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/peberminta": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
+ "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
+ "node_modules/periscopic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
+ "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^3.0.0",
+ "is-reference": "^3.0.0"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pkg-types": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz",
+ "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==",
+ "dev": true,
+ "dependencies": {
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.0",
+ "pathe": "^1.1.2"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.38",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+ "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.2.0"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dev": true,
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dev": true,
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+ "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+ "dev": true,
+ "dependencies": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^1.10.2"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "dev": true,
+ "dependencies": {
+ "postcss-selector-parser": "^6.0.11"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-nested/node_modules/postcss-selector-parser": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz",
+ "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-safe-parser": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
+ "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.3.3"
+ }
+ },
+ "node_modules/postcss-scss": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz",
+ "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-scss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.29"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.10",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
+ "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
+ "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-plugin-svelte": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.3.tgz",
+ "integrity": "sha512-wJq8RunyFlWco6U0WJV5wNCM7zpBFakS76UBSbmzMGpncpK98NZABaE+s7n8/APDCEVNHXC5Mpq+MLebQtsRlg==",
+ "dev": true,
+ "peerDependencies": {
+ "prettier": "^3.0.0",
+ "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
+ },
+ "node_modules/psl": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
+ "dev": true
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.12.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
+ "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
+ "dependencies": {
+ "side-channel": "^1.0.6"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "dev": true
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "dev": true
+ },
+ "node_modules/react-promise-suspense": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/react-promise-suspense/-/react-promise-suspense-0.3.4.tgz",
+ "integrity": "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==",
+ "dependencies": {
+ "fast-deep-equal": "^2.0.1"
+ }
+ },
+ "node_modules/react-promise-suspense/node_modules/fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w=="
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/reduce-flatten": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz",
+ "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true
+ },
+ "node_modules/resend": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/resend/-/resend-3.5.0.tgz",
+ "integrity": "sha512-bKu4LhXSecP6krvhfDzyDESApYdNfjirD5kykkT1xO0Cj9TKSiGh5Void4pGTs3Am+inSnp4dg0B5XzdwHBJOQ==",
+ "dependencies": {
+ "@react-email/render": "0.0.16"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz",
+ "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==",
+ "dependencies": {
+ "@types/estree": "1.0.5"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.18.0",
+ "@rollup/rollup-android-arm64": "4.18.0",
+ "@rollup/rollup-darwin-arm64": "4.18.0",
+ "@rollup/rollup-darwin-x64": "4.18.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.18.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.18.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.18.0",
+ "@rollup/rollup-linux-arm64-musl": "4.18.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.18.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.18.0",
+ "@rollup/rollup-linux-x64-gnu": "4.18.0",
+ "@rollup/rollup-linux-x64-musl": "4.18.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.18.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.18.0",
+ "@rollup/rollup-win32-x64-msvc": "4.18.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/rrweb-cssom": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
+ "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
+ "dev": true
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/sade": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
+ "dependencies": {
+ "mri": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/sander": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz",
+ "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==",
+ "dev": true,
+ "dependencies": {
+ "es6-promise": "^3.1.2",
+ "graceful-fs": "^4.1.3",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.2"
+ }
+ },
+ "node_modules/sander/node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dev": true,
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/selderee": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
+ "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
+ "dependencies": {
+ "parseley": "^0.12.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.6.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+ "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/set-cookie-parser": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
+ "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ=="
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sirv": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
+ "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sorcery": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz",
+ "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.14",
+ "buffer-crc32": "^0.2.5",
+ "minimist": "^1.2.0",
+ "sander": "^0.5.0"
+ },
+ "bin": {
+ "sorcery": "bin/sorcery"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true
+ },
+ "node_modules/std-env": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz",
+ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==",
+ "dev": true
+ },
+ "node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-literal": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz",
+ "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==",
+ "dev": true,
+ "dependencies": {
+ "js-tokens": "^9.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/stripe": {
+ "version": "13.11.0",
+ "resolved": "https://registry.npmjs.org/stripe/-/stripe-13.11.0.tgz",
+ "integrity": "sha512-yPxVJxUzP1QHhHeFnYjJl48QwDS1+5befcL7ju7+t+i88D5r0rbsL+GkCCS6zgcU+TiV5bF9eMGcKyJfLf8BZQ==",
+ "dependencies": {
+ "@types/node": ">=8.1.0",
+ "qs": "^6.11.0"
+ },
+ "engines": {
+ "node": ">=12.*"
+ }
+ },
+ "node_modules/strnum": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
+ "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/sucrase": {
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "^10.3.10",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/sucrase/node_modules/glob": {
+ "version": "10.3.16",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.16.tgz",
+ "integrity": "sha512-JDKXl1DiuuHJ6fVS2FXjownaavciiHNUU4mOvV/B793RLh05vZL1rcPnCSaOgv1hDT6RDlY7AB7ZUvFYAtPgAw==",
+ "dev": true,
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.1",
+ "minipass": "^7.0.4",
+ "path-scurry": "^1.11.0"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/super-sitemap": {
+ "version": "0.15.1",
+ "resolved": "https://registry.npmjs.org/super-sitemap/-/super-sitemap-0.15.1.tgz",
+ "integrity": "sha512-HqJvO/6qnioGSvoNM6xmSMHkM/YqZsV5sFa7YSgj6VLt5NPJL1z/t8PAgJ1tvoHckxxx9kjobS0LyuuEXH6rCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "directory-tree": "^3.5.1",
+ "fast-xml-parser": "^4.3.2"
+ },
+ "peerDependencies": {
+ "svelte": ">=4.0.0 <6.0.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/svelte": {
+ "version": "4.2.17",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.17.tgz",
+ "integrity": "sha512-N7m1YnoXtRf5wya5Gyx3TWuTddI4nAyayyIWFojiWV5IayDYNV5i2mRp/7qNGol4DtxEYxljmrbgp1HM6hUbmQ==",
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.15",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "@types/estree": "^1.0.1",
+ "acorn": "^8.9.0",
+ "aria-query": "^5.3.0",
+ "axobject-query": "^4.0.0",
+ "code-red": "^1.0.3",
+ "css-tree": "^2.3.1",
+ "estree-walker": "^3.0.3",
+ "is-reference": "^3.0.1",
+ "locate-character": "^3.0.0",
+ "magic-string": "^0.30.4",
+ "periscopic": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/svelte-check": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.7.1.tgz",
+ "integrity": "sha512-U4uJoLCzmz2o2U33c7mPDJNhRYX/DNFV11XTUDlFxaKLsO7P+40gvJHMPpoRfa24jqZfST4/G9fGNcUGMO8NAQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "chokidar": "^3.4.1",
+ "fast-glob": "^3.2.7",
+ "import-fresh": "^3.2.1",
+ "picocolors": "^1.0.0",
+ "sade": "^1.7.4",
+ "svelte-preprocess": "^5.1.3",
+ "typescript": "^5.0.3"
+ },
+ "bin": {
+ "svelte-check": "bin/svelte-check"
+ },
+ "peerDependencies": {
+ "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0"
+ }
+ },
+ "node_modules/svelte-eslint-parser": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.36.0.tgz",
+ "integrity": "sha512-/6YmUSr0FAVxW8dXNdIMydBnddPMHzaHirAZ7RrT21XYdgGGZMh0LQG6CZsvAFS4r2Y4ItUuCQc8TQ3urB30mQ==",
+ "dev": true,
+ "dependencies": {
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "postcss": "^8.4.38",
+ "postcss-scss": "^4.0.9"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ota-meshi"
+ },
+ "peerDependencies": {
+ "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.115"
+ },
+ "peerDependenciesMeta": {
+ "svelte": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/svelte-hmr": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz",
+ "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==",
+ "engines": {
+ "node": "^12.20 || ^14.13.1 || >= 16"
+ },
+ "peerDependencies": {
+ "svelte": "^3.19.0 || ^4.0.0"
+ }
+ },
+ "node_modules/svelte-preprocess": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz",
+ "integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "@types/pug": "^2.0.6",
+ "detect-indent": "^6.1.0",
+ "magic-string": "^0.30.5",
+ "sorcery": "^0.11.0",
+ "strip-indent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.10.2",
+ "coffeescript": "^2.5.1",
+ "less": "^3.11.3 || ^4.0.0",
+ "postcss": "^7 || ^8",
+ "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0",
+ "pug": "^3.0.0",
+ "sass": "^1.26.8",
+ "stylus": "^0.55.0",
+ "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0",
+ "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0",
+ "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "coffeescript": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "postcss-load-config": {
+ "optional": true
+ },
+ "pug": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+ "dev": true
+ },
+ "node_modules/table-layout": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz",
+ "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^4.0.1",
+ "deep-extend": "~0.6.0",
+ "typical": "^5.2.0",
+ "wordwrapjs": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/table-layout/node_modules/array-back": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz",
+ "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/table-layout/node_modules/typical": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
+ "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
+ "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
+ "dev": true,
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.0",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.21.0",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-load-config": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+ "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "lilconfig": "^3.0.0",
+ "yaml": "^2.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
+ "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-selector-parser": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz",
+ "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/yaml": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
+ "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
+ "dev": true,
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tiny-glob": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
+ "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
+ "dependencies": {
+ "globalyzer": "0.1.0",
+ "globrex": "^0.1.2"
+ }
+ },
+ "node_modules/tinybench": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz",
+ "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==",
+ "dev": true
+ },
+ "node_modules/tinypool": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz",
+ "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
+ "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+ "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/ts-api-utils": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+ "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "dev": true
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typical": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
+ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz",
+ "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==",
+ "dev": true
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
+ },
+ "node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
+ "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.2",
+ "picocolors": "^1.0.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dev": true,
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/vite": {
+ "version": "5.2.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
+ "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==",
+ "dependencies": {
+ "esbuild": "^0.20.1",
+ "postcss": "^8.4.38",
+ "rollup": "^4.13.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-node": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz",
+ "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==",
+ "dev": true,
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.3.4",
+ "pathe": "^1.1.1",
+ "picocolors": "^1.0.0",
+ "vite": "^5.0.0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",
+ "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitest": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz",
+ "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==",
+ "dev": true,
+ "dependencies": {
+ "@vitest/expect": "1.6.0",
+ "@vitest/runner": "1.6.0",
+ "@vitest/snapshot": "1.6.0",
+ "@vitest/spy": "1.6.0",
+ "@vitest/utils": "1.6.0",
+ "acorn-walk": "^8.3.2",
+ "chai": "^4.3.10",
+ "debug": "^4.3.4",
+ "execa": "^8.0.1",
+ "local-pkg": "^0.5.0",
+ "magic-string": "^0.30.5",
+ "pathe": "^1.1.1",
+ "picocolors": "^1.0.0",
+ "std-env": "^3.5.0",
+ "strip-literal": "^2.0.0",
+ "tinybench": "^2.5.1",
+ "tinypool": "^0.8.3",
+ "vite": "^5.0.0",
+ "vite-node": "1.6.0",
+ "why-is-node-running": "^2.2.2"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "@vitest/browser": "1.6.0",
+ "@vitest/ui": "1.6.0",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
+ "dev": true,
+ "dependencies": {
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "dev": true,
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/why-is-node-running": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
+ "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
+ "dev": true,
+ "dependencies": {
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wordwrapjs": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz",
+ "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "reduce-flatten": "^2.0.0",
+ "typical": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/wordwrapjs/node_modules/typical": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
+ "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+ "dev": true
+ },
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..5aeeec6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,54 @@
+{
+ "name": "cmsassstarter",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "test": "vitest",
+ "test_run": "vitest run",
+ "lint": "eslint .",
+ "format": "prettier --write --plugin prettier-plugin-svelte ./",
+ "format_check": "prettier --check --plugin prettier-plugin-svelte ./"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.2.0",
+ "@sveltejs/kit": "^2.0.0",
+ "@sveltejs/vite-plugin-svelte": "^3.1.1",
+ "@tailwindcss/typography": "^0.5.13",
+ "@types/glob": "^8.1.0",
+ "@types/html-to-text": "^9.0.4",
+ "@types/jsdom": "^21.1.7",
+ "@typescript-eslint/eslint-plugin": "^6.20.0",
+ "@typescript-eslint/parser": "^6.19.0",
+ "autoprefixer": "^10.4.15",
+ "daisyui": "^4.7.3",
+ "eslint": "^8.28.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-svelte": "^2.30.0",
+ "fuse.js": "^7.0.0",
+ "html-to-text": "^9.0.5",
+ "jsdom": "^24.1.1",
+ "postcss": "^8.4.31",
+ "prettier": "^3.0.3",
+ "prettier-plugin-svelte": "^3.0.3",
+ "super-sitemap": "^0.15.1",
+ "svelte": "^4.0.5",
+ "svelte-check": "^3.4.3",
+ "tailwindcss": "^3.4.1",
+ "typescript": "^5.0.0",
+ "vite": "^5.0.0",
+ "vitest": "^1.0.0"
+ },
+ "type": "module",
+ "dependencies": {
+ "@supabase/auth-helpers-sveltekit": "^0.11.0",
+ "@supabase/auth-ui-svelte": "^0.2.9",
+ "@supabase/supabase-js": "^2.33.0",
+ "resend": "^3.5.0",
+ "stripe": "^13.3.0"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..2e7af2b
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/src/DatabaseDefinitions.ts b/src/DatabaseDefinitions.ts
new file mode 100644
index 0000000..3d9122a
--- /dev/null
+++ b/src/DatabaseDefinitions.ts
@@ -0,0 +1,121 @@
+export type Json =
+ | string
+ | number
+ | boolean
+ | null
+ | { [key: string]: Json | undefined }
+ | Json[]
+
+export interface Database {
+ public: {
+ Tables: {
+ contact_requests: {
+ Row: {
+ company_name: string | null
+ email: string | null
+ first_name: string | null
+ id: string
+ last_name: string | null
+ message_body: string | null
+ phone: string | null
+ updated_at: Date | null
+ }
+ Insert: {
+ company_name?: string | null
+ email?: string | null
+ first_name?: string | null
+ id?: string
+ last_name?: string | null
+ message_body?: string | null
+ phone?: string | null
+ updated_at?: Date | null
+ }
+ Update: {
+ company_name?: string | null
+ email?: string | null
+ first_name?: string | null
+ id?: string
+ last_name?: string | null
+ message_body?: string | null
+ phone?: string | null
+ updated_at?: Date | null
+ }
+ Relationships: []
+ }
+ profiles: {
+ Row: {
+ avatar_url: string | null
+ full_name: string | null
+ id: string
+ updated_at: string | null
+ company_name: string | null
+ website: string | null
+ unsubscribed: boolean
+ }
+ Insert: {
+ avatar_url?: string | null
+ full_name?: string | null
+ id: string
+ updated_at?: Date | null
+ company_name?: string | null
+ website?: string | null
+ unsubscribed: boolean
+ }
+ Update: {
+ avatar_url?: string | null
+ full_name?: string | null
+ id?: string
+ updated_at?: string | null
+ company_name?: string | null
+ website?: string | null
+ unsubscribed: boolean
+ }
+ Relationships: [
+ {
+ foreignKeyName: "profiles_id_fkey"
+ columns: ["id"]
+ referencedRelation: "users"
+ referencedColumns: ["id"]
+ },
+ ]
+ }
+ stripe_customers: {
+ Row: {
+ stripe_customer_id: string
+ updated_at: Date | null
+ user_id: string
+ }
+ Insert: {
+ stripe_customer_id: string
+ updated_at?: Date | null
+ user_id: string
+ }
+ Update: {
+ stripe_customer_id?: string
+ updated_at?: Date | null
+ user_id?: string
+ }
+ Relationships: [
+ {
+ foreignKeyName: "stripe_customers_user_id_fkey"
+ columns: ["user_id"]
+ referencedRelation: "users"
+ referencedColumns: ["id"]
+ },
+ ]
+ }
+ }
+ Views: {
+ [_ in never]: never
+ }
+ Functions: {
+ [_ in never]: never
+ }
+ Enums: {
+ [_ in never]: never
+ }
+ CompositeTypes: {
+ [_ in never]: never
+ }
+ }
+}
diff --git a/src/ambient.d.ts b/src/ambient.d.ts
new file mode 100644
index 0000000..a637375
--- /dev/null
+++ b/src/ambient.d.ts
@@ -0,0 +1,12 @@
+declare global {
+ type FormAccountUpdateResult = {
+ errorMessage?: string
+ errorFields?: string[]
+ fullName?: string
+ companyName?: string
+ website?: string
+ email?: string
+ }
+}
+
+export {}
diff --git a/src/app.css b/src/app.css
new file mode 100644
index 0000000..09168d6
--- /dev/null
+++ b/src/app.css
@@ -0,0 +1,21 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+a {
+ @apply cursor-pointer;
+}
+
+/* Hack to temporarily solve https://github.com/supabase/auth-ui/issues/219 */
+.authBtn {
+ @apply btn;
+}
+button[disabled].authBtn {
+ font-size: 0.001px;
+ filter: brightness(65%);
+}
+button[disabled].authBtn::before {
+ font-size: 14px;
+ content: "Loading...";
+ color: oklch(var(--pc));
+}
diff --git a/src/app.d.ts b/src/app.d.ts
new file mode 100644
index 0000000..8dbcef7
--- /dev/null
+++ b/src/app.d.ts
@@ -0,0 +1,21 @@
+import { SupabaseClient, Session } from "@supabase/supabase-js"
+import { Database } from "./DatabaseDefinitions"
+
+// See https://kit.svelte.dev/docs/types#app
+// for information about these interfaces
+declare global {
+ namespace App {
+ interface Locals {
+ supabase: SupabaseClient
+ supabaseServiceRole: SupabaseClient
+ safeGetSession(): Promise<{ session: Session | null; user: User | null }>
+ }
+ interface PageData {
+ session: Session | null
+ }
+ // interface Error {}
+ // interface Platform {}
+ }
+}
+
+export {}
diff --git a/src/app.html b/src/app.html
new file mode 100644
index 0000000..101c87b
--- /dev/null
+++ b/src/app.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/src/config.ts b/src/config.ts
new file mode 100644
index 0000000..3e9351d
--- /dev/null
+++ b/src/config.ts
@@ -0,0 +1,4 @@
+export const WebsiteName: string = "SaaS Starter"
+export const WebsiteBaseUrl: string = "https://saasstarter.work"
+export const WebsiteDescription: string =
+ "Open source, fast, and free to host SaaS template. Built with SvelteKit, Supabase, Stripe, Tailwind, DaisyUI, and Postgres"
diff --git a/src/hooks.server.ts b/src/hooks.server.ts
new file mode 100644
index 0000000..0e823c3
--- /dev/null
+++ b/src/hooks.server.ts
@@ -0,0 +1,54 @@
+// src/hooks.server.ts
+import {
+ PUBLIC_SUPABASE_URL,
+ PUBLIC_SUPABASE_ANON_KEY,
+} from "$env/static/public"
+import { PRIVATE_SUPABASE_SERVICE_ROLE } from "$env/static/private"
+import { createSupabaseServerClient } from "@supabase/auth-helpers-sveltekit"
+import { createClient } from "@supabase/supabase-js"
+import type { Handle } from "@sveltejs/kit"
+
+export const handle: Handle = async ({ event, resolve }) => {
+ event.locals.supabase = createSupabaseServerClient({
+ supabaseUrl: PUBLIC_SUPABASE_URL,
+ supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
+ event,
+ })
+
+ event.locals.supabaseServiceRole = createClient(
+ PUBLIC_SUPABASE_URL,
+ PRIVATE_SUPABASE_SERVICE_ROLE,
+ { auth: { persistSession: false } },
+ )
+
+ /**
+ * Unlike `supabase.auth.getSession()`, which returns the session _without_
+ * validating the JWT, this function also calls `getUser()` to validate the
+ * JWT before returning the session.
+ */
+ event.locals.safeGetSession = async () => {
+ const {
+ data: { session },
+ } = await event.locals.supabase.auth.getSession()
+ if (!session) {
+ return { session: null, user: null }
+ }
+
+ const {
+ data: { user },
+ error,
+ } = await event.locals.supabase.auth.getUser()
+ if (error) {
+ // JWT validation has failed
+ return { session: null, user: null }
+ }
+
+ return { session, user }
+ }
+
+ return resolve(event, {
+ filterSerializedResponseHeaders(name) {
+ return name === "content-range"
+ },
+ })
+}
diff --git a/src/index.test.ts b/src/index.test.ts
new file mode 100644
index 0000000..39617cd
--- /dev/null
+++ b/src/index.test.ts
@@ -0,0 +1,7 @@
+import { describe, it, expect } from "vitest"
+
+describe("sum test", () => {
+ it("adds 1 + 2 to equal 3", () => {
+ expect(1 + 2).toBe(3)
+ })
+})
diff --git a/src/lib/build_index.ts b/src/lib/build_index.ts
new file mode 100644
index 0000000..6e7642a
--- /dev/null
+++ b/src/lib/build_index.ts
@@ -0,0 +1,77 @@
+import path from "path"
+import fs from "fs"
+import glob from "glob"
+import { convert } from "html-to-text"
+import JSDOM from "jsdom"
+import Fuse from "fuse.js"
+
+const excludePaths = ["/search"]
+
+export async function buildSearchIndex() {
+ const indexData = []
+
+ // iterate all files with html extension in ./svelte-kit/output/prerendered/pages
+ const fileRoot = path.resolve(".")
+ const pagesPath = path.join(fileRoot, ".svelte-kit/output/prerendered/pages")
+
+ const allFiles = glob.sync(path.join(pagesPath, "**/*.html"))
+ for (const file of allFiles) {
+ try {
+ const webPath = file
+ .replace(pagesPath, "")
+ .replace("/index.html", "")
+ .replace(".html", "")
+
+ // check if path is excluded
+ if (excludePaths.includes(webPath)) {
+ continue
+ }
+
+ // read the file
+ const data = fs.readFileSync(file, "utf8")
+ const plaintext = convert(data, {
+ selectors: [
+ { selector: "a", options: { ignoreHref: true, linkBrackets: false } },
+ { selector: "img", format: "skip" },
+ ],
+ })
+ const dom = new JSDOM.JSDOM(data)
+ const title =
+ dom.window.document.querySelector("title")?.innerHTML ||
+ "Page " + webPath
+ const description =
+ dom.window.document
+ .querySelector('meta[name="description"]')
+ ?.getAttribute("content") || ""
+ indexData.push({
+ title,
+ description,
+ body: plaintext,
+ path: webPath,
+ })
+ } catch (e) {
+ console.log("Blog search indexing error", file, e)
+ }
+ }
+
+ const index = Fuse.createIndex(["title", "description", "body"], indexData)
+ const jsonIndex = index.toJSON()
+ const data = { index: jsonIndex, indexData, buildTime: Date.now() }
+ return data
+}
+
+// Build search index into the output directory, for use in the build process (see vite.config.js)
+export async function buildAndCacheSearchIndex() {
+ const data = await buildSearchIndex()
+
+ const dir = path.resolve("./.svelte-kit/output/client/search")
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true })
+ }
+
+ fs.writeFileSync(
+ path.resolve("./.svelte-kit/output/client/search/api.json"),
+ JSON.stringify(data),
+ )
+ console.log("Search index built")
+}
diff --git a/src/lib/emails/welcome_email_html.svelte b/src/lib/emails/welcome_email_html.svelte
new file mode 100644
index 0000000..2dbfb0c
--- /dev/null
+++ b/src/lib/emails/welcome_email_html.svelte
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+ Simple Transactional Email
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ Welcome to {companyName}!
+
+
+ This is a quick sample of a welcome email. You can customize
+ this email to fit your needs.
+
+
+
+ Thanks for using {companyName}!
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
diff --git a/src/lib/emails/welcome_email_text.svelte b/src/lib/emails/welcome_email_text.svelte
new file mode 100644
index 0000000..b25da5a
--- /dev/null
+++ b/src/lib/emails/welcome_email_text.svelte
@@ -0,0 +1,18 @@
+
+
+Welcome to {companyName}!
+
+This is a quick sample of a welcome email. You can customize this email to fit your needs.
+
+To unsubscribe, visit: {WebsiteBaseUrl}/account/settings/change_email_subscription
diff --git a/src/lib/index.js b/src/lib/index.js
new file mode 100644
index 0000000..856f2b6
--- /dev/null
+++ b/src/lib/index.js
@@ -0,0 +1 @@
+// place files you want to import through the `$lib` alias in this folder.
diff --git a/src/lib/mailer.test.ts b/src/lib/mailer.test.ts
new file mode 100644
index 0000000..c2887fe
--- /dev/null
+++ b/src/lib/mailer.test.ts
@@ -0,0 +1,121 @@
+vi.mock("@supabase/supabase-js")
+vi.mock("$env/dynamic/private")
+vi.mock("resend")
+
+import { createClient, type User } from "@supabase/supabase-js"
+import { Resend } from "resend"
+import * as mailer from "./mailer"
+
+describe("mailer", () => {
+ const mockSend = vi.fn().mockResolvedValue({ id: "mock-email-id" })
+
+ const mockSupabaseClient = {
+ auth: {
+ admin: {
+ getUserById: vi.fn(),
+ },
+ },
+ from: vi.fn().mockReturnThis(),
+ select: vi.fn().mockReturnThis(),
+ eq: vi.fn().mockReturnThis(),
+ single: vi.fn(),
+ }
+
+ beforeEach(async () => {
+ vi.clearAllMocks()
+ const { env } = await import("$env/dynamic/private")
+ env.PRIVATE_RESEND_API_KEY = "mock_resend_api_key"
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ;(createClient as any).mockReturnValue(mockSupabaseClient)
+
+ vi.mocked(Resend).mockImplementation(
+ () =>
+ ({
+ emails: {
+ send: mockSend,
+ },
+ }) as unknown as Resend,
+ )
+ })
+
+ describe("sendUserEmail", () => {
+ const mockUser = { id: "user123", email: "user@example.com" }
+
+ it("sends welcome email", async () => {
+ mockSupabaseClient.auth.admin.getUserById.mockResolvedValue({
+ data: { user: { email_confirmed_at: new Date().toISOString() } },
+ error: null,
+ })
+
+ mockSupabaseClient.single.mockResolvedValue({
+ data: { unsubscribed: false },
+ error: null,
+ })
+
+ await mailer.sendUserEmail({
+ user: mockUser as User,
+ subject: "Test",
+ from_email: "test@example.com",
+ template_name: "welcome_email",
+ template_properties: {},
+ })
+
+ expect(mockSend).toHaveBeenCalled()
+ const email = mockSend.mock.calls[0][0]
+ expect(email.to).toEqual(["user@example.com"])
+ })
+
+ it("should not send email if user is unsubscribed", async () => {
+ const originalConsoleLog = console.log
+ console.log = vi.fn()
+
+ mockSupabaseClient.auth.admin.getUserById.mockResolvedValue({
+ data: { user: { email_confirmed_at: new Date().toISOString() } },
+ error: null,
+ })
+
+ mockSupabaseClient.single.mockResolvedValue({
+ data: { unsubscribed: true },
+ error: null,
+ })
+
+ await mailer.sendUserEmail({
+ user: mockUser as User,
+ subject: "Test",
+ from_email: "test@example.com",
+ template_name: "welcome_email",
+ template_properties: {},
+ })
+
+ expect(mockSend).not.toHaveBeenCalled()
+
+ expect(console.log).toHaveBeenCalledWith(
+ "User unsubscribed. Aborting email. ",
+ mockUser.id,
+ mockUser.email,
+ )
+
+ console.log = originalConsoleLog
+ })
+ })
+
+ describe("sendTemplatedEmail", () => {
+ it("sends templated email", async () => {
+ await mailer.sendTemplatedEmail({
+ subject: "Test subject",
+ from_email: "from@example.com",
+ to_emails: ["to@example.com"],
+ template_name: "welcome_email",
+ template_properties: {},
+ })
+
+ expect(mockSend).toHaveBeenCalled()
+ const email = mockSend.mock.calls[0][0]
+ expect(email.from).toEqual("from@example.com")
+ expect(email.to).toEqual(["to@example.com"])
+ expect(email.subject).toEqual("Test subject")
+ expect(email.text).toContain("This is a quick sample of a welcome email")
+ expect(email.html).toContain(">This is a quick sample of a welcome email")
+ })
+ })
+})
diff --git a/src/lib/mailer.ts b/src/lib/mailer.ts
new file mode 100644
index 0000000..082d966
--- /dev/null
+++ b/src/lib/mailer.ts
@@ -0,0 +1,175 @@
+import { Resend } from "resend"
+import { env } from "$env/dynamic/private"
+import { PRIVATE_SUPABASE_SERVICE_ROLE } from "$env/static/private"
+import { PUBLIC_SUPABASE_URL } from "$env/static/public"
+import { createClient, type User } from "@supabase/supabase-js"
+import type { Database } from "../DatabaseDefinitions"
+
+// Sends an email to the admin email address.
+// Does not throw errors, but logs them.
+export const sendAdminEmail = async ({
+ subject,
+ body,
+}: {
+ subject: string
+ body: string
+}) => {
+ // Check admin email is setup
+ if (!env.PRIVATE_ADMIN_EMAIL) {
+ return
+ }
+
+ try {
+ const resend = new Resend(env.PRIVATE_RESEND_API_KEY)
+ const resp = await resend.emails.send({
+ from: env.PRIVATE_FROM_ADMIN_EMAIL || env.PRIVATE_ADMIN_EMAIL,
+ to: [env.PRIVATE_ADMIN_EMAIL],
+ subject: "ADMIN_MAIL: " + subject,
+ text: body,
+ })
+
+ if (resp.error) {
+ console.log("Failed to send admin email, error:", resp.error)
+ }
+ } catch (e) {
+ console.log("Failed to send admin email, error:", e)
+ }
+}
+
+export const sendUserEmail = async ({
+ user,
+ subject,
+ from_email,
+ template_name,
+ template_properties,
+}: {
+ user: User
+ subject: string
+ from_email: string
+ template_name: string
+ template_properties: Record
+}) => {
+ const email = user.email
+ if (!email) {
+ console.log("No email for user. Aborting email. ", user.id)
+ return
+ }
+
+ // Check if the user email is verified using the full user object from service role
+ // Oauth uses email_verified, and email auth uses email_confirmed_at
+ const serverSupabase = createClient(
+ PUBLIC_SUPABASE_URL,
+ PRIVATE_SUPABASE_SERVICE_ROLE,
+ { auth: { persistSession: false } },
+ )
+ const { data: serviceUserData } = await serverSupabase.auth.admin.getUserById(
+ user.id,
+ )
+ const emailVerified =
+ serviceUserData.user?.email_confirmed_at ||
+ serviceUserData.user?.user_metadata?.email_verified
+
+ if (!emailVerified) {
+ console.log("User email not verified. Aborting email. ", user.id, email)
+ return
+ }
+
+ // Fetch user profile to check unsubscribed status
+ const { data: profile, error: profileError } = await serverSupabase
+ .from("profiles")
+ .select("unsubscribed")
+ .eq("id", user.id)
+ .single()
+
+ if (profileError) {
+ console.log("Error fetching user profile. Aborting email. ", user.id, email)
+ return
+ }
+
+ if (profile?.unsubscribed) {
+ console.log("User unsubscribed. Aborting email. ", user.id, email)
+ return
+ }
+
+ await sendTemplatedEmail({
+ subject,
+ to_emails: [email],
+ from_email,
+ template_name,
+ template_properties,
+ })
+}
+
+export const sendTemplatedEmail = async ({
+ subject,
+ to_emails,
+ from_email,
+ template_name,
+ template_properties,
+}: {
+ subject: string
+ to_emails: string[]
+ from_email: string
+ template_name: string
+ template_properties: Record
+}) => {
+ if (!env.PRIVATE_RESEND_API_KEY) {
+ // email not configured. Emails are optional so no error is thrown
+ return
+ }
+
+ let plaintextBody: string | undefined = undefined
+ try {
+ const emailTemplate = await import(
+ `./emails/${template_name}_text.svelte`
+ ).then((mod) => mod.default)
+ const { html } = emailTemplate.render(template_properties)
+ plaintextBody = html
+ } catch (e) {
+ // ignore, plaintextBody is optional
+ plaintextBody = undefined
+ }
+
+ let htmlBody: string | undefined = undefined
+ try {
+ const emailTemplate = await import(
+ `./emails/${template_name}_html.svelte`
+ ).then((mod) => mod.default)
+ const { html } = emailTemplate.render(template_properties)
+ htmlBody = html
+ } catch (e) {
+ // ignore, htmlBody is optional
+ htmlBody = undefined
+ }
+
+ if (!plaintextBody && !htmlBody) {
+ console.log(
+ "No email body: requires plaintextBody or htmlBody. Template: ",
+ template_name,
+ )
+ return
+ }
+
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const email: any = {
+ from: from_email,
+ to: to_emails,
+ subject: subject,
+ }
+ if (plaintextBody) {
+ email.text = plaintextBody
+ }
+ if (htmlBody) {
+ email.html = htmlBody
+ }
+ const resend = new Resend(env.PRIVATE_RESEND_API_KEY)
+ const resp = await resend.emails.send(email)
+
+ if (resp.error) {
+ console.log("Failed to send email, error:", resp.error)
+ }
+ } catch (e) {
+ console.log("Failed to send email, error:", e)
+ }
+}
diff --git a/src/routes/(admin)/account/(menu)/+layout.svelte b/src/routes/(admin)/account/(menu)/+layout.svelte
new file mode 100644
index 0000000..7b652d7
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/+layout.svelte
@@ -0,0 +1,142 @@
+
+
+
diff --git a/src/routes/(admin)/account/(menu)/+page.server.ts b/src/routes/(admin)/account/(menu)/+page.server.ts
new file mode 100644
index 0000000..1056d14
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/+page.server.ts
@@ -0,0 +1,11 @@
+import { redirect } from "@sveltejs/kit"
+
+export const actions = {
+ signout: async ({ locals: { supabase, safeGetSession } }) => {
+ const { session } = await safeGetSession()
+ if (session) {
+ await supabase.auth.signOut()
+ redirect(303, "/")
+ }
+ },
+}
diff --git a/src/routes/(admin)/account/(menu)/+page.svelte b/src/routes/(admin)/account/(menu)/+page.svelte
new file mode 100644
index 0000000..677f4a8
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/+page.svelte
@@ -0,0 +1,88 @@
+
+
+
+ Account
+
+
+Dashboard
+
+
+
+
Demo Content
+
+ This page is just a placeholder. Replace this page with your app's content
+ and functionality.
+
+
+
+
+
+
+
Users
+
+
+
Downloads
+
31K
+
↗︎ 546 (2%)
+
+
+
+
Users
+
4,200
+
↗︎ 40 (2%)
+
+
+
+
+
Accounts
+
+
+
New Registers
+
1,200
+
↘︎ 90 (14%)
+
+
+
+
Churned Accounts
+
42
+
↘︎ 6 (12%)
+
+
+
+
+
Revenue
+
+
+
Revenue
+
$4200
+
↗︎ $180 (4%)
+
+
+
+
New Subscribers
+
16
+
↘︎ 1 (%7)
+
+
+
diff --git a/src/routes/(admin)/account/(menu)/billing/+page.server.ts b/src/routes/(admin)/account/(menu)/billing/+page.server.ts
new file mode 100644
index 0000000..2a7e063
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/billing/+page.server.ts
@@ -0,0 +1,44 @@
+import { redirect, error } from "@sveltejs/kit"
+import {
+ getOrCreateCustomerId,
+ fetchSubscription,
+} from "../../subscription_helpers.server"
+import type { PageServerLoad } from "./$types"
+
+export const load: PageServerLoad = async ({
+ locals: { safeGetSession, supabaseServiceRole },
+}) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const { error: idError, customerId } = await getOrCreateCustomerId({
+ supabaseServiceRole,
+ session,
+ })
+ if (idError || !customerId) {
+ error(500, {
+ message: "Unknown error. If issue persists, please contact us.",
+ })
+ }
+
+ const {
+ primarySubscription,
+ hasEverHadSubscription,
+ error: fetchErr,
+ } = await fetchSubscription({
+ customerId,
+ })
+ if (fetchErr) {
+ error(500, {
+ message: "Unknown error. If issue persists, please contact us.",
+ })
+ }
+
+ return {
+ isActiveCustomer: !!primarySubscription,
+ hasEverHadSubscription,
+ currentPlanId: primarySubscription?.appSubscription?.id,
+ }
+}
diff --git a/src/routes/(admin)/account/(menu)/billing/+page.svelte b/src/routes/(admin)/account/(menu)/billing/+page.svelte
new file mode 100644
index 0000000..97f2e5a
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/billing/+page.svelte
@@ -0,0 +1,57 @@
+
+
+
+ Billing
+
+
+
+ {data.isActiveCustomer ? "Billing" : "Select a Plan"}
+
+
+
+{#if !data.isActiveCustomer}
+
+
+ {#if data.hasEverHadSubscription}
+
+ {/if}
+{:else}
+
+{/if}
diff --git a/src/routes/(admin)/account/(menu)/billing/manage/+page.server.ts b/src/routes/(admin)/account/(menu)/billing/manage/+page.server.ts
new file mode 100644
index 0000000..197b83a
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/billing/manage/+page.server.ts
@@ -0,0 +1,39 @@
+import { redirect, error } from "@sveltejs/kit"
+import { getOrCreateCustomerId } from "../../../subscription_helpers.server"
+import type { PageServerLoad } from "./$types"
+import { PRIVATE_STRIPE_API_KEY } from "$env/static/private"
+import Stripe from "stripe"
+const stripe = new Stripe(PRIVATE_STRIPE_API_KEY, { apiVersion: "2023-08-16" })
+
+export const load: PageServerLoad = async ({
+ url,
+ locals: { safeGetSession, supabaseServiceRole },
+}) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const { error: idError, customerId } = await getOrCreateCustomerId({
+ supabaseServiceRole,
+ session,
+ })
+ if (idError || !customerId) {
+ error(500, {
+ message: "Unknown error (PCID). If issue persists, please contact us.",
+ })
+ }
+
+ let portalLink
+ try {
+ const portalSession = await stripe.billingPortal.sessions.create({
+ customer: customerId,
+ return_url: `${url.origin}/account/billing`,
+ })
+ portalLink = portalSession?.url
+ } catch (e) {
+ error(500, "Unknown error (PSE). If issue persists, please contact us.")
+ }
+
+ redirect(303, portalLink ?? "/account/billing")
+}
diff --git a/src/routes/(admin)/account/(menu)/settings/+page.svelte b/src/routes/(admin)/account/(menu)/settings/+page.svelte
new file mode 100644
index 0000000..89e15d9
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/+page.svelte
@@ -0,0 +1,75 @@
+
+
+
+ Settings
+
+
+Settings
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/(admin)/account/(menu)/settings/change_email/+page.svelte b/src/routes/(admin)/account/(menu)/settings/change_email/+page.svelte
new file mode 100644
index 0000000..6a9b38f
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/change_email/+page.svelte
@@ -0,0 +1,34 @@
+
+
+
+ Change Email
+
+
+Settings
+
+
diff --git a/src/routes/(admin)/account/(menu)/settings/change_email_subscription/+page.svelte b/src/routes/(admin)/account/(menu)/settings/change_email_subscription/+page.svelte
new file mode 100644
index 0000000..8cd35a0
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/change_email_subscription/+page.svelte
@@ -0,0 +1,26 @@
+
+
+
+ Change Email Subscription
+
+
+Email Subscription
+
+
diff --git a/src/routes/(admin)/account/(menu)/settings/change_password/+page.svelte b/src/routes/(admin)/account/(menu)/settings/change_password/+page.svelte
new file mode 100644
index 0000000..fef0fb1
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/change_password/+page.svelte
@@ -0,0 +1,109 @@
+
+
+
+ Change Password
+
+
+Change Password
+
+{#if hasPassword}
+
+{:else}
+
+
+ {#if usingOAuth}
+
Set Password By Email
+
+ You use oAuth to sign in ("Sign in with Github" or similar). You can
+ continue to access your account using only oAuth if you like!
+
+ {:else}
+
Change Password By Email
+ {/if}
+
+ The button below will send you an email at {session?.user?.email} which will
+ allow you to set your password.
+
+
+
+ Sent email! Please check your inbox and use the link to set your
+ password.
+
+
+
+{/if}
diff --git a/src/routes/(admin)/account/(menu)/settings/delete_account/+page.svelte b/src/routes/(admin)/account/(menu)/settings/delete_account/+page.svelte
new file mode 100644
index 0000000..473380e
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/delete_account/+page.svelte
@@ -0,0 +1,37 @@
+
+
+
+ Delete Account
+
+
+Settings
+
+
diff --git a/src/routes/(admin)/account/(menu)/settings/edit_profile/+page.svelte b/src/routes/(admin)/account/(menu)/settings/edit_profile/+page.svelte
new file mode 100644
index 0000000..243ec1b
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/edit_profile/+page.svelte
@@ -0,0 +1,46 @@
+
+
+
+ Edit Profile
+
+
+Settings
+
+
diff --git a/src/routes/(admin)/account/(menu)/settings/reset_password/+page.svelte b/src/routes/(admin)/account/(menu)/settings/reset_password/+page.svelte
new file mode 100644
index 0000000..e8a7dcf
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/reset_password/+page.svelte
@@ -0,0 +1,37 @@
+
+
+
+ Reset Password
+
+
+Settings
+
+
diff --git a/src/routes/(admin)/account/(menu)/settings/settings_module.svelte b/src/routes/(admin)/account/(menu)/settings/settings_module.svelte
new file mode 100644
index 0000000..4541c91
--- /dev/null
+++ b/src/routes/(admin)/account/(menu)/settings/settings_module.svelte
@@ -0,0 +1,157 @@
+
+
+
+ {#if title}
+
{title}
+ {/if}
+
+
+ {#if !showSuccess}
+ {#if message}
+
+ {#if dangerous}
+
+ {/if}
+
+
{message}
+
+ {/if}
+
+ {:else}
+
+
+
{successTitle}
+
{successBody}
+
+
+
+
+ {/if}
+
+
diff --git a/src/routes/(admin)/account/+layout.server.ts b/src/routes/(admin)/account/+layout.server.ts
new file mode 100644
index 0000000..18f21b9
--- /dev/null
+++ b/src/routes/(admin)/account/+layout.server.ts
@@ -0,0 +1,20 @@
+import { redirect } from "@sveltejs/kit"
+import type { LayoutServerLoad } from "./$types"
+
+export const load: LayoutServerLoad = async ({
+ locals: { supabase, safeGetSession },
+}) => {
+ const { session } = await safeGetSession()
+
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const { data: profile } = await supabase
+ .from("profiles")
+ .select(`*`)
+ .eq("id", session.user.id)
+ .single()
+
+ return { session, profile }
+}
diff --git a/src/routes/(admin)/account/+layout.svelte b/src/routes/(admin)/account/+layout.svelte
new file mode 100644
index 0000000..468d5fd
--- /dev/null
+++ b/src/routes/(admin)/account/+layout.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/src/routes/(admin)/account/+layout.ts b/src/routes/(admin)/account/+layout.ts
new file mode 100644
index 0000000..52c667d
--- /dev/null
+++ b/src/routes/(admin)/account/+layout.ts
@@ -0,0 +1,57 @@
+import {
+ PUBLIC_SUPABASE_ANON_KEY,
+ PUBLIC_SUPABASE_URL,
+} from "$env/static/public"
+import { createSupabaseLoadClient } from "@supabase/auth-helpers-sveltekit"
+import type { Database } from "../../../DatabaseDefinitions.js"
+import { redirect } from "@sveltejs/kit"
+
+export const load = async ({ fetch, data, depends, url }) => {
+ depends("supabase:auth")
+
+ const supabase = createSupabaseLoadClient({
+ supabaseUrl: PUBLIC_SUPABASE_URL,
+ supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
+ event: { fetch },
+ serverSession: data.session,
+ })
+
+ const {
+ data: { session },
+ } = await supabase.auth.getSession()
+
+ const profile: Database["public"]["Tables"]["profiles"]["Row"] | null =
+ data.profile
+
+ const createProfilePath = "/account/create_profile"
+ const signOutPath = "/account/sign_out"
+ if (
+ profile &&
+ !_hasFullProfile(profile) &&
+ url.pathname !== createProfilePath &&
+ url.pathname !== signOutPath
+ ) {
+ redirect(303, createProfilePath)
+ }
+
+ return { supabase, session, profile }
+}
+
+export const _hasFullProfile = (
+ profile: Database["public"]["Tables"]["profiles"]["Row"] | null,
+) => {
+ if (!profile) {
+ return false
+ }
+ if (!profile.full_name) {
+ return false
+ }
+ if (!profile.company_name) {
+ return false
+ }
+ if (!profile.website) {
+ return false
+ }
+
+ return true
+}
diff --git a/src/routes/(admin)/account/api/+page.server.ts b/src/routes/(admin)/account/api/+page.server.ts
new file mode 100644
index 0000000..c8356a4
--- /dev/null
+++ b/src/routes/(admin)/account/api/+page.server.ts
@@ -0,0 +1,334 @@
+import { fail, redirect } from "@sveltejs/kit"
+import { sendAdminEmail, sendUserEmail } from "$lib/mailer"
+
+export const actions = {
+ toggleEmailSubscription: async ({ locals: { supabase, safeGetSession } }) => {
+ const { session } = await safeGetSession()
+
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const { data: currentProfile } = await supabase
+ .from("profiles")
+ .select("unsubscribed")
+ .eq("id", session.user.id)
+ .single()
+
+ const newUnsubscribedStatus = !currentProfile?.unsubscribed
+
+ const { error } = await supabase
+ .from("profiles")
+ .update({ unsubscribed: newUnsubscribedStatus })
+ .eq("id", session.user.id)
+
+ if (error) {
+ return fail(500, { message: "Failed to update subscription status" })
+ }
+
+ return {
+ unsubscribed: newUnsubscribedStatus,
+ }
+ },
+ updateEmail: async ({ request, locals: { supabase, safeGetSession } }) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const formData = await request.formData()
+ const email = formData.get("email") as string
+
+ let validationError
+ if (!email || email === "") {
+ validationError = "An email address is required"
+ }
+ // Dead simple check -- there's no standard here (which is followed),
+ // and lots of errors will be missed until we actually email to verify, so
+ // just do that
+ else if (!email.includes("@")) {
+ validationError = "A valid email address is required"
+ }
+ if (validationError) {
+ return fail(400, {
+ errorMessage: validationError,
+ errorFields: ["email"],
+ email,
+ })
+ }
+
+ // Supabase does not change the email until the user verifies both
+ // if 'Secure email change' is enabled in the Supabase dashboard
+ const { error } = await supabase.auth.updateUser({ email: email })
+
+ if (error) {
+ return fail(500, {
+ errorMessage: "Unknown error. If this persists please contact us.",
+ email,
+ })
+ }
+
+ return {
+ email,
+ }
+ },
+ updatePassword: async ({ request, locals: { supabase, safeGetSession } }) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const formData = await request.formData()
+ const newPassword1 = formData.get("newPassword1") as string
+ const newPassword2 = formData.get("newPassword2") as string
+ const currentPassword = formData.get("currentPassword") as string
+
+ // Can check if we're a "password recovery" session by checking session amr
+ // let currentPassword take priority if provided (user can use either form)
+ // @ts-expect-error: we ignore because Supabase does not maintain an AMR typedef
+ const recoveryAmr = session.user?.amr?.find((x) => x.method === "recovery")
+ const isRecoverySession = recoveryAmr && !currentPassword
+
+ // if this is password recovery session, check timestamp of recovery session
+ if (isRecoverySession) {
+ const timeSinceLogin = Date.now() - recoveryAmr.timestamp * 1000
+ if (timeSinceLogin > 1000 * 60 * 15) {
+ // 15 mins in milliseconds
+ return fail(400, {
+ errorMessage:
+ 'Recovery code expired. Please log out, then use "Forgot Password" on the sign in page to reset your password. Codes are valid for 15 minutes.',
+ errorFields: [],
+ newPassword1,
+ newPassword2,
+ currentPassword: "",
+ })
+ }
+ }
+
+ let validationError
+ const errorFields = []
+ if (!newPassword1) {
+ validationError = "You must type a new password"
+ errorFields.push("newPassword1")
+ }
+ if (!newPassword2) {
+ validationError = "You must type the new password twice"
+ errorFields.push("newPassword2")
+ }
+ if (newPassword1.length < 6) {
+ validationError = "The new password must be at least 6 charaters long"
+ errorFields.push("newPassword1")
+ }
+ if (newPassword1.length > 72) {
+ validationError = "The new password can be at most 72 charaters long"
+ errorFields.push("newPassword1")
+ }
+ if (newPassword1 != newPassword2) {
+ validationError = "The passwords don't match"
+ errorFields.push("newPassword1")
+ errorFields.push("newPassword2")
+ }
+ if (!currentPassword && !isRecoverySession) {
+ validationError =
+ "You must include your current password. If you forgot it, sign out then use 'forgot password' on the sign in page."
+ errorFields.push("currentPassword")
+ }
+ if (validationError) {
+ return fail(400, {
+ errorMessage: validationError,
+ errorFields: [...new Set(errorFields)], // unique values
+ newPassword1,
+ newPassword2,
+ currentPassword,
+ })
+ }
+
+ // Check current password is correct before updating, but only if they didn't log in with "recover" link
+ // Note: to make this truly enforced you need to contact supabase. See: https://www.reddit.com/r/Supabase/comments/12iw7o1/updating_password_in_supabase_seems_insecure/
+ // However, having the UI accessible route still verify password is still helpful, and needed once you get the setting above enabled
+ if (!isRecoverySession) {
+ const { error } = await supabase.auth.signInWithPassword({
+ email: session?.user.email || "",
+ password: currentPassword,
+ })
+ if (error) {
+ // The user was logged out because of bad password. Redirect to error page explaining.
+ redirect(303, "/login/current_password_error")
+ }
+ }
+
+ const { error } = await supabase.auth.updateUser({
+ password: newPassword1,
+ })
+ if (error) {
+ return fail(500, {
+ errorMessage: "Unknown error. If this persists please contact us.",
+ newPassword1,
+ newPassword2,
+ currentPassword,
+ })
+ }
+
+ return {
+ newPassword1,
+ newPassword2,
+ currentPassword,
+ }
+ },
+ deleteAccount: async ({
+ request,
+ locals: { supabase, supabaseServiceRole, safeGetSession },
+ }) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const formData = await request.formData()
+ const currentPassword = formData.get("currentPassword") as string
+
+ if (!currentPassword) {
+ return fail(400, {
+ errorMessage:
+ "You must provide your current password to delete your account. If you forgot it, sign out then use 'forgot password' on the sign in page.",
+ errorFields: ["currentPassword"],
+ currentPassword,
+ })
+ }
+
+ // Check current password is correct before deleting account
+ const { error: pwError } = await supabase.auth.signInWithPassword({
+ email: session?.user.email || "",
+ password: currentPassword,
+ })
+ if (pwError) {
+ // The user was logged out because of bad password. Redirect to error page explaining.
+ redirect(303, "/login/current_password_error")
+ }
+
+ const { error } = await supabaseServiceRole.auth.admin.deleteUser(
+ session.user.id,
+ true,
+ )
+ if (error) {
+ return fail(500, {
+ errorMessage: "Unknown error. If this persists please contact us.",
+ currentPassword,
+ })
+ }
+
+ await supabase.auth.signOut()
+ redirect(303, "/")
+ },
+ updateProfile: async ({ request, locals: { supabase, safeGetSession } }) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ const formData = await request.formData()
+ const fullName = formData.get("fullName") as string
+ const companyName = formData.get("companyName") as string
+ const website = formData.get("website") as string
+
+ let validationError
+ const fieldMaxTextLength = 50
+ const errorFields = []
+ if (!fullName) {
+ validationError = "Name is required"
+ errorFields.push("fullName")
+ } else if (fullName.length > fieldMaxTextLength) {
+ validationError = `Name must be less than ${fieldMaxTextLength} characters`
+ errorFields.push("fullName")
+ }
+ if (!companyName) {
+ validationError =
+ "Company name is required. If this is a hobby project or personal app, please put your name."
+ errorFields.push("companyName")
+ } else if (companyName.length > fieldMaxTextLength) {
+ validationError = `Company name must be less than ${fieldMaxTextLength} characters`
+ errorFields.push("companyName")
+ }
+ if (!website) {
+ validationError =
+ "Company website is required. An app store URL is a good alternative if you don't have a website."
+ errorFields.push("website")
+ } else if (website.length > fieldMaxTextLength) {
+ validationError = `Company website must be less than ${fieldMaxTextLength} characters`
+ errorFields.push("website")
+ }
+ if (validationError) {
+ return fail(400, {
+ errorMessage: validationError,
+ errorFields,
+ fullName,
+ companyName,
+ website,
+ })
+ }
+
+ // To check if created or updated, check if priorProfile exists
+ const { data: priorProfile, error: priorProfileError } = await supabase
+ .from("profiles")
+ .select(`*`)
+ .eq("id", session?.user.id)
+ .single()
+
+ const { error } = await supabase
+ .from("profiles")
+ .upsert({
+ id: session?.user.id,
+ full_name: fullName,
+ company_name: companyName,
+ website: website,
+ updated_at: new Date(),
+ unsubscribed: priorProfile?.unsubscribed ?? false,
+ })
+ .select()
+
+ if (error) {
+ return fail(500, {
+ errorMessage: "Unknown error. If this persists please contact us.",
+ fullName,
+ companyName,
+ website,
+ })
+ }
+
+ // If the profile was just created, send an email to the user and admin
+ const newProfile =
+ priorProfile?.updated_at === null && priorProfileError === null
+ if (newProfile) {
+ await sendAdminEmail({
+ subject: "Profile Created",
+ body: `Profile created by ${session.user.email}\nFull name: ${fullName}\nCompany name: ${companyName}\nWebsite: ${website}`,
+ })
+
+ // Send welcome email
+ await sendUserEmail({
+ user: session.user,
+ subject: "Welcome!",
+ from_email: "no-reply@saasstarter.work",
+ template_name: "welcome_email",
+ template_properties: {
+ companyName: "SaaS Starter",
+ },
+ })
+ }
+
+ return {
+ fullName,
+ companyName,
+ website,
+ }
+ },
+ signout: async ({ locals: { supabase, safeGetSession } }) => {
+ const { session } = await safeGetSession()
+ if (session) {
+ await supabase.auth.signOut()
+ redirect(303, "/")
+ } else {
+ redirect(303, "/")
+ }
+ },
+}
diff --git a/src/routes/(admin)/account/api/page.server.test.ts b/src/routes/(admin)/account/api/page.server.test.ts
new file mode 100644
index 0000000..5d63e8d
--- /dev/null
+++ b/src/routes/(admin)/account/api/page.server.test.ts
@@ -0,0 +1,123 @@
+import { describe, it, expect, vi, beforeEach } from "vitest"
+import { actions } from "./+page.server"
+import { fail, redirect } from "@sveltejs/kit"
+
+vi.mock("@sveltejs/kit", async () => {
+ const actual = await vi.importActual("@sveltejs/kit")
+ return {
+ ...actual,
+ fail: vi.fn(),
+ redirect: vi.fn().mockImplementation(() => {
+ throw new Error("Redirect error")
+ }),
+ }
+})
+
+describe("toggleEmailSubscription", () => {
+ const mockSupabase = {
+ from: vi.fn().mockReturnThis(),
+ select: vi.fn().mockReturnThis(),
+ eq: vi.fn().mockReturnThis(),
+ single: vi.fn().mockResolvedValue({ data: null }),
+ update: vi.fn().mockReturnThis(),
+ }
+
+ const mockSafeGetSession = vi.fn()
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+ })
+
+ it("should redirect if no session", async () => {
+ mockSafeGetSession.mockResolvedValue({ session: null })
+
+ await expect(
+ actions.toggleEmailSubscription({
+ locals: {
+ supabase: mockSupabase,
+ safeGetSession: mockSafeGetSession,
+ },
+ } as any),
+ ).rejects.toThrow("Redirect")
+
+ expect(redirect).toHaveBeenCalledWith(303, "/login")
+ })
+
+ it("should toggle subscription status from false to true", async () => {
+ const mockSession = { user: { id: "user123" } }
+ mockSafeGetSession.mockResolvedValue({ session: mockSession })
+
+ // Mock the first query to get the current status
+ mockSupabase.single.mockResolvedValueOnce({ data: { unsubscribed: false } })
+
+ // Mock the update query
+ const mockUpdateChain = {
+ eq: vi.fn().mockResolvedValue({ error: null }),
+ }
+
+ mockSupabase.update.mockReturnValue(mockUpdateChain)
+
+ const result = await actions.toggleEmailSubscription({
+ locals: { supabase: mockSupabase, safeGetSession: mockSafeGetSession },
+ } as any)
+
+ expect(mockSupabase.from).toHaveBeenCalledWith("profiles")
+ expect(mockSupabase.select).toHaveBeenCalledWith("unsubscribed")
+ expect(mockSupabase.eq).toHaveBeenCalledWith("id", "user123")
+ expect(mockSupabase.single).toHaveBeenCalled()
+ expect(mockSupabase.update).toHaveBeenCalledWith({ unsubscribed: true })
+ expect(mockUpdateChain.eq).toHaveBeenCalledWith("id", "user123")
+ expect(result).toEqual({ unsubscribed: true })
+ })
+
+ it("should toggle subscription status from true to false", async () => {
+ const mockSession = { user: { id: "user123" } }
+ mockSafeGetSession.mockResolvedValue({ session: mockSession })
+
+ // Mock the first query to get the current status
+ mockSupabase.single.mockResolvedValueOnce({ data: { unsubscribed: true } })
+
+ // Mock the update query
+ const mockUpdateChain = {
+ eq: vi.fn().mockResolvedValue({ error: null }),
+ }
+
+ mockSupabase.update.mockReturnValue(mockUpdateChain)
+
+ const result = await actions.toggleEmailSubscription({
+ locals: { supabase: mockSupabase, safeGetSession: mockSafeGetSession },
+ } as any)
+
+ expect(mockSupabase.from).toHaveBeenCalledWith("profiles")
+ expect(mockSupabase.select).toHaveBeenCalledWith("unsubscribed")
+ expect(mockSupabase.eq).toHaveBeenCalledWith("id", "user123")
+ expect(mockSupabase.single).toHaveBeenCalled()
+ expect(mockSupabase.update).toHaveBeenCalledWith({ unsubscribed: false })
+ expect(mockUpdateChain.eq).toHaveBeenCalledWith("id", "user123")
+ expect(result).toEqual({ unsubscribed: false })
+ })
+
+ it("should return fail response if update operation fails", async () => {
+ const mockSession = { user: { id: "user123" } }
+ mockSafeGetSession.mockResolvedValue({ session: mockSession })
+
+ // Mock the first query to get the current status
+ mockSupabase.single.mockResolvedValueOnce({ data: { unsubscribed: false } })
+
+ // Mock the update query to return an error
+ const mockUpdateChain = {
+ eq: vi.fn().mockResolvedValue({ error: new Error("Update failed") }),
+ }
+
+ mockSupabase.update.mockReturnValue(mockUpdateChain)
+
+ await actions.toggleEmailSubscription({
+ locals: { supabase: mockSupabase, safeGetSession: mockSafeGetSession },
+ } as any)
+
+ // Check if fail was called with the correct arguments
+ expect(fail).toHaveBeenCalledWith(500, {
+ message: "Failed to update subscription status",
+ })
+ })
+})
diff --git a/src/routes/(admin)/account/create_profile/+page.svelte b/src/routes/(admin)/account/create_profile/+page.svelte
new file mode 100644
index 0000000..d71af2e
--- /dev/null
+++ b/src/routes/(admin)/account/create_profile/+page.svelte
@@ -0,0 +1,120 @@
+
+
+
+ Create Profile
+
+
+
+
+
+
Create Profile
+
+
+
+ You are logged in as {session?.user?.email}.
+
+
Sign out
+
+
+
+
diff --git a/src/routes/(admin)/account/create_profile/+page.ts b/src/routes/(admin)/account/create_profile/+page.ts
new file mode 100644
index 0000000..dea7c5f
--- /dev/null
+++ b/src/routes/(admin)/account/create_profile/+page.ts
@@ -0,0 +1,13 @@
+import { _hasFullProfile } from "../+layout.js"
+import { redirect } from "@sveltejs/kit"
+
+export async function load({ parent }) {
+ const data = await parent()
+
+ // They completed their profile! Redirect to "Select a Plan" screen.
+ if (_hasFullProfile(data?.profile)) {
+ redirect(303, "/account/select_plan")
+ }
+
+ return data
+}
diff --git a/src/routes/(admin)/account/select_plan/+page.svelte b/src/routes/(admin)/account/select_plan/+page.svelte
new file mode 100644
index 0000000..696812d
--- /dev/null
+++ b/src/routes/(admin)/account/select_plan/+page.svelte
@@ -0,0 +1,22 @@
+
+
+
+ Select a Plan
+
+
+
diff --git a/src/routes/(admin)/account/sign_out/+page.svelte b/src/routes/(admin)/account/sign_out/+page.svelte
new file mode 100644
index 0000000..15028df
--- /dev/null
+++ b/src/routes/(admin)/account/sign_out/+page.svelte
@@ -0,0 +1,18 @@
+
+
+{message}
diff --git a/src/routes/(admin)/account/subscribe/[slug]/+page.server.ts b/src/routes/(admin)/account/subscribe/[slug]/+page.server.ts
new file mode 100644
index 0000000..003f086
--- /dev/null
+++ b/src/routes/(admin)/account/subscribe/[slug]/+page.server.ts
@@ -0,0 +1,64 @@
+import { redirect, error } from "@sveltejs/kit"
+import {
+ getOrCreateCustomerId,
+ fetchSubscription,
+} from "../../subscription_helpers.server"
+import type { PageServerLoad } from "./$types"
+import { PRIVATE_STRIPE_API_KEY } from "$env/static/private"
+import Stripe from "stripe"
+const stripe = new Stripe(PRIVATE_STRIPE_API_KEY, { apiVersion: "2023-08-16" })
+
+export const load: PageServerLoad = async ({
+ params,
+ url,
+ locals: { safeGetSession, supabaseServiceRole },
+}) => {
+ const { session } = await safeGetSession()
+ if (!session) {
+ redirect(303, "/login")
+ }
+
+ if (params.slug === "free_plan") {
+ // plan with no stripe_price_id. Redirect to account home
+ redirect(303, "/account")
+ }
+
+ const { error: idError, customerId } = await getOrCreateCustomerId({
+ supabaseServiceRole,
+ session,
+ })
+ if (idError || !customerId) {
+ error(500, {
+ message: "Unknown error. If issue persists, please contact us.",
+ })
+ }
+
+ const { primarySubscription } = await fetchSubscription({
+ customerId,
+ })
+ if (primarySubscription) {
+ // User already has plan, we shouldn't let them buy another
+ redirect(303, "/account/billing")
+ }
+
+ let checkoutUrl
+ try {
+ const stripeSession = await stripe.checkout.sessions.create({
+ line_items: [
+ {
+ price: params.slug,
+ quantity: 1,
+ },
+ ],
+ customer: customerId,
+ mode: "subscription",
+ success_url: `${url.origin}/account`,
+ cancel_url: `${url.origin}/account/billing`,
+ })
+ checkoutUrl = stripeSession.url
+ } catch (e) {
+ error(500, "Unknown Error (SSE): If issue persists please contact us.")
+ }
+
+ redirect(303, checkoutUrl ?? "/pricing")
+}
diff --git a/src/routes/(admin)/account/subscription_helpers.server.ts b/src/routes/(admin)/account/subscription_helpers.server.ts
new file mode 100644
index 0000000..372ea90
--- /dev/null
+++ b/src/routes/(admin)/account/subscription_helpers.server.ts
@@ -0,0 +1,130 @@
+import type { SupabaseClient, Session } from "@supabase/supabase-js"
+import type { Database } from "../../../DatabaseDefinitions"
+
+import { pricingPlans } from "../../(marketing)/pricing/pricing_plans"
+import { PRIVATE_STRIPE_API_KEY } from "$env/static/private"
+import Stripe from "stripe"
+const stripe = new Stripe(PRIVATE_STRIPE_API_KEY, { apiVersion: "2023-08-16" })
+
+export const getOrCreateCustomerId = async ({
+ supabaseServiceRole,
+ session,
+}: {
+ supabaseServiceRole: SupabaseClient
+ session: Session
+}) => {
+ const { data: dbCustomer, error } = await supabaseServiceRole
+ .from("stripe_customers")
+ .select("stripe_customer_id")
+ .eq("user_id", session.user.id)
+ .single()
+
+ if (error && error.code != "PGRST116") {
+ // PGRST116 == no rows
+ return { error: error }
+ }
+
+ if (dbCustomer?.stripe_customer_id) {
+ return { customerId: dbCustomer.stripe_customer_id }
+ }
+
+ // Fetch data needed to create customer
+ const { data: profile, error: profileError } = await supabaseServiceRole
+ .from("profiles")
+ .select(`full_name, website, company_name`)
+ .eq("id", session.user.id)
+ .single()
+ if (profileError) {
+ return { error: profileError }
+ }
+
+ // Create a stripe customer
+ let customer
+ try {
+ customer = await stripe.customers.create({
+ email: session.user.email,
+ name: profile.full_name ?? "",
+ metadata: {
+ user_id: session.user.id,
+ company_name: profile.company_name ?? "",
+ website: profile.website ?? "",
+ },
+ })
+ } catch (e) {
+ return { error: e }
+ }
+
+ if (!customer.id) {
+ return { error: "Unknown stripe user creation error" }
+ }
+
+ // insert instead of upsert so we never over-write. PK ensures later attempts error.
+ const { error: insertError } = await supabaseServiceRole
+ .from("stripe_customers")
+ .insert({
+ user_id: session.user.id,
+ stripe_customer_id: customer.id,
+ updated_at: new Date(),
+ })
+
+ if (insertError) {
+ return { error: insertError }
+ }
+
+ return { customerId: customer.id }
+}
+
+export const fetchSubscription = async ({
+ customerId,
+}: {
+ customerId: string
+}) => {
+ // Fetch user's subscriptions
+ let stripeSubscriptions
+ try {
+ stripeSubscriptions = await stripe.subscriptions.list({
+ customer: customerId,
+ limit: 100,
+ status: "all",
+ })
+ } catch (e) {
+ return { error: e }
+ }
+
+ // find "primary". The user may have several old ones, we want an active one (including trials, and past_due in grace period).
+ const primaryStripeSubscription = stripeSubscriptions.data.find((x) => {
+ return (
+ x.status === "active" ||
+ x.status === "trialing" ||
+ x.status === "past_due"
+ )
+ })
+ let appSubscription = null
+ if (primaryStripeSubscription) {
+ const productId =
+ primaryStripeSubscription?.items?.data?.[0]?.price.product ?? ""
+ appSubscription = pricingPlans.find((x) => {
+ return x.stripe_product_id === productId
+ })
+ if (!appSubscription) {
+ return {
+ error:
+ "Stripe subscription does not have matching app subscription in pricing_plans.ts (via product id match)",
+ }
+ }
+ }
+ let primarySubscription = null
+ if (primaryStripeSubscription && appSubscription) {
+ primarySubscription = {
+ stripeSubscription: primaryStripeSubscription,
+ appSubscription: appSubscription,
+ }
+ }
+
+ const hasEverHadSubscription = stripeSubscriptions.data.length > 0
+
+ return {
+ primarySubscription,
+ hasEverHadSubscription,
+ }
+}
diff --git a/src/routes/(marketing)/+layout.svelte b/src/routes/(marketing)/+layout.svelte
new file mode 100644
index 0000000..54b2d30
--- /dev/null
+++ b/src/routes/(marketing)/+layout.svelte
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/(marketing)/+page.svelte b/src/routes/(marketing)/+page.svelte
new file mode 100644
index 0000000..7d3d344
--- /dev/null
+++ b/src/routes/(marketing)/+page.svelte
@@ -0,0 +1,431 @@
+
+
+
+ {WebsiteName}
+
+
+ {@html jsonldScript}
+
+
+
+
+
+
+ SaaS Starter Demo
+
+
+
+ The
+ open source,
+ fast, and
+ free to host
+ SaaS template
+
+
+
+
+
+
+
+
+
+
+ Explore the Features
+
+
+ And try them on this
+
+ fully functional demo
+
+
+
+
+
+ {#each features as feature}
+
+ {/each}
+
+
+
+
+
+
+
+ See it in Action
+
+
+
+
+
+
+
+
+ Our
webpage is the best example of SaaS Starter with style and real content.
+
+
+
+
+
+
+
+
diff --git a/src/routes/(marketing)/+page.ts b/src/routes/(marketing)/+page.ts
new file mode 100644
index 0000000..176ae64
--- /dev/null
+++ b/src/routes/(marketing)/+page.ts
@@ -0,0 +1 @@
+export const prerender = true
diff --git a/src/routes/(marketing)/auth/callback/+server.js b/src/routes/(marketing)/auth/callback/+server.js
new file mode 100644
index 0000000..92e8b43
--- /dev/null
+++ b/src/routes/(marketing)/auth/callback/+server.js
@@ -0,0 +1,27 @@
+// src/routes/auth/callback/+server.js
+import { redirect } from "@sveltejs/kit"
+import { isAuthApiError } from "@supabase/supabase-js"
+
+export const GET = async ({ url, locals: { supabase } }) => {
+ const code = url.searchParams.get("code")
+ if (code) {
+ try {
+ await supabase.auth.exchangeCodeForSession(code)
+ } catch (error) {
+ // If you open in another browser, need to redirect to login.
+ // Should not display error
+ if (isAuthApiError(error)) {
+ redirect(303, "/login/sign_in?verified=true")
+ } else {
+ throw error
+ }
+ }
+ }
+
+ const next = url.searchParams.get("next")
+ if (next) {
+ redirect(303, next)
+ }
+
+ redirect(303, "/account")
+}
diff --git a/src/routes/(marketing)/blog/(posts)/+layout.svelte b/src/routes/(marketing)/blog/(posts)/+layout.svelte
new file mode 100644
index 0000000..56e8526
--- /dev/null
+++ b/src/routes/(marketing)/blog/(posts)/+layout.svelte
@@ -0,0 +1,71 @@
+
+
+
+ {currentPost.title}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {@html jsonldScript}
+
+
+
+
+ {currentPost.parsedDate?.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ })}
+
+ {currentPost.title}
+
+
diff --git a/src/routes/(marketing)/blog/(posts)/awesome_post/+page.svelte b/src/routes/(marketing)/blog/(posts)/awesome_post/+page.svelte
new file mode 100644
index 0000000..36e36e2
--- /dev/null
+++ b/src/routes/(marketing)/blog/(posts)/awesome_post/+page.svelte
@@ -0,0 +1,26 @@
+A sample post
+
+
+ This is a sample blog post to demonstrate the blog engine. It shows some of
+ the formatting options included in the template.
+
+
+Section Titles are great
+
+As are more paragraphs.
+
+
+ Block quotes are styled
+
+
+# Code blocks work too!
+npm install
+
+
+
+ Check out more formatting options like lists, headers, and more in the tailwind/typograpy docs.
+
diff --git a/src/routes/(marketing)/blog/(posts)/example_blog_post/+page.svelte b/src/routes/(marketing)/blog/(posts)/example_blog_post/+page.svelte
new file mode 100644
index 0000000..36e36e2
--- /dev/null
+++ b/src/routes/(marketing)/blog/(posts)/example_blog_post/+page.svelte
@@ -0,0 +1,26 @@
+A sample post
+
+
+ This is a sample blog post to demonstrate the blog engine. It shows some of
+ the formatting options included in the template.
+
+
+Section Titles are great
+
+As are more paragraphs.
+
+
+ Block quotes are styled
+
+
+# Code blocks work too!
+npm install
+
+
+
+ Check out more formatting options like lists, headers, and more in the tailwind/typograpy docs.
+
diff --git a/src/routes/(marketing)/blog/(posts)/how_we_built_our_41kb_saas_website/+page.svelte b/src/routes/(marketing)/blog/(posts)/how_we_built_our_41kb_saas_website/+page.svelte
new file mode 100644
index 0000000..f2a8758
--- /dev/null
+++ b/src/routes/(marketing)/blog/(posts)/how_we_built_our_41kb_saas_website/+page.svelte
@@ -0,0 +1,35 @@
+How to use this template you to bootstrap your own site.
+
+
+ We've written a detailed blog post about how we took this template, and
+ created a real SaaS company website. Topics include:
+
+
+
+ - Optimizing the stack for performance and developer productivity
+ - Creating rich interactive animations with Svelte
+ - Creating pixel perfect designs without rasterization
+ - Speed measurements: how we kept it small and lightning fast
+
+
+Read the Blog Post
+
+
+ The blog post is over on criticalmoments.io, a page which uses this boilerplate as a starting point.
+
+
+
+ If you are looking for examples of blog posts with rich content rendered
+ inside this template, checkout the other demo posts here.
+
diff --git a/src/routes/(marketing)/blog/+layout.ts b/src/routes/(marketing)/blog/+layout.ts
new file mode 100644
index 0000000..176ae64
--- /dev/null
+++ b/src/routes/(marketing)/blog/+layout.ts
@@ -0,0 +1 @@
+export const prerender = true
diff --git a/src/routes/(marketing)/blog/+page.svelte b/src/routes/(marketing)/blog/+page.svelte
new file mode 100644
index 0000000..0d973c4
--- /dev/null
+++ b/src/routes/(marketing)/blog/+page.svelte
@@ -0,0 +1,47 @@
+
+
+
+ {blogInfo.name}
+
+
+
+
diff --git a/src/routes/(marketing)/blog/posts.ts b/src/routes/(marketing)/blog/posts.ts
new file mode 100644
index 0000000..6199262
--- /dev/null
+++ b/src/routes/(marketing)/blog/posts.ts
@@ -0,0 +1,52 @@
+export const blogInfo = {
+ name: "SaaS Starter Blog",
+ description: "A sample blog",
+}
+
+export type BlogPost = {
+ link: string
+ date: string // date is a string 'YYYY-MM-DD'
+ title: string
+ description: string
+ parsedDate?: Date // Optional because it's added dynamically
+}
+
+// Update this list with the actual blog post list
+// Create a page in the "(posts)" directory for each entry
+const blogPosts: BlogPost[] = [
+ {
+ title: "How we built a beautiful 41kb SaaS website with this template",
+ description: "How to use this template you to bootstrap your own site.",
+ link: "/blog/how_we_built_our_41kb_saas_website",
+ date: "2024-03-10",
+ },
+ {
+ title: "Example Blog Post 2",
+ description: "Even more example content!",
+ link: "/blog/awesome_post",
+ date: "2022-9-23",
+ },
+ {
+ title: "Example Blog Post",
+ description: "A sample blog post, showing our blog engine",
+ link: "/blog/example_blog_post",
+ date: "2023-03-13",
+ },
+]
+
+// Parse post dates from strings to Date objects
+for (const post of blogPosts) {
+ if (!post.parsedDate) {
+ const dateParts = post.date.split("-")
+ post.parsedDate = new Date(
+ parseInt(dateParts[0]),
+ parseInt(dateParts[1]) - 1,
+ parseInt(dateParts[2]),
+ ) // Note: months are 0-based
+ }
+}
+
+export const sortedBlogPosts = blogPosts.sort(
+ (a: BlogPost, b: BlogPost) =>
+ (b.parsedDate?.getTime() ?? 0) - (a.parsedDate?.getTime() ?? 0),
+)
diff --git a/src/routes/(marketing)/blog/rss.xml/+server.ts b/src/routes/(marketing)/blog/rss.xml/+server.ts
new file mode 100644
index 0000000..6a11fd1
--- /dev/null
+++ b/src/routes/(marketing)/blog/rss.xml/+server.ts
@@ -0,0 +1,37 @@
+import { sortedBlogPosts, blogInfo } from "../posts"
+
+const encodeXML = (str: string) =>
+ str
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'")
+
+/** @type {import('./$types').RequestHandler} */
+export function GET({ url }) {
+ const headers = {
+ "Cache-Control": "max-age=0, s-maxage=3600",
+ "Content-Type": "application/xml",
+ }
+
+ let body = `
+
+ ${blogInfo.name}
+ ${url.origin}/blog
+ ${blogInfo.description}
+ `
+ for (const post of sortedBlogPosts) {
+ body += `
+ -
+ ${encodeXML(post.title)}
+ ${encodeXML(post.description)}
+ ${url.origin + post.link}/
+ ${post.parsedDate?.toUTCString()}
+
\n`
+ }
+ body += ` \n\n`
+ return new Response(body, {
+ headers: headers,
+ })
+}
diff --git a/src/routes/(marketing)/contact_us/+page.server.ts b/src/routes/(marketing)/contact_us/+page.server.ts
new file mode 100644
index 0000000..c933b52
--- /dev/null
+++ b/src/routes/(marketing)/contact_us/+page.server.ts
@@ -0,0 +1,78 @@
+import { fail } from "@sveltejs/kit"
+import { sendAdminEmail } from "$lib/mailer.js"
+
+/** @type {import('./$types').Actions} */
+export const actions = {
+ submitContactUs: async ({ request, locals: { supabaseServiceRole } }) => {
+ const formData = await request.formData()
+ const errors: { [fieldName: string]: string } = {}
+
+ const firstName = formData.get("first_name")?.toString() ?? ""
+ if (firstName.length < 2) {
+ errors["first_name"] = "First name is required"
+ }
+ if (firstName.length > 500) {
+ errors["first_name"] = "First name too long"
+ }
+
+ const lastName = formData.get("last_name")?.toString() ?? ""
+ if (lastName.length < 2) {
+ errors["last_name"] = "Last name is required"
+ }
+ if (lastName.length > 500) {
+ errors["last_name"] = "Last name too long"
+ }
+
+ const email = formData.get("email")?.toString() ?? ""
+ if (email.length < 6) {
+ errors["email"] = "Email is required"
+ } else if (email.length > 500) {
+ errors["email"] = "Email too long"
+ } else if (!email.includes("@") || !email.includes(".")) {
+ errors["email"] = "Invalid email"
+ }
+
+ const company = formData.get("company")?.toString() ?? ""
+ if (company.length > 500) {
+ errors["company"] = "Company too long"
+ }
+
+ const phone = formData.get("phone")?.toString() ?? ""
+ if (phone.length > 100) {
+ errors["phone"] = "Phone number too long"
+ }
+
+ const message = formData.get("message")?.toString() ?? ""
+ if (message.length > 2000) {
+ errors["message"] = "Message too long (" + message.length + " of 2000)"
+ }
+
+ console.log("errors:", errors)
+ if (Object.keys(errors).length > 0) {
+ return fail(400, { errors })
+ }
+
+ // Save to database
+ const { error: insertError } = await supabaseServiceRole
+ .from("contact_requests")
+ .insert({
+ first_name: firstName,
+ last_name: lastName,
+ email,
+ company_name: company,
+ phone,
+ message_body: message,
+ updated_at: new Date(),
+ })
+
+ if (insertError) {
+ return fail(500, { errors: { _: "Error saving" } })
+ }
+
+ // Send email to admin
+ await sendAdminEmail({
+ subject: "New contact request",
+ body: `New contact request from ${firstName} ${lastName}.\n\nEmail: ${email}\n\nPhone: ${phone}\n\nCompany: ${company}\n\nMessage: ${message}`,
+ })
+ },
+}
diff --git a/src/routes/(marketing)/contact_us/+page.svelte b/src/routes/(marketing)/contact_us/+page.svelte
new file mode 100644
index 0000000..195bb21
--- /dev/null
+++ b/src/routes/(marketing)/contact_us/+page.svelte
@@ -0,0 +1,156 @@
+
+
+
+
+
+
Contact Us
+
Talk to one of our service professionals to:
+
+ - Get a live demo
+ - Discuss your specific needs
+ - Get a quote
+ - Answer any technical questions you have
+
+
Once you complete the form, we'll reach out to you! *
+
+ *Not really for this demo page, but you should say something like that
+ 😉
+
+
+
+
+
+ {#if showSuccess}
+
+
+
Thank you!
+
We've received your message and will be in touch soon.
+
+
+ {:else}
+
+ {/if}
+
+
diff --git a/src/routes/(marketing)/login/+layout.server.ts b/src/routes/(marketing)/login/+layout.server.ts
new file mode 100644
index 0000000..c844cfa
--- /dev/null
+++ b/src/routes/(marketing)/login/+layout.server.ts
@@ -0,0 +1,19 @@
+import { redirect } from "@sveltejs/kit"
+import type { LayoutServerLoad } from "./$types"
+
+export const load: LayoutServerLoad = async ({
+ url,
+ locals: { safeGetSession },
+}) => {
+ const { session } = await safeGetSession()
+
+ // if the user is already logged in return them to the account page
+ if (session) {
+ redirect(303, "/account")
+ }
+
+ return {
+ session: session,
+ url: url.origin,
+ }
+}
diff --git a/src/routes/(marketing)/login/+layout.svelte b/src/routes/(marketing)/login/+layout.svelte
new file mode 100644
index 0000000..9e5239c
--- /dev/null
+++ b/src/routes/(marketing)/login/+layout.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ 🍪 Logging in uses Cookies 🍪
+
+
+
diff --git a/src/routes/(marketing)/login/+layout.ts b/src/routes/(marketing)/login/+layout.ts
new file mode 100644
index 0000000..b6324fa
--- /dev/null
+++ b/src/routes/(marketing)/login/+layout.ts
@@ -0,0 +1,20 @@
+import {
+ PUBLIC_SUPABASE_ANON_KEY,
+ PUBLIC_SUPABASE_URL,
+} from "$env/static/public"
+import { createSupabaseLoadClient } from "@supabase/auth-helpers-sveltekit"
+
+export const load = async ({ fetch, data, depends }) => {
+ depends("supabase:auth")
+
+ const supabase = createSupabaseLoadClient({
+ supabaseUrl: PUBLIC_SUPABASE_URL,
+ supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
+ event: { fetch },
+ serverSession: data.session,
+ })
+
+ const url = data.url
+
+ return { supabase, url }
+}
diff --git a/src/routes/(marketing)/login/+page.svelte b/src/routes/(marketing)/login/+page.svelte
new file mode 100644
index 0000000..adfdec4
--- /dev/null
+++ b/src/routes/(marketing)/login/+page.svelte
@@ -0,0 +1,16 @@
+
+ Log In
+
+
+
diff --git a/src/routes/(marketing)/login/current_password_error/+page.svelte b/src/routes/(marketing)/login/current_password_error/+page.svelte
new file mode 100644
index 0000000..b15e245
--- /dev/null
+++ b/src/routes/(marketing)/login/current_password_error/+page.svelte
@@ -0,0 +1,19 @@
+
+ Current Password Incorrect
+
+
+Current Password Incorrect
+
+
+ You attempted edit your account with an incorrect current password, and have
+ been logged out.
+
+
+ If you remember your password sign in and try again.
+
+
+ If you forget your password reset it.
+
diff --git a/src/routes/(marketing)/login/forgot_password/+page.server.ts b/src/routes/(marketing)/login/forgot_password/+page.server.ts
new file mode 100644
index 0000000..62ad4e4
--- /dev/null
+++ b/src/routes/(marketing)/login/forgot_password/+page.server.ts
@@ -0,0 +1 @@
+export const ssr = false
diff --git a/src/routes/(marketing)/login/forgot_password/+page.svelte b/src/routes/(marketing)/login/forgot_password/+page.svelte
new file mode 100644
index 0000000..a8baa1f
--- /dev/null
+++ b/src/routes/(marketing)/login/forgot_password/+page.svelte
@@ -0,0 +1,26 @@
+
+
+
+ Forgot Password
+
+
+Forgot Password
+
+
+ Remember your password?
Sign in.
+
diff --git a/src/routes/(marketing)/login/login_config.ts b/src/routes/(marketing)/login/login_config.ts
new file mode 100644
index 0000000..76ea58c
--- /dev/null
+++ b/src/routes/(marketing)/login/login_config.ts
@@ -0,0 +1,30 @@
+import { ThemeSupa } from "@supabase/auth-ui-shared"
+import type { Provider } from "@supabase/supabase-js"
+
+export const oauthProviders = ["github"] as Provider[]
+
+// use the css variables from DaisyUI to style Supabase auth template
+export const sharedAppearance = {
+ theme: ThemeSupa,
+ variables: {
+ default: {
+ colors: {
+ brand: "oklch(var(--p))",
+ brandAccent: "oklch(var(--ac))",
+ inputText: "oklch(var(--n))",
+ brandButtonText: "oklch(var(--pc))",
+ messageText: "oklch(var(--b))",
+ dividerBackground: "oklch(var(--n))",
+ inputLabelText: "oklch(var(--n))",
+ defaultButtonText: "oklch(var(--n))",
+ anchorTextColor: "oklch(var(--p))",
+ },
+ fontSizes: {
+ baseInputSize: "16px",
+ },
+ },
+ },
+ className: {
+ button: "authBtn",
+ },
+}
diff --git a/src/routes/(marketing)/login/sign_in/+page.server.ts b/src/routes/(marketing)/login/sign_in/+page.server.ts
new file mode 100644
index 0000000..62ad4e4
--- /dev/null
+++ b/src/routes/(marketing)/login/sign_in/+page.server.ts
@@ -0,0 +1 @@
+export const ssr = false
diff --git a/src/routes/(marketing)/login/sign_in/+page.svelte b/src/routes/(marketing)/login/sign_in/+page.svelte
new file mode 100644
index 0000000..6457d88
--- /dev/null
+++ b/src/routes/(marketing)/login/sign_in/+page.svelte
@@ -0,0 +1,63 @@
+
+
+
+ Sign in
+
+
+{#if $page.url.searchParams.get("verified") == "true"}
+
+
+
Email verified! Please sign in.
+
+{/if}
+Sign In
+
+
+
+ Don't have an account?
Sign up.
+
diff --git a/src/routes/(marketing)/login/sign_up/+page.server.ts b/src/routes/(marketing)/login/sign_up/+page.server.ts
new file mode 100644
index 0000000..62ad4e4
--- /dev/null
+++ b/src/routes/(marketing)/login/sign_up/+page.server.ts
@@ -0,0 +1 @@
+export const ssr = false
diff --git a/src/routes/(marketing)/login/sign_up/+page.svelte b/src/routes/(marketing)/login/sign_up/+page.svelte
new file mode 100644
index 0000000..15b9c51
--- /dev/null
+++ b/src/routes/(marketing)/login/sign_up/+page.svelte
@@ -0,0 +1,25 @@
+
+
+
+ Sign up
+
+
+Sign Up
+
+
+ Have an account?
Sign in.
+
diff --git a/src/routes/(marketing)/pricing/+page.svelte b/src/routes/(marketing)/pricing/+page.svelte
new file mode 100644
index 0000000..0d3ba51
--- /dev/null
+++ b/src/routes/(marketing)/pricing/+page.svelte
@@ -0,0 +1,215 @@
+
+
+
+ Pricing
+
+
+
+
+
Pricing
+
+ Totally free, scale to millions of users
+
+
+
+
+
Pricing FAQ
+
+
+
+
+
+ Is this template free to use?
+
+
+
Yup! This template is free to use for any project.
+
+
+
+
+
+ Why does a free template have a pricing page?
+
+
+
+ The pricing page is part of the boilerplate. It shows how the
+ pricing page integrates into the billing portal and the Stripe
+ Checkout flows.
+
+
+
+
+
+
+ What license is the template under?
+
+
+
The template is under the MIT license.
+
+
+
+
+
+ Can I try out purchase flows without real a credit card?
+
+
+
+ Our demo page SaasStarter.work has a functional demo page, using Stripe's test environment.
+
+
+ You can use the credit card number 4242 4242 4242 4242 with any
+ future expiry date to test the payment and upgrade flows.
+
+
+
+
+
+
+
+
+
+
+
Plan Features
+
+ Example feature table
+
+
+
+
+
+
+ |
+ Free |
+ Pro |
+
+
+
+ {#each planFeatures as feature}
+ {#if feature.header}
+
+ {feature.name} |
+
+ {:else}
+
+ {feature.name} |
+
+ {#if feature.freeString}
+ {feature.freeString}
+ {:else if feature.freeIncluded}
+
+ {:else}
+
+ {/if}
+ |
+
+ {#if feature.proString}
+ {feature.proString}
+ {:else if feature.proIncluded}
+
+ {:else}
+
+ {/if}
+ |
+
+ {/if}
+ {/each}
+
+
+
+
+
diff --git a/src/routes/(marketing)/pricing/+page.ts b/src/routes/(marketing)/pricing/+page.ts
new file mode 100644
index 0000000..176ae64
--- /dev/null
+++ b/src/routes/(marketing)/pricing/+page.ts
@@ -0,0 +1 @@
+export const prerender = true
diff --git a/src/routes/(marketing)/pricing/pricing_module.svelte b/src/routes/(marketing)/pricing/pricing_module.svelte
new file mode 100644
index 0000000..5cb25ec
--- /dev/null
+++ b/src/routes/(marketing)/pricing/pricing_module.svelte
@@ -0,0 +1,60 @@
+
+
+
+ {#each pricingPlans as plan}
+
+
+
{plan.name}
+
+ {plan.description}
+
+
+ Plan Includes:
+
+ {#each plan.features as feature}
+ - {feature}
+ {/each}
+
+
+
+
+
{plan.price}
+
{plan.priceIntervalName}
+
+ {#if plan.id === currentPlanId}
+
+ Current Plan
+
+ {:else}
+
+ {callToAction}
+
+ {/if}
+
+
+
+
+ {/each}
+
diff --git a/src/routes/(marketing)/pricing/pricing_plans.ts b/src/routes/(marketing)/pricing/pricing_plans.ts
new file mode 100644
index 0000000..e214ce5
--- /dev/null
+++ b/src/routes/(marketing)/pricing/pricing_plans.ts
@@ -0,0 +1,43 @@
+export const defaultPlanId = "free"
+
+export const pricingPlans = [
+ {
+ id: "free",
+ name: "Free",
+ description: "A free plan to get you started!",
+ price: "$0",
+ priceIntervalName: "per month",
+ stripe_price_id: null,
+ features: ["MIT Licence", "Fast Performance", "Stripe Integration"],
+ },
+ {
+ id: "pro",
+ name: "Pro",
+ description:
+ "A plan to test the purchase experience. Try buying this with the test credit card 4242424242424242.",
+ price: "$5",
+ priceIntervalName: "per month",
+ stripe_price_id: "price_1NkdZCHMjzZ8mGZnRSjUm4yA",
+ stripe_product_id: "prod_OXj1CcemGMWOlU",
+ features: [
+ "Everything in Free",
+ "Support us with fake money",
+ "Test the purchase experience",
+ ],
+ },
+ {
+ id: "enterprise",
+ name: "Enterprise",
+ description:
+ "A plan to test the upgrade experience. Try buying this with the test credit card 4242424242424242.",
+ price: "$15",
+ priceIntervalName: "per month",
+ stripe_price_id: "price_1Nkda2HMjzZ8mGZn4sKvbDAV",
+ stripe_product_id: "prod_OXj20YNpHYOXi7",
+ features: [
+ "Everything in Pro",
+ "Try the 'upgrade plan' UX",
+ "Still actually free!",
+ ],
+ },
+]
diff --git a/src/routes/(marketing)/search/+page.server.ts b/src/routes/(marketing)/search/+page.server.ts
new file mode 100644
index 0000000..176ae64
--- /dev/null
+++ b/src/routes/(marketing)/search/+page.server.ts
@@ -0,0 +1 @@
+export const prerender = true
diff --git a/src/routes/(marketing)/search/+page.svelte b/src/routes/(marketing)/search/+page.svelte
new file mode 100644
index 0000000..775b98e
--- /dev/null
+++ b/src/routes/(marketing)/search/+page.svelte
@@ -0,0 +1,156 @@
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+ {#if loading && searchQuery.length > 0}
+
Loading...
+ {/if}
+
+ {#if error}
+
+ Error connecting to search. Please try again later.
+
+ {/if}
+
+ {#if !loading && searchQuery.length > 0 && results.length === 0 && !error}
+
No results found
+ {#if dev}
+
+ Development mode only message: if you're missing content, rebuild your
+ local search index with `npm run build`
+
+ {/if}
+ {/if}
+
+
+
+
+
diff --git a/src/routes/(marketing)/search/api.json/+server.ts b/src/routes/(marketing)/search/api.json/+server.ts
new file mode 100644
index 0000000..de285e0
--- /dev/null
+++ b/src/routes/(marketing)/search/api.json/+server.ts
@@ -0,0 +1,14 @@
+import { dev } from "$app/environment"
+import { error } from "@sveltejs/kit"
+
+export async function GET() {
+ // only build search index in dev mode. It will be pre-built in production (see vite.config.js)
+ if (dev) {
+ const { buildSearchIndex } = await import("$lib/build_index")
+ const searchData = await buildSearchIndex()
+ return new Response(JSON.stringify(searchData), {
+ headers: { "Content-Type": "application/json" },
+ })
+ }
+ error(404, "Search index not found")
+}
diff --git a/src/routes/(marketing)/sitemap.xml/+server.ts b/src/routes/(marketing)/sitemap.xml/+server.ts
new file mode 100644
index 0000000..8ed4a5a
--- /dev/null
+++ b/src/routes/(marketing)/sitemap.xml/+server.ts
@@ -0,0 +1,14 @@
+import type { RequestHandler } from "@sveltejs/kit"
+import * as sitemap from "super-sitemap"
+import { WebsiteBaseUrl } from "../../../config"
+
+export const prerender = true
+
+export const GET: RequestHandler = async () => {
+ return await sitemap.response({
+ origin: WebsiteBaseUrl,
+ excludeRoutePatterns: [
+ ".*\\(admin\\).*", // i.e. exclude routes within admin group
+ ],
+ })
+}
diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte
new file mode 100644
index 0000000..b744a48
--- /dev/null
+++ b/src/routes/+error.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
+
This is embarrassing...
+
There was an error: {$page?.error?.message}
+
+
+
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
new file mode 100644
index 0000000..a9e8d25
--- /dev/null
+++ b/src/routes/+layout.svelte
@@ -0,0 +1,21 @@
+
+
+{#if $navigating}
+
+
+{/if}
+
diff --git a/static/favicon.png b/static/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..7841249d5ee424dba7d0a168d4f1f51bd01e2644
GIT binary patch
literal 5420
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
WPIZYS?SJGZKvhvwp-j#?
\ No newline at end of file
diff --git a/static/images/example-home.png b/static/images/example-home.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff2e9f328abd2e3697958e87aeb9c6a9c3ff8b96
GIT binary patch
literal 31320
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
Zw!z(JLRIg|&-|&Sqp7b^p>7-ezW|cKXO;i}
literal 0
HcmV?d00001
diff --git a/static/images/rss.svg b/static/images/rss.svg
new file mode 100644
index 0000000..14a6f3f
--- /dev/null
+++ b/static/images/rss.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/robots.txt b/static/robots.txt
new file mode 100644
index 0000000..4738d6a
--- /dev/null
+++ b/static/robots.txt
@@ -0,0 +1,3 @@
+User-agent: *
+Disallow:
+
diff --git a/supabase/migrations/20240730010101_initial.sql b/supabase/migrations/20240730010101_initial.sql
new file mode 100644
index 0000000..076ae11
--- /dev/null
+++ b/supabase/migrations/20240730010101_initial.sql
@@ -0,0 +1,72 @@
+-- Create a table for public profiles
+create table profiles (
+ id uuid references auth.users on delete cascade not null primary key,
+ updated_at timestamp with time zone,
+ full_name text,
+ company_name text,
+ avatar_url text,
+ website text
+);
+-- Set up Row Level Security (RLS)
+-- See https://supabase.com/docs/guides/auth/row-level-security for more details.
+alter table profiles
+ enable row level security;
+
+create policy "Profiles are viewable by self." on profiles
+ for select using (auth.uid() = id);
+
+create policy "Users can insert their own profile." on profiles
+ for insert with check (auth.uid() = id);
+
+create policy "Users can update own profile." on profiles
+ for update using (auth.uid() = id);
+
+-- Create Stripe Customer Table
+-- One stripe customer per user (PK enforced)
+-- Limit RLS policies -- mostly only server side access
+create table stripe_customers (
+ user_id uuid references auth.users on delete cascade not null primary key,
+ updated_at timestamp with time zone,
+ stripe_customer_id text unique
+);
+alter table stripe_customers enable row level security;
+
+-- Create a table for "Contact Us" form submissions
+-- Limit RLS policies -- only server side access
+create table contact_requests (
+ id uuid primary key default gen_random_uuid(),
+ updated_at timestamp with time zone,
+ first_name text,
+ last_name text,
+ email text,
+ phone text,
+ company_name text,
+ message_body text
+);
+alter table contact_requests enable row level security;
+
+-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
+-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
+create function public.handle_new_user()
+returns trigger as $$
+begin
+ insert into public.profiles (id, full_name, avatar_url)
+ values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
+ return new;
+end;
+$$ language plpgsql security definer;
+create trigger on_auth_user_created
+ after insert on auth.users
+ for each row execute procedure public.handle_new_user();
+
+-- Set up Storage!
+insert into storage.buckets (id, name)
+ values ('avatars', 'avatars');
+
+-- Set up access controls for storage.
+-- See https://supabase.com/docs/guides/storage#policy-examples for more details.
+create policy "Avatar images are publicly accessible." on storage.objects
+ for select using (bucket_id = 'avatars');
+
+create policy "Anyone can upload an avatar." on storage.objects
+ for insert with check (bucket_id = 'avatars');
diff --git a/supabase/migrations/20240731051052_add_unsubscribed_to_profiles.sql b/supabase/migrations/20240731051052_add_unsubscribed_to_profiles.sql
new file mode 100644
index 0000000..1042d6d
--- /dev/null
+++ b/supabase/migrations/20240731051052_add_unsubscribed_to_profiles.sql
@@ -0,0 +1,2 @@
+ALTER TABLE profiles
+ADD COLUMN IF NOT EXISTS unsubscribed boolean NOT NULL DEFAULT false;
diff --git a/svelte.config.js b/svelte.config.js
new file mode 100644
index 0000000..83bae9e
--- /dev/null
+++ b/svelte.config.js
@@ -0,0 +1,15 @@
+import adapter from "@sveltejs/adapter-auto"
+import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ kit: {
+ // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
+ // If your environment is not supported or you settled on a specific environment, switch out the adapter.
+ // See https://kit.svelte.dev/docs/adapters for more information about adapters.
+ adapter: adapter(),
+ },
+ preprocess: vitePreprocess(),
+}
+
+export default config
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..01c6a74
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,28 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./src/**/*.{html,js,svelte,ts}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [require("@tailwindcss/typography"), require("daisyui")],
+ daisyui: {
+ themes: [
+ {
+ saasstartertheme: {
+ primary: "#180042",
+ "primary-content": "#fefbf6",
+ secondary: "#c7b9f8",
+ neutral: "#180042",
+ "neutral-content": "#fefbf6",
+ accent: "#db2777",
+ "accent-content": "#180042",
+ "base-content": "#180042",
+ "base-100": "#fefbf6",
+ "base-200": "#faedd6",
+ success: "#37d399",
+ error: "#f77272",
+ },
+ },
+ ],
+ },
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..59aa71c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "types": ["vitest/globals"] // allows to skip import of test functions like `describe`, `it`, `expect`, etc.
+ }
+ // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias and https://kit.svelte.dev/docs/configuration#files
+ //
+ // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
+ // from the referenced tsconfig.json - TypeScript does not merge them in
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..96b6b72
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,24 @@
+import { sveltekit } from "@sveltejs/kit/vite"
+import { defineConfig } from "vitest/config"
+import { buildAndCacheSearchIndex } from "./src/lib/build_index"
+
+export default defineConfig({
+ plugins: [
+ sveltekit(),
+ {
+ name: "vite-build-search-index",
+ writeBundle: {
+ order: "post",
+ sequential: false,
+ handler: async () => {
+ console.log("Building search index...")
+ await buildAndCacheSearchIndex()
+ },
+ },
+ },
+ ],
+ test: {
+ include: ["src/**/*.{test,spec}.{js,ts}"],
+ globals: true, /// allows to skip import of test functions like `describe`, `it`, `expect`, etc.
+ },
+})