From 38d1752f5b9112293d3d2acefa30f4f2b79da6d6 Mon Sep 17 00:00:00 2001 From: NeilClack Date: Tue, 7 Jul 2026 13:36:23 -0500 Subject: [PATCH] admin: Superforms + Zod validation, three-address-defaults schema, profiles toast fix - Add Superforms + Zod 4 for all admin form validation - Replace address isDefault with three separate boolean defaults (Mailing, Billing, Shipping) - Update profiles page with three-checkbox address form and toast improvements - Convert all admin page server actions to pass request directly to crud - Export superFormErrorsToFieldErrors helper for profiles server actions - Regenerate Prisma client for new schema fields --- .../better-auth-best-practices/SKILL.md | 36 +- .../SKILL.MD | 346 +++--- .agents/skills/create-auth-skill/SKILL.md | 82 +- .../SKILL.md | 149 ++- .../organization-best-practices/SKILL.md | 409 ++++--- .../SKILL.md | 276 ++--- .prettierrc | 7 +- .vscode/settings.json | 2 +- AGENTS.md | 20 +- README.md | 20 + package-lock.json | 1085 +++++++++++------ package.json | 8 +- prisma.config.ts | 3 +- .../migration.sql | 5 + .../migration.sql | 11 + prisma/schema.prisma | 22 +- prisma/seed.ts | 111 ++ skills-lock.json | 78 +- src/app.d.ts | 4 +- src/app.html | 43 +- src/hooks.server.spec.ts | 4 +- src/hooks.server.ts | 28 +- src/lib/auth-client.ts | 4 +- src/lib/auth.ts | 5 +- src/lib/components/tiptap/TipTap.svelte | 92 ++ src/lib/generated/prisma/client.ts | 4 +- src/lib/generated/prisma/commonInputTypes.ts | 43 - src/lib/generated/prisma/internal/class.ts | 36 +- .../prisma/internal/prismaNamespace.ts | 33 +- .../prisma/internal/prismaNamespaceBrowser.ts | 14 +- src/lib/generated/prisma/models/Account.ts | 7 +- src/lib/generated/prisma/models/Address.ts | 149 ++- src/lib/generated/prisma/models/LicenseKey.ts | 7 +- .../generated/prisma/models/Proclamation.ts | 74 +- .../prisma/models/ProclamationCategory.ts | 7 +- src/lib/generated/prisma/models/Profile.ts | 45 +- src/lib/generated/prisma/models/Session.ts | 7 +- .../prisma/models/SolfeggioFrequency.ts | 25 +- .../prisma/models/SubscriptionLevel.ts | 7 +- src/lib/generated/prisma/models/User.ts | 7 +- .../prisma/models/UserProclamations.ts | 7 +- src/lib/generated/prisma/models/UserRole.ts | 7 +- .../generated/prisma/models/Verification.ts | 7 +- src/lib/payments.ts | 100 +- src/lib/server/email-verification.ts | 5 +- src/lib/server/resend.ts | 42 +- src/lib/svelte-admin/README.md | 183 +-- src/lib/svelte-admin/crud.spec.ts | 124 ++ src/lib/svelte-admin/crud.ts | 202 +++ src/lib/svelte-admin/form-data.ts | 4 + src/lib/svelte-admin/schemas.ts | 74 ++ src/lib/svelte-admin/types.ts | 9 + .../(protected)/(user)/account/+page.svelte | 45 +- .../(user)/account/page.server.spec.ts | 12 +- .../(user)/account/setup/+page.svelte | 29 +- .../(user)/account/setup/page.server.spec.ts | 6 +- .../(protected)/(user)/dashboard/+page.svelte | 8 +- .../(user)/license-keys/+page.svelte | 22 +- .../(user)/proclamations/+page.server.ts | 2 +- .../(user)/proclamations/+page.svelte | 18 +- .../(user)/proclamations/[id]/+page.server.ts | 3 +- .../(user)/proclamations/[id]/+page.svelte | 20 +- .../proclamations/[id]/page.server.spec.ts | 9 +- .../(user)/proclamations/page.server.spec.ts | 14 +- src/routes/(protected)/+layout.svelte | 4 +- .../(protected)/admin/+layout.server.ts | 8 +- src/routes/(protected)/admin/+page.server.ts | 7 + src/routes/(protected)/admin/+page.svelte | 22 +- .../admin/categories/+page.server.ts | 10 - .../(protected)/admin/categories/+page.svelte | 41 - .../admin/license-keys/+page.server.ts | 68 ++ .../admin/license-keys/+page.svelte | 100 ++ .../proclamation-categories/+page.server.ts | 18 + .../proclamation-categories/+page.svelte | 8 + .../admin/proclamations/+page.server.ts | 18 + .../admin/proclamations/+page.svelte | 8 + .../admin/profiles/+page.server.ts | 98 +- .../(protected)/admin/profiles/+page.svelte | 114 +- .../solfeggio-frequencies/+page.server.ts | 18 + .../admin/solfeggio-frequencies/+page.svelte | 8 + .../admin/subscription-levels/+page.server.ts | 18 + .../admin/subscription-levels/+page.svelte | 8 + .../admin/user-roles/+page.server.ts | 18 + .../(protected)/admin/user-roles/+page.svelte | 8 + .../(protected)/admin/users/+page.server.ts | 18 + .../(protected)/admin/users/+page.svelte | 8 + src/routes/(protected)/layout.server.spec.ts | 4 +- src/routes/+error.svelte | 9 +- .../v1/automations/create/account/+server.ts | 30 +- src/routes/api/v1/categories/+server.ts | 6 +- src/routes/api/v1/frequencies/+server.ts | 6 +- src/routes/forgot-password/+page.svelte | 13 +- src/routes/layout.css | 130 +- src/routes/login/+page.svelte | 18 +- src/routes/register/+page.svelte | 16 +- src/routes/reset-password/+page.svelte | 4 +- src/routes/reset-password/page.server.spec.ts | 13 +- src/routes/send/+server.ts | 22 +- 98 files changed, 3408 insertions(+), 1758 deletions(-) create mode 100644 prisma/migrations/20260707164743_admin_audit_3/migration.sql create mode 100644 prisma/migrations/20260707182814_profiles_address_three_defaults/migration.sql create mode 100644 prisma/seed.ts create mode 100644 src/lib/components/tiptap/TipTap.svelte create mode 100644 src/lib/svelte-admin/crud.spec.ts create mode 100644 src/lib/svelte-admin/crud.ts create mode 100644 src/lib/svelte-admin/schemas.ts create mode 100644 src/routes/(protected)/admin/+page.server.ts delete mode 100644 src/routes/(protected)/admin/categories/+page.server.ts delete mode 100644 src/routes/(protected)/admin/categories/+page.svelte create mode 100644 src/routes/(protected)/admin/license-keys/+page.server.ts create mode 100644 src/routes/(protected)/admin/license-keys/+page.svelte create mode 100644 src/routes/(protected)/admin/proclamation-categories/+page.server.ts create mode 100644 src/routes/(protected)/admin/proclamation-categories/+page.svelte create mode 100644 src/routes/(protected)/admin/proclamations/+page.server.ts create mode 100644 src/routes/(protected)/admin/proclamations/+page.svelte create mode 100644 src/routes/(protected)/admin/solfeggio-frequencies/+page.server.ts create mode 100644 src/routes/(protected)/admin/solfeggio-frequencies/+page.svelte create mode 100644 src/routes/(protected)/admin/subscription-levels/+page.server.ts create mode 100644 src/routes/(protected)/admin/subscription-levels/+page.svelte create mode 100644 src/routes/(protected)/admin/user-roles/+page.server.ts create mode 100644 src/routes/(protected)/admin/user-roles/+page.svelte create mode 100644 src/routes/(protected)/admin/users/+page.server.ts create mode 100644 src/routes/(protected)/admin/users/+page.svelte diff --git a/.agents/skills/better-auth-best-practices/SKILL.md b/.agents/skills/better-auth-best-practices/SKILL.md index 3e6a4e1..fabd32f 100644 --- a/.agents/skills/better-auth-best-practices/SKILL.md +++ b/.agents/skills/better-auth-best-practices/SKILL.md @@ -23,15 +23,18 @@ description: Configure Better Auth server and client, set up database adapters, ## Quick Reference ### Environment Variables + - `BETTER_AUTH_SECRET` - Encryption secret (min 32 chars). Generate: `openssl rand -base64 32` - `BETTER_AUTH_URL` - Base URL (e.g., `https://example.com`) Only define `baseURL`/`secret` in config if env vars are NOT set. ### File Location + CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--config` for custom path. ### CLI Commands + - `npx @better-auth/cli@latest migrate` - Apply schema (built-in adapter) - `npx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle - `npx @better-auth/cli mcp --cursor` - Add MCP to AI tools @@ -42,18 +45,18 @@ CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--c ## Core Config Options -| Option | Notes | -|--------|-------| -| `appName` | Optional display name | -| `baseURL` | Only if `BETTER_AUTH_URL` not set | -| `basePath` | Default `/api/auth`. Set `/` for root. | -| `secret` | Only if `BETTER_AUTH_SECRET` not set | -| `database` | Required for most features. See adapters docs. | -| `secondaryStorage` | Redis/KV for sessions & rate limits | -| `emailAndPassword` | `{ enabled: true }` to activate | -| `socialProviders` | `{ google: { clientId, clientSecret }, ... }` | -| `plugins` | Array of plugins | -| `trustedOrigins` | CSRF whitelist | +| Option | Notes | +| ------------------ | ---------------------------------------------- | +| `appName` | Optional display name | +| `baseURL` | Only if `BETTER_AUTH_URL` not set | +| `basePath` | Default `/api/auth`. Set `/` for root. | +| `secret` | Only if `BETTER_AUTH_SECRET` not set | +| `database` | Required for most features. See adapters docs. | +| `secondaryStorage` | Redis/KV for sessions & rate limits | +| `emailAndPassword` | `{ enabled: true }` to activate | +| `socialProviders` | `{ google: { clientId, clientSecret }, ... }` | +| `plugins` | Array of plugins | +| `trustedOrigins` | CSRF whitelist | --- @@ -70,11 +73,13 @@ CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--c ## Session Management **Storage priority:** + 1. If `secondaryStorage` defined → sessions go there (not DB) 2. Set `session.storeSessionInDatabase: true` to also persist to DB 3. No database + `cookieCache` → fully stateless mode **Cookie cache strategies:** + - `compact` (default) - Base64url + HMAC. Smallest. - `jwt` - Standard JWT. Readable but signed. - `jwe` - Encrypted. Maximum security. @@ -104,9 +109,10 @@ CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--c ## Security **In `advanced`:** + - `useSecureCookies` - Force HTTPS cookies - `disableCSRFCheck` - ⚠️ Security risk -- `disableOriginCheck` - ⚠️ Security risk +- `disableOriginCheck` - ⚠️ Security risk - `crossSubDomainCookies.enabled` - Share cookies across subdomains - `ipAddress.ipAddressHeaders` - Custom IP headers for proxies - `database.generateId` - Custom ID generation or `"serial"`/`"uuid"`/`false` @@ -128,9 +134,11 @@ CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--c ## Plugins **Import from dedicated paths for tree-shaking:** + ``` import { twoFactor } from "better-auth/plugins/two-factor" ``` + NOT `from "better-auth/plugins"`. **Popular plugins:** `twoFactor`, `organization`, `passkey`, `magicLink`, `emailOtp`, `username`, `phoneNumber`, `admin`, `apiKey`, `bearer`, `jwt`, `multiSession`, `sso`, `oauthProvider`, `oidcProvider`, `openAPI`, `genericOAuth`. @@ -172,4 +180,4 @@ For separate client/server projects: `createAuthClient()`. - [Options Reference](https://better-auth.com/docs/reference/options) - [LLMs.txt](https://better-auth.com/llms.txt) - [GitHub](https://github.com/better-auth/better-auth) -- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts) \ No newline at end of file +- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts) diff --git a/.agents/skills/better-auth-security-best-practices/SKILL.MD b/.agents/skills/better-auth-security-best-practices/SKILL.MD index 5abc5a8..071998c 100644 --- a/.agents/skills/better-auth-security-best-practices/SKILL.MD +++ b/.agents/skills/better-auth-security-best-practices/SKILL.MD @@ -8,14 +8,15 @@ description: Configure rate limiting, manage auth secrets, set up CSRF protectio ### Configuring the Secret ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - secret: process.env.BETTER_AUTH_SECRET, // or via `BETTER_AUTH_SECRET` env + secret: process.env.BETTER_AUTH_SECRET // or via `BETTER_AUTH_SECRET` env }); ``` Better Auth looks for secrets in this order: + 1. `options.secret` in your config 2. `BETTER_AUTH_SECRET` environment variable 3. `AUTH_SECRET` environment variable @@ -34,14 +35,14 @@ Enabled in production by default. Applies to all endpoints. Plugins can override ### Default Configuration ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - rateLimit: { - enabled: true, // Default: true in production - window: 10, // Time window in seconds (default: 10) - max: 100, // Max requests per window (default: 100) - }, + rateLimit: { + enabled: true, // Default: true in production + window: 10, // Time window in seconds (default: 10) + max: 100 // Max requests per window (default: 100) + } }); ``` @@ -95,12 +96,12 @@ Multi-layer protection: origin header validation, Fetch Metadata checks, and fir ### Configuration ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - advanced: { - disableCSRFCheck: false, // Default: false (keep enabled) - }, + advanced: { + disableCSRFCheck: false // Default: false (keep enabled) + } }); ``` @@ -111,14 +112,11 @@ Only disable for testing or with an alternative CSRF mechanism. ### Configuring Trusted Origins ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - baseURL: "https://api.example.com", - trustedOrigins: [ - "https://app.example.com", - "https://admin.example.com", - ], + baseURL: 'https://api.example.com', + trustedOrigins: ['https://app.example.com', 'https://admin.example.com'] }); ``` @@ -128,10 +126,10 @@ The `baseURL` origin is automatically trusted. Also configurable via env: `BETTE ```ts trustedOrigins: [ - "*.example.com", // Matches any subdomain - "https://*.example.com", // Protocol-specific wildcard - "exp://192.168.*.*:*/*", // Custom schemes (e.g., Expo) -] + '*.example.com', // Matches any subdomain + 'https://*.example.com', // Protocol-specific wildcard + 'exp://192.168.*.*:*/*' // Custom schemes (e.g., Expo) +]; ``` ### Dynamic Trusted Origins @@ -140,10 +138,10 @@ Compute trusted origins based on the request: ```ts trustedOrigins: async (request) => { - // Validate against database, header, etc. - const tenant = getTenantFromRequest(request); - return [`https://${tenant}.myapp.com`]; -} + // Validate against database, header, etc. + const tenant = getTenantFromRequest(request); + return [`https://${tenant}.myapp.com`]; +}; ``` Validates `callbackURL`, `redirectTo`, `errorCallbackURL`, `newUserCallbackURL`, and `origin` against trusted origins. Invalid URLs receive 403. @@ -153,13 +151,13 @@ Validates `callbackURL`, `redirectTo`, `errorCallbackURL`, `newUserCallbackURL`, ### Session Expiration ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - session: { - expiresIn: 60 * 60 * 24 * 7, // 7 days (default) - updateAge: 60 * 60 * 24, // Refresh session every 24 hours (default) - }, + session: { + expiresIn: 60 * 60 * 24 * 7, // 7 days (default) + updateAge: 60 * 60 * 24 // Refresh session every 24 hours (default) + } }); ``` @@ -186,17 +184,17 @@ Defaults: `secure: true` (HTTPS/production), `sameSite: "lax"`, `httpOnly: true` ### Custom Cookie Configuration ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - advanced: { - useSecureCookies: true, // Force secure cookies - cookiePrefix: "myapp", // Custom prefix (default: "better-auth") - defaultCookieAttributes: { - sameSite: "strict", // Stricter CSRF protection - path: "/auth", // Limit cookie scope - }, - }, + advanced: { + useSecureCookies: true, // Force secure cookies + cookiePrefix: 'myapp', // Custom prefix (default: "better-auth") + defaultCookieAttributes: { + sameSite: 'strict', // Stricter CSRF protection + path: '/auth' // Limit cookie scope + } + } }); ``` @@ -221,12 +219,12 @@ PKCE is automatic for all OAuth flows. State tokens are 32-char random strings e ### State Parameter Storage ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - account: { - storeStateStrategy: "cookie", // Options: "cookie" (default), "database" - }, + account: { + storeStateStrategy: 'cookie' // Options: "cookie" (default), "database" + } }); ``` @@ -245,15 +243,15 @@ Enable if storing OAuth tokens for API access on behalf of users. Use `skipState ### IP Address Configuration ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - advanced: { - ipAddress: { - ipAddressHeaders: ["x-forwarded-for", "x-real-ip"], // Headers to check - disableIpTracking: false, // Keep enabled for rate limiting - }, - }, + advanced: { + ipAddress: { + ipAddressHeaders: ['x-forwarded-for', 'x-real-ip'], // Headers to check + disableIpTracking: false // Keep enabled for rate limiting + } + } }); ``` @@ -262,50 +260,50 @@ Set `ipv6Subnet` (128, 64, 48, 32; default 64) to group IPv6 addresses. Enable ` ## Database Hooks for Security Auditing ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - databaseHooks: { - session: { - create: { - after: async ({ data, ctx }) => { - await auditLog("session.created", { - userId: data.userId, - ip: ctx?.request?.headers.get("x-forwarded-for"), - userAgent: ctx?.request?.headers.get("user-agent"), - }); - }, - }, - delete: { - before: async ({ data }) => { - await auditLog("session.revoked", { sessionId: data.id }); - }, - }, - }, - user: { - update: { - after: async ({ data, oldData }) => { - if (oldData?.email !== data.email) { - await auditLog("user.email_changed", { - userId: data.id, - oldEmail: oldData?.email, - newEmail: data.email, - }); - } - }, - }, - }, - account: { - create: { - after: async ({ data }) => { - await auditLog("account.linked", { - userId: data.userId, - provider: data.providerId, - }); - }, - }, - }, - }, + databaseHooks: { + session: { + create: { + after: async ({ data, ctx }) => { + await auditLog('session.created', { + userId: data.userId, + ip: ctx?.request?.headers.get('x-forwarded-for'), + userAgent: ctx?.request?.headers.get('user-agent') + }); + } + }, + delete: { + before: async ({ data }) => { + await auditLog('session.revoked', { sessionId: data.id }); + } + } + }, + user: { + update: { + after: async ({ data, oldData }) => { + if (oldData?.email !== data.email) { + await auditLog('user.email_changed', { + userId: data.id, + oldEmail: oldData?.email, + newEmail: data.email + }); + } + } + } + }, + account: { + create: { + after: async ({ data }) => { + await auditLog('account.linked', { + userId: data.userId, + provider: data.providerId + }); + } + } + } + } }); ``` @@ -314,19 +312,19 @@ Return `false` from a `before` hook to prevent an operation. ## Background Tasks ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - advanced: { - backgroundTasks: { - handler: (promise) => { - // Platform-specific handler - // Vercel: waitUntil(promise) - // Cloudflare: ctx.waitUntil(promise) - waitUntil(promise); - }, - }, - }, + advanced: { + backgroundTasks: { + handler: (promise) => { + // Platform-specific handler + // Vercel: waitUntil(promise) + // Cloudflare: ctx.waitUntil(promise) + waitUntil(promise); + } + } + } }); ``` @@ -339,80 +337,76 @@ Built-in: consistent response messages, dummy operations on invalid requests, ba ## Complete Security Configuration Example ```ts -import { betterAuth } from "better-auth"; +import { betterAuth } from 'better-auth'; export const auth = betterAuth({ - secret: process.env.BETTER_AUTH_SECRET, - baseURL: "https://api.example.com", - trustedOrigins: [ - "https://app.example.com", - "https://*.preview.example.com", - ], - - // Rate limiting - rateLimit: { - enabled: true, - storage: "secondary-storage", - customRules: { - "/api/auth/sign-in/email": { window: 60, max: 5 }, - "/api/auth/sign-up/email": { window: 60, max: 3 }, - }, - }, - - // Session security - session: { - expiresIn: 60 * 60 * 24 * 7, // 7 days - updateAge: 60 * 60 * 24, // 24 hours - freshAge: 60 * 60, // 1 hour for sensitive actions - cookieCache: { - enabled: true, - maxAge: 300, - strategy: "jwe", // Encrypted session data - }, - }, - - // OAuth security - account: { - encryptOAuthTokens: true, - storeStateStrategy: "cookie", - }, - - - // Advanced settings - advanced: { - useSecureCookies: true, - cookiePrefix: "myapp", - defaultCookieAttributes: { - sameSite: "lax", - }, - ipAddress: { - ipAddressHeaders: ["x-forwarded-for"], - ipv6Subnet: 64, - }, - backgroundTasks: { - handler: (promise) => waitUntil(promise), - }, - }, - - // Security auditing - databaseHooks: { - session: { - create: { - after: async ({ data, ctx }) => { - console.log(`New session for user ${data.userId}`); - }, - }, - }, - user: { - update: { - after: async ({ data, oldData }) => { - if (oldData?.email !== data.email) { - console.log(`Email changed for user ${data.id}`); - } - }, - }, - }, - }, + secret: process.env.BETTER_AUTH_SECRET, + baseURL: 'https://api.example.com', + trustedOrigins: ['https://app.example.com', 'https://*.preview.example.com'], + + // Rate limiting + rateLimit: { + enabled: true, + storage: 'secondary-storage', + customRules: { + '/api/auth/sign-in/email': { window: 60, max: 5 }, + '/api/auth/sign-up/email': { window: 60, max: 3 } + } + }, + + // Session security + session: { + expiresIn: 60 * 60 * 24 * 7, // 7 days + updateAge: 60 * 60 * 24, // 24 hours + freshAge: 60 * 60, // 1 hour for sensitive actions + cookieCache: { + enabled: true, + maxAge: 300, + strategy: 'jwe' // Encrypted session data + } + }, + + // OAuth security + account: { + encryptOAuthTokens: true, + storeStateStrategy: 'cookie' + }, + + // Advanced settings + advanced: { + useSecureCookies: true, + cookiePrefix: 'myapp', + defaultCookieAttributes: { + sameSite: 'lax' + }, + ipAddress: { + ipAddressHeaders: ['x-forwarded-for'], + ipv6Subnet: 64 + }, + backgroundTasks: { + handler: (promise) => waitUntil(promise) + } + }, + + // Security auditing + databaseHooks: { + session: { + create: { + after: async ({ data, ctx }) => { + console.log(`New session for user ${data.userId}`); + } + } + }, + user: { + update: { + after: async ({ data, oldData }) => { + if (oldData?.email !== data.email) { + console.log(`Email changed for user ${data.id}`); + } + } + } + } + } }); ``` diff --git a/.agents/skills/create-auth-skill/SKILL.md b/.agents/skills/create-auth-skill/SKILL.md index 515e6dd..93e5887 100644 --- a/.agents/skills/create-auth-skill/SKILL.md +++ b/.agents/skills/create-auth-skill/SKILL.md @@ -18,6 +18,7 @@ Before writing any code, gather requirements by scanning the project and asking ### Step 1: Scan the project Analyze the codebase to auto-detect: + - **Framework** — Look for `next.config`, `svelte.config`, `nuxt.config`, `astro.config`, `vite.config`, or Express/Hono entry files. - **Database/ORM** — Look for `prisma/schema.prisma`, `drizzle.config`, `package.json` deps (`pg`, `mysql2`, `better-sqlite3`, `mongoose`, `mongodb`). - **Existing auth** — Look for existing auth libraries (`next-auth`, `lucia`, `clerk`, `supabase/auth`, `firebase/auth`) in `package.json` or imports. @@ -75,8 +76,9 @@ Use the `AskQuestion` tool to ask the user **all applicable questions in a singl - `allow_multiple: true` 10. **Auth UI style** (always ask) - - Prompt: "What style do you want for the auth pages? Pick one or describe your own." - - Options: Minimal & clean | Centered card with background | Split layout (form + hero image) | Floating / glassmorphism | Other (I'll describe) + +- Prompt: "What style do you want for the auth pages? Pick one or describe your own." +- Options: Minimal & clean | Centered card with background | Split layout (form + hero image) | Floating / glassmorphism | Other (I'll describe) ### Step 3: Summarize the plan @@ -180,15 +182,18 @@ Add OAuth secrets as needed: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE **Location:** `lib/auth.ts` or `src/lib/auth.ts` **Minimal config needs:** + - `database` - Connection or adapter - `emailAndPassword: { enabled: true }` - For email/password auth **Standard config adds:** + - `socialProviders` - OAuth providers (google, github, etc.) - `emailVerification.sendVerificationEmail` - Email verification handler - `emailAndPassword.sendResetPassword` - Password reset handler **Full config adds:** + - `plugins` - Array of feature plugins - `session` - Expiry, cookie cache settings - `account.accountLinking` - Multi-provider linking @@ -217,14 +222,14 @@ Add OAuth secrets as needed: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE ## Route Handler Setup -| Framework | File | Handler | -|-----------|------|---------| +| Framework | File | Handler | +| ------------------ | -------------------------------- | ------------------------------------------------ | | Next.js App Router | `app/api/auth/[...all]/route.ts` | `toNextJsHandler(auth)` → export `{ GET, POST }` | -| Next.js Pages | `pages/api/auth/[...all].ts` | `toNextJsHandler(auth)` → default export | -| Express | Any file | `app.all("/api/auth/*", toNodeHandler(auth))` | -| SvelteKit | `src/hooks.server.ts` | `svelteKitHandler(auth)` | -| SolidStart | Route file | `solidStartHandler(auth)` | -| Hono | Route file | `auth.handler(c.req.raw)` | +| Next.js Pages | `pages/api/auth/[...all].ts` | `toNextJsHandler(auth)` → default export | +| Express | Any file | `app.all("/api/auth/*", toNodeHandler(auth))` | +| SvelteKit | `src/hooks.server.ts` | `svelteKitHandler(auth)` | +| SolidStart | Route file | `solidStartHandler(auth)` | +| Hono | Route file | `auth.handler(c.req.raw)` | **Next.js Server Components:** Add `nextCookies()` plugin to auth config. @@ -232,11 +237,11 @@ Add OAuth secrets as needed: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE ## Database Migrations -| Adapter | Command | -|---------|---------| -| Built-in Kysely | `npx @better-auth/cli@latest migrate` (applies directly) | -| Prisma | `npx @better-auth/cli@latest generate --output prisma/schema.prisma` then `npx prisma migrate dev` | -| Drizzle | `npx @better-auth/cli@latest generate --output src/db/auth-schema.ts` then `npx drizzle-kit push` | +| Adapter | Command | +| --------------- | -------------------------------------------------------------------------------------------------- | +| Built-in Kysely | `npx @better-auth/cli@latest migrate` (applies directly) | +| Prisma | `npx @better-auth/cli@latest generate --output prisma/schema.prisma` then `npx prisma migrate dev` | +| Drizzle | `npx @better-auth/cli@latest generate --output src/db/auth-schema.ts` then `npx drizzle-kit push` | **Re-run after adding plugins.** @@ -244,28 +249,28 @@ Add OAuth secrets as needed: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE ## Database Adapters -| Database | Setup | -|----------|-------| -| SQLite | Pass `better-sqlite3` or `bun:sqlite` instance directly | -| PostgreSQL | Pass `pg.Pool` instance directly | -| MySQL | Pass `mysql2` pool directly | -| Prisma | `prismaAdapter(prisma, { provider: "postgresql" })` from `better-auth/adapters/prisma` | -| Drizzle | `drizzleAdapter(db, { provider: "pg" })` from `better-auth/adapters/drizzle` | -| MongoDB | `mongodbAdapter(db)` from `better-auth/adapters/mongodb` | +| Database | Setup | +| ---------- | -------------------------------------------------------------------------------------- | +| SQLite | Pass `better-sqlite3` or `bun:sqlite` instance directly | +| PostgreSQL | Pass `pg.Pool` instance directly | +| MySQL | Pass `mysql2` pool directly | +| Prisma | `prismaAdapter(prisma, { provider: "postgresql" })` from `better-auth/adapters/prisma` | +| Drizzle | `drizzleAdapter(db, { provider: "pg" })` from `better-auth/adapters/drizzle` | +| MongoDB | `mongodbAdapter(db)` from `better-auth/adapters/mongodb` | --- ## Common Plugins -| Plugin | Server Import | Client Import | Purpose | -|--------|---------------|---------------|---------| -| `twoFactor` | `better-auth/plugins` | `twoFactorClient` | 2FA with TOTP/OTP | -| `organization` | `better-auth/plugins` | `organizationClient` | Teams/orgs | -| `admin` | `better-auth/plugins` | `adminClient` | User management | -| `bearer` | `better-auth/plugins` | - | API token auth | -| `openAPI` | `better-auth/plugins` | - | API docs | -| `passkey` | `@better-auth/passkey` | `passkeyClient` | WebAuthn | -| `sso` | `@better-auth/sso` | - | Enterprise SSO | +| Plugin | Server Import | Client Import | Purpose | +| -------------- | ---------------------- | -------------------- | ----------------- | +| `twoFactor` | `better-auth/plugins` | `twoFactorClient` | 2FA with TOTP/OTP | +| `organization` | `better-auth/plugins` | `organizationClient` | Teams/orgs | +| `admin` | `better-auth/plugins` | `adminClient` | User management | +| `bearer` | `better-auth/plugins` | - | API token auth | +| `openAPI` | `better-auth/plugins` | - | API docs | +| `passkey` | `@better-auth/passkey` | `passkeyClient` | WebAuthn | +| `sso` | `@better-auth/sso` | - | Enterprise SSO | **Plugin pattern:** Server plugin + client plugin + run migrations. @@ -274,6 +279,7 @@ Add OAuth secrets as needed: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE ## Auth UI Implementation **Sign in flow:** + 1. `signIn.email({ email, password })` or `signIn.social({ provider, callbackURL })` 2. Handle `error` in response 3. Redirect on success @@ -302,13 +308,13 @@ Add OAuth secrets as needed: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE ## Troubleshooting -| Issue | Fix | -|-------|-----| -| "Secret not set" | Add `BETTER_AUTH_SECRET` env var | -| "Invalid Origin" | Add domain to `trustedOrigins` | -| Cookies not setting | Check `baseURL` matches domain; enable secure cookies in prod | -| OAuth callback errors | Verify redirect URIs in provider dashboard | -| Type errors after adding plugin | Re-run CLI generate/migrate | +| Issue | Fix | +| ------------------------------- | ------------------------------------------------------------- | +| "Secret not set" | Add `BETTER_AUTH_SECRET` env var | +| "Invalid Origin" | Add domain to `trustedOrigins` | +| Cookies not setting | Check `baseURL` matches domain; enable secure cookies in prod | +| OAuth callback errors | Verify redirect URIs in provider dashboard | +| Type errors after adding plugin | Re-run CLI generate/migrate | --- diff --git a/.agents/skills/email-and-password-best-practices/SKILL.md b/.agents/skills/email-and-password-best-practices/SKILL.md index 537c010..b1bcb04 100644 --- a/.agents/skills/email-and-password-best-practices/SKILL.md +++ b/.agents/skills/email-and-password-best-practices/SKILL.md @@ -18,19 +18,19 @@ description: Configure email verification, implement password reset flows, set p Configure `emailVerification.sendVerificationEmail` to verify user email addresses. ```ts -import { betterAuth } from "better-auth"; -import { sendEmail } from "./email"; // your email sending function +import { betterAuth } from 'better-auth'; +import { sendEmail } from './email'; // your email sending function export const auth = betterAuth({ - emailVerification: { - sendVerificationEmail: async ({ user, url, token }, request) => { - await sendEmail({ - to: user.email, - subject: "Verify your email address", - text: `Click the link to verify your email: ${url}`, - }); - }, - }, + emailVerification: { + sendVerificationEmail: async ({ user, url, token }, request) => { + await sendEmail({ + to: user.email, + subject: 'Verify your email address', + text: `Click the link to verify your email: ${url}` + }); + } + } }); ``` @@ -42,9 +42,9 @@ For stricter security, enable `emailAndPassword.requireEmailVerification` to blo ```ts export const auth = betterAuth({ - emailAndPassword: { - requireEmailVerification: true, - }, + emailAndPassword: { + requireEmailVerification: true + } }); ``` @@ -60,7 +60,7 @@ Always use absolute URLs (including the origin) for callback URLs in sign-up and ```ts const { data, error } = await authClient.signUp.email({ - callbackURL: "https://example.com/callback", // absolute URL with origin + callbackURL: 'https://example.com/callback' // absolute URL with origin }); ``` @@ -69,26 +69,26 @@ const { data, error } = await authClient.signUp.email({ Provide `sendResetPassword` in the email and password config to enable password resets. ```ts -import { betterAuth } from "better-auth"; -import { sendEmail } from "./email"; // your email sending function +import { betterAuth } from 'better-auth'; +import { sendEmail } from './email'; // your email sending function export const auth = betterAuth({ - emailAndPassword: { - enabled: true, - // Custom email sending function to send reset-password email - sendResetPassword: async ({ user, url, token }, request) => { - void sendEmail({ - to: user.email, - subject: "Reset your password", - text: `Click the link to reset your password: ${url}`, - }); - }, - // Optional event hook - onPasswordReset: async ({ user }, request) => { - // your logic here - console.log(`Password for user ${user.email} has been reset.`); - }, - }, + emailAndPassword: { + enabled: true, + // Custom email sending function to send reset-password email + sendResetPassword: async ({ user, url, token }, request) => { + void sendEmail({ + to: user.email, + subject: 'Reset your password', + text: `Click the link to reset your password: ${url}` + }); + }, + // Optional event hook + onPasswordReset: async ({ user }, request) => { + // your logic here + console.log(`Password for user ${user.email} has been reset.`); + } + } }); ``` @@ -100,14 +100,14 @@ On serverless platforms, configure a background task handler: ```ts export const auth = betterAuth({ - advanced: { - backgroundTasks: { - handler: (promise) => { - // Use platform-specific methods like waitUntil - waitUntil(promise); - }, - }, - }, + advanced: { + backgroundTasks: { + handler: (promise) => { + // Use platform-specific methods like waitUntil + waitUntil(promise); + } + } + } }); ``` @@ -117,10 +117,10 @@ Tokens expire after 1 hour by default. Configure with `resetPasswordTokenExpires ```ts export const auth = betterAuth({ - emailAndPassword: { - enabled: true, - resetPasswordTokenExpiresIn: 60 * 30, // 30 minutes - }, + emailAndPassword: { + enabled: true, + resetPasswordTokenExpiresIn: 60 * 30 // 30 minutes + } }); ``` @@ -132,10 +132,10 @@ Enable `revokeSessionsOnPasswordReset` to invalidate all existing sessions on pa ```ts export const auth = betterAuth({ - emailAndPassword: { - enabled: true, - revokeSessionsOnPasswordReset: true, - }, + emailAndPassword: { + enabled: true, + revokeSessionsOnPasswordReset: true + } }); ``` @@ -145,11 +145,11 @@ Password length limits (configurable): ```ts export const auth = betterAuth({ - emailAndPassword: { - enabled: true, - minPasswordLength: 12, - maxPasswordLength: 256, - }, + emailAndPassword: { + enabled: true, + minPasswordLength: 12, + maxPasswordLength: 256 + } }); ``` @@ -159,10 +159,10 @@ Call `requestPasswordReset` to send the reset link. Triggers the `sendResetPassw ```ts const data = await auth.api.requestPasswordReset({ - body: { - email: "john.doe@example.com", // required - redirectTo: "https://example.com/reset-password", - }, + body: { + email: 'john.doe@example.com', // required + redirectTo: 'https://example.com/reset-password' + } }); ``` @@ -170,8 +170,8 @@ Or authClient: ```ts const { data, error } = await authClient.requestPasswordReset({ - email: "john.doe@example.com", // required - redirectTo: "https://example.com/reset-password", + email: 'john.doe@example.com', // required + redirectTo: 'https://example.com/reset-password' }); ``` @@ -186,26 +186,25 @@ Default: `scrypt` (Node.js native, no external dependencies). To use Argon2id or another algorithm, provide custom `hash` and `verify` functions: ```ts -import { betterAuth } from "better-auth"; -import { hash, verify, type Options } from "@node-rs/argon2"; +import { betterAuth } from 'better-auth'; +import { hash, verify, type Options } from '@node-rs/argon2'; const argon2Options: Options = { - memoryCost: 65536, // 64 MiB - timeCost: 3, // 3 iterations - parallelism: 4, // 4 parallel lanes - outputLen: 32, // 32 byte output - algorithm: 2, // Argon2id variant + memoryCost: 65536, // 64 MiB + timeCost: 3, // 3 iterations + parallelism: 4, // 4 parallel lanes + outputLen: 32, // 32 byte output + algorithm: 2 // Argon2id variant }; export const auth = betterAuth({ - emailAndPassword: { - enabled: true, - password: { - hash: (password) => hash(password, argon2Options), - verify: ({ password, hash: storedHash }) => - verify(storedHash, password, argon2Options), - }, - }, + emailAndPassword: { + enabled: true, + password: { + hash: (password) => hash(password, argon2Options), + verify: ({ password, hash: storedHash }) => verify(storedHash, password, argon2Options) + } + } }); ``` diff --git a/.agents/skills/organization-best-practices/SKILL.md b/.agents/skills/organization-best-practices/SKILL.md index 0e84a84..f299c82 100644 --- a/.agents/skills/organization-best-practices/SKILL.md +++ b/.agents/skills/organization-best-practices/SKILL.md @@ -11,28 +11,28 @@ description: Configure multi-tenant organizations, manage members and invitation 4. Verify: check that organization, member, invitation tables exist in your database ```ts -import { betterAuth } from "better-auth"; -import { organization } from "better-auth/plugins"; +import { betterAuth } from 'better-auth'; +import { organization } from 'better-auth/plugins'; export const auth = betterAuth({ - plugins: [ - organization({ - allowUserToCreateOrganization: true, - organizationLimit: 5, // Max orgs per user - membershipLimit: 100, // Max members per org - }), - ], + plugins: [ + organization({ + allowUserToCreateOrganization: true, + organizationLimit: 5, // Max orgs per user + membershipLimit: 100 // Max members per org + }) + ] }); ``` ### Client-Side Setup ```ts -import { createAuthClient } from "better-auth/client"; -import { organizationClient } from "better-auth/client/plugins"; +import { createAuthClient } from 'better-auth/client'; +import { organizationClient } from 'better-auth/client/plugins'; export const authClient = createAuthClient({ - plugins: [organizationClient()], + plugins: [organizationClient()] }); ``` @@ -42,12 +42,12 @@ The creator is automatically assigned the `owner` role. ```ts const createOrg = async () => { - const { data, error } = await authClient.organization.create({ - name: "My Company", - slug: "my-company", - logo: "https://example.com/logo.png", - metadata: { plan: "pro" }, - }); + const { data, error } = await authClient.organization.create({ + name: 'My Company', + slug: 'my-company', + logo: 'https://example.com/logo.png', + metadata: { plan: 'pro' } + }); }; ``` @@ -57,13 +57,13 @@ Restrict who can create organizations based on user attributes: ```ts organization({ - allowUserToCreateOrganization: async (user) => { - return user.emailVerified === true; - }, - organizationLimit: async (user) => { - // Premium users get more organizations - return user.plan === "premium" ? 20 : 3; - }, + allowUserToCreateOrganization: async (user) => { + return user.emailVerified === true; + }, + organizationLimit: async (user) => { + // Premium users get more organizations + return user.plan === 'premium' ? 20 : 3; + } }); ``` @@ -73,26 +73,25 @@ Administrators can create organizations for other users (server-side only): ```ts await auth.api.createOrganization({ - body: { - name: "Client Organization", - slug: "client-org", - userId: "user-id-who-will-be-owner", // `userId` is required - }, + body: { + name: 'Client Organization', + slug: 'client-org', + userId: 'user-id-who-will-be-owner' // `userId` is required + } }); ``` **Note**: The `userId` parameter cannot be used alongside session headers. - ## Active Organizations Stored in the session and scopes subsequent API calls. Set after user selects one. ```ts const setActive = async (organizationId: string) => { - const { data, error } = await authClient.organization.setActive({ - organizationId, - }); + const { data, error } = await authClient.organization.setActive({ + organizationId + }); }; ``` @@ -106,11 +105,11 @@ Use `getFullOrganization()` to retrieve the active org with all members, invitat ```ts await auth.api.addMember({ - body: { - userId: "user-id", - role: "member", - organizationId: "org-id", - }, + body: { + userId: 'user-id', + role: 'member', + organizationId: 'org-id' + } }); ``` @@ -120,11 +119,11 @@ For client-side member additions, use the invitation system instead. ```ts await auth.api.addMember({ - body: { - userId: "user-id", - role: ["admin", "moderator"], - organizationId: "org-id", - }, + body: { + userId: 'user-id', + role: ['admin', 'moderator'], + organizationId: 'org-id' + } }); ``` @@ -140,12 +139,12 @@ Use `updateMemberRole({ memberId, role })`. ```ts organization({ - membershipLimit: async (user, organization) => { - if (organization.metadata?.plan === "enterprise") { - return 1000; - } - return 50; - }, + membershipLimit: async (user, organization) => { + if (organization.metadata?.plan === 'enterprise') { + return 1000; + } + return 50; + } }); ``` @@ -154,29 +153,29 @@ organization({ ### Setting Up Invitation Emails ```ts -import { betterAuth } from "better-auth"; -import { organization } from "better-auth/plugins"; -import { sendEmail } from "./email"; +import { betterAuth } from 'better-auth'; +import { organization } from 'better-auth/plugins'; +import { sendEmail } from './email'; export const auth = betterAuth({ - plugins: [ - organization({ - sendInvitationEmail: async (data) => { - const { email, organization, inviter, invitation } = data; + plugins: [ + organization({ + sendInvitationEmail: async (data) => { + const { email, organization, inviter, invitation } = data; - await sendEmail({ - to: email, - subject: `Join ${organization.name}`, - html: ` + await sendEmail({ + to: email, + subject: `Join ${organization.name}`, + html: `

${inviter.user.name} invited you to join ${organization.name}

Accept Invitation - `, - }); - }, - }), - ], + ` + }); + } + }) + ] }); ``` @@ -184,8 +183,8 @@ export const auth = betterAuth({ ```ts await authClient.organization.inviteMember({ - email: "newuser@example.com", - role: "member", + email: 'newuser@example.com', + role: 'member' }); ``` @@ -193,9 +192,9 @@ await authClient.organization.inviteMember({ ```ts const { data } = await authClient.organization.getInvitationURL({ - email: "newuser@example.com", - role: "member", - callbackURL: "https://yourapp.com/dashboard", + email: 'newuser@example.com', + role: 'member', + callbackURL: 'https://yourapp.com/dashboard' }); // Share data.url via any channel @@ -207,9 +206,9 @@ This endpoint does not call `sendInvitationEmail` — handle delivery yourself. ```ts organization({ - invitationExpiresIn: 60 * 60 * 24 * 7, // 7 days (default: 48 hours) - invitationLimit: 100, // Max pending invitations per org - cancelPendingInvitationsOnReInvite: true, // Cancel old invites when re-inviting + invitationExpiresIn: 60 * 60 * 24 * 7, // 7 days (default: 48 hours) + invitationLimit: 100, // Max pending invitations per org + cancelPendingInvitationsOnReInvite: true // Cancel old invites when re-inviting }); ``` @@ -221,11 +220,11 @@ Default roles: `owner` (full access), `admin` (manage members/invitations/settin ```ts const { data } = await authClient.organization.hasPermission({ - permission: "member:write", + permission: 'member:write' }); if (data?.hasPermission) { - // User can manage members + // User can manage members } ``` @@ -236,16 +235,16 @@ Use `checkRolePermission({ role, permissions })` for client-side UI rendering (s ### Enabling Teams ```ts -import { organization } from "better-auth/plugins"; +import { organization } from 'better-auth/plugins'; export const auth = betterAuth({ - plugins: [ - organization({ - teams: { - enabled: true - } - }), - ], + plugins: [ + organization({ + teams: { + enabled: true + } + }) + ] }); ``` @@ -253,7 +252,7 @@ export const auth = betterAuth({ ```ts const { data } = await authClient.organization.createTeam({ - name: "Engineering", + name: 'Engineering' }); ``` @@ -267,11 +266,11 @@ Set active team with `setActiveTeam({ teamId })`. ```ts organization({ - teams: { - maximumTeams: 20, // Max teams per org - maximumMembersPerTeam: 50, // Max members per team - allowRemovingAllTeams: false, // Prevent removing last team - } + teams: { + maximumTeams: 20, // Max teams per org + maximumMembersPerTeam: 50, // Max members per team + allowRemovingAllTeams: false // Prevent removing last team + } }); ``` @@ -280,17 +279,17 @@ organization({ ### Enabling Dynamic Access Control ```ts -import { organization } from "better-auth/plugins"; -import { dynamicAccessControl } from "@better-auth/organization/addons"; +import { organization } from 'better-auth/plugins'; +import { dynamicAccessControl } from '@better-auth/organization/addons'; export const auth = betterAuth({ - plugins: [ - organization({ - dynamicAccessControl: { - enabled: true - } - }), - ], + plugins: [ + organization({ + dynamicAccessControl: { + enabled: true + } + }) + ] }); ``` @@ -298,11 +297,11 @@ export const auth = betterAuth({ ```ts await authClient.organization.createRole({ - role: "moderator", - permission: { - member: ["read"], - invitation: ["read"], - }, + role: 'moderator', + permission: { + member: ['read'], + invitation: ['read'] + } }); ``` @@ -314,37 +313,37 @@ Execute custom logic at various points in the organization lifecycle: ```ts organization({ - hooks: { - organization: { - beforeCreate: async ({ data, user }) => { - // Validate or modify data before creation - return { - data: { - ...data, - metadata: { ...data.metadata, createdBy: user.id }, - }, - }; - }, - afterCreate: async ({ organization, member }) => { - // Post-creation logic (e.g., send welcome email, create default resources) - await createDefaultResources(organization.id); - }, - beforeDelete: async ({ organization }) => { - // Cleanup before deletion - await archiveOrganizationData(organization.id); - }, - }, - member: { - afterCreate: async ({ member, organization }) => { - await notifyAdmins(organization.id, `New member joined`); - }, - }, - invitation: { - afterCreate: async ({ invitation, organization, inviter }) => { - await logInvitation(invitation); - }, - }, - }, + hooks: { + organization: { + beforeCreate: async ({ data, user }) => { + // Validate or modify data before creation + return { + data: { + ...data, + metadata: { ...data.metadata, createdBy: user.id } + } + }; + }, + afterCreate: async ({ organization, member }) => { + // Post-creation logic (e.g., send welcome email, create default resources) + await createDefaultResources(organization.id); + }, + beforeDelete: async ({ organization }) => { + // Cleanup before deletion + await archiveOrganizationData(organization.id); + } + }, + member: { + afterCreate: async ({ member, organization }) => { + await notifyAdmins(organization.id, `New member joined`); + } + }, + invitation: { + afterCreate: async ({ invitation, organization, inviter }) => { + await logInvitation(invitation); + } + } + } }); ``` @@ -354,32 +353,32 @@ Customize table names, field names, and add additional fields: ```ts organization({ - schema: { - organization: { - modelName: "workspace", // Rename table - fields: { - name: "workspaceName", // Rename fields - }, - additionalFields: { - billingId: { - type: "string", - required: false, - }, - }, - }, - member: { - additionalFields: { - department: { - type: "string", - required: false, - }, - title: { - type: "string", - required: false, - }, - }, - }, - }, + schema: { + organization: { + modelName: 'workspace', // Rename table + fields: { + name: 'workspaceName' // Rename fields + }, + additionalFields: { + billingId: { + type: 'string', + required: false + } + } + }, + member: { + additionalFields: { + department: { + type: 'string', + required: false + }, + title: { + type: 'string', + required: false + } + } + } + } }); ``` @@ -396,8 +395,8 @@ Always ensure ownership transfer before removing the current owner: ```ts // Transfer ownership first await authClient.organization.updateMemberRole({ - memberId: "new-owner-member-id", - role: "owner", + memberId: 'new-owner-member-id', + role: 'owner' }); // Then the previous owner can be demoted or removed @@ -409,7 +408,7 @@ Deleting an organization removes all associated data (members, invitations, team ```ts organization({ - disableOrganizationDeletion: true, // Disable via config + disableOrganizationDeletion: true // Disable via config }); ``` @@ -417,15 +416,15 @@ Or implement soft delete via hooks: ```ts organization({ - hooks: { - organization: { - beforeDelete: async ({ organization }) => { - // Archive instead of delete - await archiveOrganization(organization.id); - throw new Error("Organization archived, not deleted"); - }, - }, - }, + hooks: { + organization: { + beforeDelete: async ({ organization }) => { + // Archive instead of delete + await archiveOrganization(organization.id); + throw new Error('Organization archived, not deleted'); + } + } + } }); ``` @@ -438,42 +437,42 @@ organization({ ## Complete Configuration Example ```ts -import { betterAuth } from "better-auth"; -import { organization } from "better-auth/plugins"; -import { sendEmail } from "./email"; +import { betterAuth } from 'better-auth'; +import { organization } from 'better-auth/plugins'; +import { sendEmail } from './email'; export const auth = betterAuth({ - plugins: [ - organization({ - // Organization limits - allowUserToCreateOrganization: true, - organizationLimit: 10, - membershipLimit: 100, - creatorRole: "owner", + plugins: [ + organization({ + // Organization limits + allowUserToCreateOrganization: true, + organizationLimit: 10, + membershipLimit: 100, + creatorRole: 'owner', - // Slugs - defaultOrganizationIdField: "slug", + // Slugs + defaultOrganizationIdField: 'slug', - // Invitations - invitationExpiresIn: 60 * 60 * 24 * 7, // 7 days - invitationLimit: 50, - sendInvitationEmail: async (data) => { - await sendEmail({ - to: data.email, - subject: `Join ${data.organization.name}`, - html: `Accept`, - }); - }, + // Invitations + invitationExpiresIn: 60 * 60 * 24 * 7, // 7 days + invitationLimit: 50, + sendInvitationEmail: async (data) => { + await sendEmail({ + to: data.email, + subject: `Join ${data.organization.name}`, + html: `Accept` + }); + }, - // Hooks - hooks: { - organization: { - afterCreate: async ({ organization }) => { - console.log(`Organization ${organization.name} created`); - }, - }, - }, - }), - ], + // Hooks + hooks: { + organization: { + afterCreate: async ({ organization }) => { + console.log(`Organization ${organization.name} created`); + } + } + } + }) + ] }); ``` diff --git a/.agents/skills/two-factor-authentication-best-practices/SKILL.md b/.agents/skills/two-factor-authentication-best-practices/SKILL.md index cf9c30b..bafaa92 100644 --- a/.agents/skills/two-factor-authentication-best-practices/SKILL.md +++ b/.agents/skills/two-factor-authentication-best-practices/SKILL.md @@ -11,33 +11,33 @@ description: Configure TOTP authenticator apps, send OTP codes via email/SMS, ma 4. Verify: check that `twoFactorSecret` column exists on user table ```ts -import { betterAuth } from "better-auth"; -import { twoFactor } from "better-auth/plugins"; +import { betterAuth } from 'better-auth'; +import { twoFactor } from 'better-auth/plugins'; export const auth = betterAuth({ - appName: "My App", - plugins: [ - twoFactor({ - issuer: "My App", - }), - ], + appName: 'My App', + plugins: [ + twoFactor({ + issuer: 'My App' + }) + ] }); ``` ### Client-Side Setup ```ts -import { createAuthClient } from "better-auth/client"; -import { twoFactorClient } from "better-auth/client/plugins"; +import { createAuthClient } from 'better-auth/client'; +import { twoFactorClient } from 'better-auth/client/plugins'; export const authClient = createAuthClient({ - plugins: [ - twoFactorClient({ - onTwoFactorRedirect() { - window.location.href = "/2fa"; - }, - }), - ], + plugins: [ + twoFactorClient({ + onTwoFactorRedirect() { + window.location.href = '/2fa'; + } + }) + ] }); ``` @@ -47,14 +47,14 @@ Requires password verification. Returns TOTP URI (for QR code) and backup codes. ```ts const enable2FA = async (password: string) => { - const { data, error } = await authClient.twoFactor.enable({ - password, - }); + const { data, error } = await authClient.twoFactor.enable({ + password + }); - if (data) { - // data.totpURI — generate a QR code from this - // data.backupCodes — display to user - } + if (data) { + // data.totpURI — generate a QR code from this + // data.backupCodes — display to user + } }; ``` @@ -65,10 +65,10 @@ const enable2FA = async (password: string) => { ### Displaying the QR Code ```tsx -import QRCode from "react-qr-code"; +import QRCode from 'react-qr-code'; const TotpSetup = ({ totpURI }: { totpURI: string }) => { - return ; + return ; }; ``` @@ -78,10 +78,10 @@ Accepts codes from one period before/after current time: ```ts const verifyTotp = async (code: string) => { - const { data, error } = await authClient.twoFactor.verifyTotp({ - code, - trustDevice: true, - }); + const { data, error } = await authClient.twoFactor.verifyTotp({ + code, + trustDevice: true + }); }; ``` @@ -89,10 +89,10 @@ const verifyTotp = async (code: string) => { ```ts twoFactor({ - totpOptions: { - digits: 6, // 6 or 8 digits (default: 6) - period: 30, // Code validity period in seconds (default: 30) - }, + totpOptions: { + digits: 6, // 6 or 8 digits (default: 6) + period: 30 // Code validity period in seconds (default: 30) + } }); ``` @@ -101,27 +101,27 @@ twoFactor({ ### Configuring OTP Delivery ```ts -import { betterAuth } from "better-auth"; -import { twoFactor } from "better-auth/plugins"; -import { sendEmail } from "./email"; +import { betterAuth } from 'better-auth'; +import { twoFactor } from 'better-auth/plugins'; +import { sendEmail } from './email'; export const auth = betterAuth({ - plugins: [ - twoFactor({ - otpOptions: { - sendOTP: async ({ user, otp }, ctx) => { - await sendEmail({ - to: user.email, - subject: "Your verification code", - text: `Your code is: ${otp}`, - }); - }, - period: 5, // Code validity in minutes (default: 3) - digits: 6, // Number of digits (default: 6) - allowedAttempts: 5, // Max verification attempts (default: 5) - }, - }), - ], + plugins: [ + twoFactor({ + otpOptions: { + sendOTP: async ({ user, otp }, ctx) => { + await sendEmail({ + to: user.email, + subject: 'Your verification code', + text: `Your code is: ${otp}` + }); + }, + period: 5, // Code validity in minutes (default: 3) + digits: 6, // Number of digits (default: 6) + allowedAttempts: 5 // Max verification attempts (default: 5) + } + }) + ] }); ``` @@ -135,9 +135,9 @@ Configure how OTP codes are stored in the database: ```ts twoFactor({ - otpOptions: { - storeOTP: "encrypted", // Options: "plain", "encrypted", "hashed" - }, + otpOptions: { + storeOTP: 'encrypted' // Options: "plain", "encrypted", "hashed" + } }); ``` @@ -145,12 +145,12 @@ For custom encryption: ```ts twoFactor({ - otpOptions: { - storeOTP: { - encrypt: async (token) => myEncrypt(token), - decrypt: async (token) => myDecrypt(token), - }, - }, + otpOptions: { + storeOTP: { + encrypt: async (token) => myEncrypt(token), + decrypt: async (token) => myDecrypt(token) + } + } }); ``` @@ -162,16 +162,16 @@ Generated automatically when 2FA is enabled. Each code is single-use. ```tsx const BackupCodes = ({ codes }: { codes: string[] }) => { - return ( -
-

Save these codes in a secure location:

-
    - {codes.map((code, i) => ( -
  • {code}
  • - ))} -
-
- ); + return ( +
+

Save these codes in a secure location:

+
    + {codes.map((code, i) => ( +
  • {code}
  • + ))} +
+
+ ); }; ``` @@ -181,10 +181,10 @@ Invalidates all previous codes: ```ts const regenerateBackupCodes = async (password: string) => { - const { data, error } = await authClient.twoFactor.generateBackupCodes({ - password, - }); - // data.backupCodes contains the new codes + const { data, error } = await authClient.twoFactor.generateBackupCodes({ + password + }); + // data.backupCodes contains the new codes }; ``` @@ -192,10 +192,10 @@ const regenerateBackupCodes = async (password: string) => { ```ts const verifyBackupCode = async (code: string) => { - const { data, error } = await authClient.twoFactor.verifyBackupCode({ - code, - trustDevice: true, - }); + const { data, error } = await authClient.twoFactor.verifyBackupCode({ + code, + trustDevice: true + }); }; ``` @@ -203,11 +203,11 @@ const verifyBackupCode = async (code: string) => { ```ts twoFactor({ - backupCodeOptions: { - amount: 10, // Number of codes to generate (default: 10) - length: 10, // Length of each code (default: 10) - storeBackupCodes: "encrypted", // Options: "plain", "encrypted" - }, + backupCodeOptions: { + amount: 10, // Number of codes to generate (default: 10) + length: 10, // Length of each code (default: 10) + storeBackupCodes: 'encrypted' // Options: "plain", "encrypted" + } }); ``` @@ -225,16 +225,16 @@ Response includes `twoFactorRedirect: true` when 2FA is required: ```ts const signIn = async (email: string, password: string) => { - const { data, error } = await authClient.signIn.email( - { email, password }, - { - onSuccess(context) { - if (context.data.twoFactorRedirect) { - window.location.href = "/2fa"; - } - }, - } - ); + const { data, error } = await authClient.signIn.email( + { email, password }, + { + onSuccess(context) { + if (context.data.twoFactorRedirect) { + window.location.href = '/2fa'; + } + } + } + ); }; ``` @@ -252,7 +252,7 @@ Flow: credentials → session removed → temporary 2FA cookie (10 min default) ```ts twoFactor({ - twoFactorCookieMaxAge: 600, // 10 minutes in seconds (default) + twoFactorCookieMaxAge: 600 // 10 minutes in seconds (default) }); ``` @@ -262,9 +262,9 @@ Built-in: 3 requests per 10 seconds for all 2FA endpoints. OTP has additional at ```ts twoFactor({ - otpOptions: { - allowedAttempts: 5, // Max attempts per OTP code (default: 5) - }, + otpOptions: { + allowedAttempts: 5 // Max attempts per OTP code (default: 5) + } }); ``` @@ -280,52 +280,52 @@ Requires password confirmation. Revokes trusted device records: ```ts const disable2FA = async (password: string) => { - const { data, error } = await authClient.twoFactor.disable({ - password, - }); + const { data, error } = await authClient.twoFactor.disable({ + password + }); }; ``` ## Complete Configuration Example ```ts -import { betterAuth } from "better-auth"; -import { twoFactor } from "better-auth/plugins"; -import { sendEmail } from "./email"; +import { betterAuth } from 'better-auth'; +import { twoFactor } from 'better-auth/plugins'; +import { sendEmail } from './email'; export const auth = betterAuth({ - appName: "My App", - plugins: [ - twoFactor({ - // TOTP settings - issuer: "My App", - totpOptions: { - digits: 6, - period: 30, - }, - // OTP settings - otpOptions: { - sendOTP: async ({ user, otp }) => { - await sendEmail({ - to: user.email, - subject: "Your verification code", - text: `Your code is: ${otp}`, - }); - }, - period: 5, - allowedAttempts: 5, - storeOTP: "encrypted", - }, - // Backup code settings - backupCodeOptions: { - amount: 10, - length: 10, - storeBackupCodes: "encrypted", - }, - // Session settings - twoFactorCookieMaxAge: 600, // 10 minutes - trustDeviceMaxAge: 30 * 24 * 60 * 60, // 30 days - }), - ], + appName: 'My App', + plugins: [ + twoFactor({ + // TOTP settings + issuer: 'My App', + totpOptions: { + digits: 6, + period: 30 + }, + // OTP settings + otpOptions: { + sendOTP: async ({ user, otp }) => { + await sendEmail({ + to: user.email, + subject: 'Your verification code', + text: `Your code is: ${otp}` + }); + }, + period: 5, + allowedAttempts: 5, + storeOTP: 'encrypted' + }, + // Backup code settings + backupCodeOptions: { + amount: 10, + length: 10, + storeBackupCodes: 'encrypted' + }, + // Session settings + twoFactorCookieMaxAge: 600, // 10 minutes + trustDeviceMaxAge: 30 * 24 * 60 * 60 // 30 days + }) + ] }); ``` diff --git a/.prettierrc b/.prettierrc index 8aacc14..075d35f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,10 +4,7 @@ "trailingComma": "none", "semi": true, "printWidth": 100, - "plugins": [ - "prettier-plugin-svelte", - "prettier-plugin-tailwindcss" - ], + "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], "overrides": [ { "files": "*.svelte", @@ -17,4 +14,4 @@ } ], "tailwindStylesheet": "./src/routes/layout.css" -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 9e26dfe..0967ef4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/AGENTS.md b/AGENTS.md index 51ce2f3..e1233f0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,16 +14,16 @@ Requires `.env` with at least `DATABASE_URL`, `BETTER_AUTH_SECRET`, `BETTER_AUTH ## Commands -| npm run ... | What it does | -|----------------|-------------| -| `check` | `svelte-kit sync && svelte-check` (typecheck) | -| `lint` | `prettier --check . && eslint .` (order matters) | -| `format` | `prettier --write .` | -| `test` | `vitest --run` (single run) | -| `test:unit` | `vitest` (watch mode) | -| `migrate -- --name ` | Create a Prisma migration | -| `deploy` | Apply pending migrations | -| `build` | Production build (adapter-node) | +| npm run ... | What it does | +| -------------------------- | ------------------------------------------------ | +| `check` | `svelte-kit sync && svelte-check` (typecheck) | +| `lint` | `prettier --check . && eslint .` (order matters) | +| `format` | `prettier --write .` | +| `test` | `vitest --run` (single run) | +| `test:unit` | `vitest` (watch mode) | +| `migrate -- --name ` | Create a Prisma migration | +| `deploy` | Apply pending migrations | +| `build` | Production build (adapter-node) | ## Testing quirks diff --git a/README.md b/README.md index 9435861..9ca413c 100644 --- a/README.md +++ b/README.md @@ -1 +1,21 @@ # Rhema Wave Technologies - User Portal + +SvelteKit 2 + Svelte 5 + Tailwind CSS v4 + Prisma 7 + PostgreSQL + Better-Auth. + +## Admin + +Admin CRUD pages at `/admin`. 9 models have per-page routes with modals for create/edit: + +| Included | Excluded | +| -------- | --------------------- | +| users | Session (Better Auth) | +| profiles | Account (Better Auth) | +| addresses| Verification (Better Auth) | +| user-roles | UserProclamations (composite key) | +| proclamations | | +| solfeggio-frequencies | | +| proclamation-categories | | +| license-keys (list-only) | | +| subscription-levels | | + +See `src/lib/svelte-admin/README.md` for architecture and configuration docs. diff --git a/package-lock.json b/package-lock.json index a9f3407..336539e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,11 +11,16 @@ "@prisma/adapter-pg": "^7.2.0", "@prisma/client": "^7.2.0", "@tiptap/core": "^3.15.3", + "@tiptap/extension-color": "^3.27.3", + "@tiptap/extension-highlight": "^3.27.3", + "@tiptap/extension-text-style": "^3.27.3", "@tiptap/starter-kit": "^3.15.3", "better-auth": "^1.4.10", "dotenv": "^17.2.3", "pg": "^8.16.3", - "resend": "^6.17.1" + "resend": "^6.17.1", + "sveltekit-superforms": "^2.30.2", + "zod": "^4.4.3" }, "devDependencies": { "@eslint/compat": "^1.4.0", @@ -42,6 +47,7 @@ "svelte": "^5.45.6", "svelte-check": "^4.3.4", "tailwindcss": "^4.1.17", + "tsx": "^4.23.0", "typescript": "^5.9.3", "typescript-eslint": "^8.48.1", "vite": "^7.2.6", @@ -49,6 +55,33 @@ "vitest-browser-svelte": "^2.0.1" } }, + "node_modules/@ark/schema": { + "version": "0.56.1", + "resolved": "https://registry.npmjs.org/@ark/schema/-/schema-0.56.1.tgz", + "integrity": "sha512-1Cf2g9nKD8K/3JGRu+gCCfYw5d4qR8YLLjDs5W5kpmaButCYWAPFUJqSXyBATPjglzCd4tIkp398iPYVs8MjRA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@ark/util": "0.56.1" + } + }, + "node_modules/@ark/util": { + "version": "0.56.1", + "resolved": "https://registry.npmjs.org/@ark/util/-/util-0.56.1.tgz", + "integrity": "sha512-Tp1rTik3q5Z+jAeeDxr5JZpmVIw0miti1ykSEHyZv5Pw3TIJl2xbN6KTacOxITp0l3s9ytlrWd30Zvqcy5vzoQ==", + "license": "MIT", + "optional": true + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@better-auth/core": { "version": "1.6.23", "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.23.tgz", @@ -213,9 +246,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -229,9 +262,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -245,9 +278,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -261,9 +294,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -277,9 +310,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -293,9 +326,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -309,9 +342,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -325,9 +358,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -341,9 +374,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -357,9 +390,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -373,9 +406,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -389,9 +422,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -405,9 +438,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -421,9 +454,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -437,9 +470,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -453,9 +486,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -469,9 +502,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -485,9 +518,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -501,9 +534,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -517,9 +550,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -533,9 +566,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -549,9 +582,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -565,9 +598,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -581,9 +614,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -597,9 +630,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -613,9 +646,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -806,6 +839,30 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "license": "MIT", + "optional": true + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@hono/node-server": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", @@ -875,7 +932,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -886,7 +942,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -897,7 +952,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -907,14 +961,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -965,9 +1017,15 @@ "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "devOptional": true, "license": "MIT" }, + "node_modules/@poppinss/macroable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@poppinss/macroable/-/macroable-1.1.2.tgz", + "integrity": "sha512-FAVBRzzWhYP5mA3lCwLH1A0fKBqq5anyjGet90Z81aRK5c/+LTGUE1zJhZrErjaenBSOOI9BVUs3WVmotneFQA==", + "license": "MIT", + "optional": true + }, "node_modules/@prisma/adapter-pg": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.2.0.tgz", @@ -1364,12 +1422,6 @@ } } }, - "node_modules/@remirror/core-constants": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", - "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", - "license": "MIT" - }, "node_modules/@rollup/plugin-commonjs": { "version": "28.0.9", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.9.tgz", @@ -1854,6 +1906,30 @@ "win32" ] }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause", + "optional": true + }, "node_modules/@stablelib/base64": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", @@ -1870,7 +1946,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.10.tgz", "integrity": "sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==", - "devOptional": true, "license": "MIT", "peerDependencies": { "acorn": "^8.9.0" @@ -1906,7 +1981,6 @@ "version": "2.69.1", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.69.1.tgz", "integrity": "sha512-+nz8Fx/cElzb2ZPHC+6Ll3y3NEVIe4Na75PeplLlyTmd1dBXAjz2KR14y1ZgNjb2ThfAYzulu+PFy1UE3RCUzA==", - "devOptional": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -1948,7 +2022,6 @@ "version": "6.2.4", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz", "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==", - "devOptional": true, "license": "MIT", "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", @@ -1969,7 +2042,6 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz", "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==", - "devOptional": true, "license": "MIT", "dependencies": { "obug": "^2.1.0" @@ -2282,16 +2354,16 @@ } }, "node_modules/@tiptap/core": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.15.3.tgz", - "integrity": "sha512-bmXydIHfm2rEtGju39FiQNfzkFx9CDvJe+xem1dgEZ2P6Dj7nQX9LnA1ZscW7TuzbBRkL5p3dwuBIi3f62A66A==", + "version": "3.27.3", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.27.3.tgz", + "integrity": "sha512-TJj5929M96C1KlH796wS8MywfHDh49RhmakOyzyMMc9pFmRj9UXi1gj0TCXgsZtjEOG7B+m/DRvNOvnuvR9kmg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "^3.15.3" + "@tiptap/pm": "3.27.3" } }, "node_modules/@tiptap/extension-blockquote": { @@ -2360,6 +2432,19 @@ "@tiptap/pm": "^3.15.3" } }, + "node_modules/@tiptap/extension-color": { + "version": "3.27.3", + "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-3.27.3.tgz", + "integrity": "sha512-tNXyK3VXPGygJP+vq1+YyPmrxLabx4vs+rYiVhGtmhIapTQeMVYcHbFH4s4v3h5m8JGVlTWnpI8n7cb5ExIhSQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-text-style": "3.27.3" + } + }, "node_modules/@tiptap/extension-document": { "version": "3.15.3", "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.15.3.tgz", @@ -2425,6 +2510,19 @@ "@tiptap/core": "^3.15.3" } }, + "node_modules/@tiptap/extension-highlight": { + "version": "3.27.3", + "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-3.27.3.tgz", + "integrity": "sha512-99QYxMx8F/NhdvznM8/Zhm4XiCdMU0OEiLwPvLNObJiKV8UBqjdA68cJLX6FRuOi2nqD7xfJq2KuSsFKBldi2A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, "node_modules/@tiptap/extension-horizontal-rule": { "version": "3.15.3", "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.15.3.tgz", @@ -2561,6 +2659,19 @@ "@tiptap/core": "^3.15.3" } }, + "node_modules/@tiptap/extension-text-style": { + "version": "3.27.3", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.27.3.tgz", + "integrity": "sha512-oim4RqFtMBCA4N+J8f8dTFFYZrwyfmXLxLL5SvQkn+kkpfGLv8PqJCnJ4uHxsnHXDNsWHBtVVhfTGUABZsTEHg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.27.3" + } + }, "node_modules/@tiptap/extension-underline": { "version": "3.15.3", "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.15.3.tgz", @@ -2589,29 +2700,24 @@ } }, "node_modules/@tiptap/pm": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.15.3.tgz", - "integrity": "sha512-Zm1BaU1TwFi3CQiisxjgnzzIus+q40bBKWLqXf6WEaus8Z6+vo1MT2pU52dBCMIRaW9XNDq3E5cmGtMc1AlveA==", + "version": "3.27.3", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.27.3.tgz", + "integrity": "sha512-ppiG57RxM3HSHHgcHT0hP6Ib4P56Sd5itxdV4w0hIGHKPGyLLKiAkYp+htIHa9T7IvjMdaqxIlsfyV3ZKsS1sw==", "license": "MIT", "dependencies": { - "prosemirror-changeset": "^2.3.0", - "prosemirror-collab": "^1.3.1", - "prosemirror-commands": "^1.6.2", - "prosemirror-dropcursor": "^1.8.1", - "prosemirror-gapcursor": "^1.3.2", - "prosemirror-history": "^1.4.1", - "prosemirror-inputrules": "^1.4.0", - "prosemirror-keymap": "^1.2.2", - "prosemirror-markdown": "^1.13.1", - "prosemirror-menu": "^1.2.4", - "prosemirror-model": "^1.24.1", - "prosemirror-schema-basic": "^1.2.3", - "prosemirror-schema-list": "^1.5.0", - "prosemirror-state": "^1.4.3", - "prosemirror-tables": "^1.6.4", - "prosemirror-trailing-node": "^3.0.0", - "prosemirror-transform": "^1.10.2", - "prosemirror-view": "^1.38.1" + "prosemirror-changeset": "^2.4.1", + "prosemirror-commands": "^1.7.1", + "prosemirror-dropcursor": "^1.8.2", + "prosemirror-gapcursor": "^1.4.1", + "prosemirror-history": "^1.5.0", + "prosemirror-inputrules": "^1.5.1", + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.9", + "prosemirror-schema-list": "^1.5.1", + "prosemirror-state": "^1.4.4", + "prosemirror-tables": "^1.8.5", + "prosemirror-transform": "^1.12.0", + "prosemirror-view": "^1.41.9" }, "funding": { "type": "github", @@ -2669,7 +2775,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/deep-eql": { @@ -2683,36 +2788,13 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "devOptional": true, "license": "MIT" }, "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, - "license": "MIT" - }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "license": "MIT" - }, - "node_modules/@types/markdown-it": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", - "license": "MIT", - "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" - } - }, - "node_modules/@types/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "devOptional": true, "license": "MIT" }, "node_modules/@types/node": { @@ -2759,9 +2841,48 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "devOptional": true, "license": "MIT" }, + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "license": "MIT", + "optional": true + }, + "node_modules/@typeschema/class-validator": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@typeschema/class-validator/-/class-validator-0.3.0.tgz", + "integrity": "sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==", + "license": "MIT", + "optional": true, + "dependencies": { + "@typeschema/core": "0.14.0" + }, + "peerDependencies": { + "class-validator": "^0.14.1" + }, + "peerDependenciesMeta": { + "class-validator": { + "optional": true + } + } + }, + "node_modules/@typeschema/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@typeschema/core/-/core-0.14.0.tgz", + "integrity": "sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==", + "license": "MIT", + "optional": true, + "peerDependencies": { + "@types/json-schema": "^7.0.15" + }, + "peerDependenciesMeta": { + "@types/json-schema": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.52.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz", @@ -3018,6 +3139,36 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@vinejs/compiler": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@vinejs/compiler/-/compiler-3.0.0.tgz", + "integrity": "sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@vinejs/vine": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@vinejs/vine/-/vine-3.0.1.tgz", + "integrity": "sha512-ZtvYkYpZOYdvbws3uaOAvTFuvFXoQGAtmzeiXu+XSMGxi5GVsODpoI9Xu9TplEMuD/5fmAtBbKb9cQHkWkLXDQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@poppinss/macroable": "^1.0.4", + "@types/validator": "^13.12.2", + "@vinejs/compiler": "^3.0.0", + "camelcase": "^8.0.0", + "dayjs": "^1.11.13", + "dlv": "^1.1.3", + "normalize-url": "^8.0.1", + "validator": "^13.12.0" + }, + "engines": { + "node": ">=18.16.0" + } + }, "node_modules/@vitest/browser": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.0.16.tgz", @@ -3180,7 +3331,6 @@ "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", - "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3236,18 +3386,40 @@ "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, "license": "Python-2.0" }, "node_modules/aria-query": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" } }, + "node_modules/arkregex": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arkregex/-/arkregex-0.0.7.tgz", + "integrity": "sha512-O/Ltrn9EUSn3ui0KVzfyrWGDUsHlzKxDVBtpQxL/6JmLRMAZAebfSNf/A/J5Ny5S6QIwrXX+RfXsu888HMs35A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@ark/util": "0.56.1" + } + }, + "node_modules/arktype": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/arktype/-/arktype-2.2.2.tgz", + "integrity": "sha512-YYf1xhL2dh5aPZFlsY0RAsxv5HZqfLGLptH2ZP3JidTmsGRW8VOymhPjjMTkerL12vR2YtX0SK4c1mATtae8SA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@ark/schema": "0.56.1", + "@ark/util": "0.56.1", + "arkregex": "0.0.7" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -3272,7 +3444,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -3497,6 +3668,19 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -3553,11 +3737,22 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/class-validator": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.4.tgz", + "integrity": "sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/validator": "^13.15.3", + "libphonenumber-js": "^1.11.1", + "validator": "^13.15.22" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -3608,18 +3803,11 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/crelt": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", - "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3656,6 +3844,13 @@ "license": "MIT", "peer": true }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT", + "optional": true + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -3685,7 +3880,6 @@ "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==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3738,9 +3932,15 @@ "version": "5.8.1", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", - "devOptional": true, "license": "MIT" }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT", + "optional": true + }, "node_modules/dotenv": { "version": "17.4.2", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", @@ -3788,18 +3988,6 @@ "node": ">=10.13.0" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/env-paths": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", @@ -3821,10 +4009,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "devOptional": true, + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -3834,38 +4021,39 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "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, "license": "MIT", "engines": { "node": ">=10" @@ -4018,7 +4206,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "devOptional": true, "license": "MIT" }, "node_modules/espree": { @@ -4056,7 +4243,6 @@ "version": "2.2.13", "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.13.tgz", "integrity": "sha512-m8jH5hZgJE2RRUK/jjkGPcJEDAV+dYnZYFkosQaPTcE+Yw4xynXHOo6FUdwaWBtdR3b1MMa7wEDTSHeR2VWsGA==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -4201,7 +4387,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -4532,7 +4717,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.6" @@ -4555,6 +4739,20 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/joi": { + "version": "17.13.4", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.4.tgz", + "integrity": "sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/jose": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", @@ -4594,6 +4792,20 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4622,7 +4834,6 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -4658,6 +4869,13 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.8.tgz", + "integrity": "sha512-80xal1m93rADejw2pMp2MSzFhHCPLEspjHxnH2UtqI+DgAmElsbmLMiqk9niwH9NWAfjsRtaJI+qBrOEmRx9nQ==", + "license": "MIT", + "optional": true + }, "node_modules/lightningcss": { "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", @@ -4918,25 +5136,6 @@ "node": ">=10" } }, - "node_modules/linkify-it": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", - "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, "node_modules/linkifyjs": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", @@ -4947,7 +5146,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "devOptional": true, "license": "MIT" }, "node_modules/locate-path": { @@ -5000,44 +5198,16 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/markdown-it": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", - "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.5.0", - "linkify-it": "^5.0.2", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "license": "MIT" + "node_modules/memoize-weak": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/memoize-weak/-/memoize-weak-1.0.2.tgz", + "integrity": "sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==", + "license": "ISC" }, "node_modules/mini-svg-data-uri": { "version": "1.4.4", @@ -5076,7 +5246,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -5127,7 +5296,6 @@ "version": "3.3.15", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", - "devOptional": true, "funding": [ { "type": "github", @@ -5164,11 +5332,23 @@ "dev": true, "license": "MIT" }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "devOptional": true, "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" @@ -5385,14 +5565,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "devOptional": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -5478,7 +5656,6 @@ "version": "8.5.16", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", - "devOptional": true, "funding": [ { "type": "opencollective", @@ -5833,24 +6010,22 @@ "devOptional": true, "license": "ISC" }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT", + "optional": true + }, "node_modules/prosemirror-changeset": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz", - "integrity": "sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", "license": "MIT", "dependencies": { "prosemirror-transform": "^1.0.0" } }, - "node_modules/prosemirror-collab": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", - "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", - "license": "MIT", - "dependencies": { - "prosemirror-state": "^1.0.0" - } - }, "node_modules/prosemirror-commands": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", @@ -5874,9 +6049,9 @@ } }, "node_modules/prosemirror-gapcursor": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.0.tgz", - "integrity": "sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", "license": "MIT", "dependencies": { "prosemirror-keymap": "^1.0.0", @@ -5917,47 +6092,15 @@ "w3c-keyname": "^2.2.0" } }, - "node_modules/prosemirror-markdown": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz", - "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==", - "license": "MIT", - "dependencies": { - "@types/markdown-it": "^14.0.0", - "markdown-it": "^14.0.0", - "prosemirror-model": "^1.25.0" - } - }, - "node_modules/prosemirror-menu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz", - "integrity": "sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==", - "license": "MIT", - "dependencies": { - "crelt": "^1.0.0", - "prosemirror-commands": "^1.0.0", - "prosemirror-history": "^1.0.0", - "prosemirror-state": "^1.0.0" - } - }, "node_modules/prosemirror-model": { - "version": "1.25.4", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", - "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", + "version": "1.25.10", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.10.tgz", + "integrity": "sha512-9n6rH4DbJU1eH4SxLt6Y0HhJIo6cZsb7DJ/30uob1hOKPeO6TAaMWI2tc7kwR92BjfPOU2fFHWbZLovLi3XQfA==", "license": "MIT", "dependencies": { "orderedmap": "^2.0.0" } }, - "node_modules/prosemirror-schema-basic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", - "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.25.0" - } - }, "node_modules/prosemirror-schema-list": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", @@ -5993,37 +6136,22 @@ "prosemirror-view": "^1.41.4" } }, - "node_modules/prosemirror-trailing-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", - "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", - "license": "MIT", - "dependencies": { - "@remirror/core-constants": "3.0.0", - "escape-string-regexp": "^4.0.0" - }, - "peerDependencies": { - "prosemirror-model": "^1.22.1", - "prosemirror-state": "^1.4.2", - "prosemirror-view": "^1.33.8" - } - }, "node_modules/prosemirror-transform": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.5.tgz", - "integrity": "sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.21.0" } }, "node_modules/prosemirror-view": { - "version": "1.41.5", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.5.tgz", - "integrity": "sha512-UDQbIPnDrjE8tqUBbPmCOZgtd75htE6W3r0JCmY9bL6W1iemDM37MZEKC49d+tdQ0v/CKx4gjxLoLsfkD2NiZA==", + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.0.tgz", + "integrity": "sha512-N54DF3OXNWDuP81G1kbfCys8ZzIjuL1VnvJ2mk5STSu/fNxWIcX/EutQLA3s9KR/2wVhgDi4hzBB/1fINVxk0A==", "license": "MIT", "dependencies": { - "prosemirror-model": "^1.20.0", + "prosemirror-model": "^1.25.8", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0" } @@ -6038,15 +6166,6 @@ "node": ">=6" } }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -6200,7 +6319,6 @@ "version": "4.62.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.9" @@ -6353,7 +6471,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", - "devOptional": true, "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", @@ -6368,7 +6485,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -6430,6 +6546,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6460,7 +6586,6 @@ "version": "5.56.4", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.4.tgz", "integrity": "sha512-/d0QHehmRuJW8gVz395MTkPcPozxzdjBMBE8oEYGz8O3b9KTMzzQ9ZHJQLuFKOHOPQbU6kx/X4iid/EBBzH7iw==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", @@ -6552,6 +6677,139 @@ "node": ">=4" } }, + "node_modules/sveltekit-superforms": { + "version": "2.30.2", + "resolved": "https://registry.npmjs.org/sveltekit-superforms/-/sveltekit-superforms-2.30.2.tgz", + "integrity": "sha512-6sR70ZfjFMAfdNure/Bu26o1rY32+WGxebko1L8jUFS+qZw5fxIHBPkUaTpNBkOIlJZ/UJwoNCYCm5xK2Z7Kqw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ciscoheat" + }, + { + "type": "ko-fi", + "url": "https://ko-fi.com/ciscoheat" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=NY7F5ALHHSVQS" + } + ], + "license": "MIT", + "dependencies": { + "devalue": "^5.8.1", + "memoize-weak": "^1.0.2", + "ts-deepmerge": "^8.0.0" + }, + "optionalDependencies": { + "@exodus/schemasafe": "^1.3.0", + "@standard-schema/spec": "^1.1.0", + "@typeschema/class-validator": "^0.3.0", + "@valibot/to-json-schema": "^1.7.1", + "@vinejs/vine": "^3.0.1", + "arktype": "^2.2.2", + "class-validator": "^0.14.4", + "effect": "^3.21.4", + "joi": "^17.13.4", + "json-schema-to-ts": "^3.1.1", + "superstruct": "^2.0.2", + "typebox": "^1.3.3", + "valibot": "^1.4.2", + "yup": "^1.7.1", + "zod": "^4.4.3", + "zod-v3-to-json-schema": "^4.0.0" + }, + "peerDependencies": { + "@exodus/schemasafe": "^1.3.0", + "@sveltejs/kit": "1.x || 2.x", + "@typeschema/class-validator": "^0.3.0", + "@vinejs/vine": "^1.8.0 || ^2.0.0 || ^3.0.0", + "arktype": ">=2.0.0-rc.23", + "class-validator": "^0.14.1", + "effect": "^3.21.0", + "joi": "^17.13.1", + "superstruct": "^2.0.2", + "svelte": "3.x || 4.x || >=5.0.0-next.51", + "typebox": "^1.0.36", + "valibot": "^1.2.0", + "yup": "^1.4.0", + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@exodus/schemasafe": { + "optional": true + }, + "@typeschema/class-validator": { + "optional": true + }, + "@vinejs/vine": { + "optional": true + }, + "arktype": { + "optional": true + }, + "class-validator": { + "optional": true + }, + "effect": { + "optional": true + }, + "joi": { + "optional": true + }, + "superstruct": { + "optional": true + }, + "typebox": { + "optional": true + }, + "valibot": { + "optional": true + }, + "yup": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/sveltekit-superforms/node_modules/@valibot/to-json-schema": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@valibot/to-json-schema/-/to-json-schema-1.7.1.tgz", + "integrity": "sha512-3qkmU6KXWh8GIThEAW3kuRHPQBMjWkKy+Ppz3WkUucx53DTpOa6siMn4xDGSOhlVyMrDaJTCTMLYPZVAIk1P0A==", + "license": "MIT", + "optional": true, + "peerDependencies": { + "valibot": "^1.4.0" + } + }, + "node_modules/sveltekit-superforms/node_modules/effect": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.21.4.tgz", + "integrity": "sha512-B89v/xSgPbl1J2Ai2u18jxq3odpFauU1rC6/eSs4FeNHi72kwKdJp12VGigvRV2lK+kRnx+OOz41XV8guZd4gQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/sveltekit-superforms/node_modules/valibot": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.2.tgz", + "integrity": "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==", + "license": "MIT", + "optional": true, + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tailwindcss": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", @@ -6573,6 +6831,13 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT", + "optional": true + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -6594,7 +6859,6 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "devOptional": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -6617,16 +6881,29 @@ "node": ">=14.0.0" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT", + "optional": true + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT", + "optional": true + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -6640,6 +6917,48 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-deepmerge": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-8.0.0.tgz", + "integrity": "sha512-133O+10nJmVI8w5xeVZPEv5PIrv7iaUae07wv1aH8XJH95Ur6YIhWAPhPyP1YPlbPS9fCVcNIZTu7m8urRVF0A==", + "license": "ISC", + "engines": { + "node": ">=14.13.1" + } + }, + "node_modules/tsx": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz", + "integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6653,6 +6972,26 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typebox": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.4.tgz", + "integrity": "sha512-j3MCKfJMIHdrr4ZQMzaJnvXrUbMNuncwssmQkny3Cv5vxrDE1o1WhZFEqGSlU884xtYS5sAa3O/XsUPbUbPWKQ==", + "license": "MIT", + "optional": true + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -6691,12 +7030,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "license": "MIT" - }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -6736,11 +7069,20 @@ } } }, + "node_modules/validator": { + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vite": { "version": "7.3.6", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", - "devOptional": true, "license": "MIT", "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", @@ -6829,7 +7171,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", - "devOptional": true, "license": "MIT", "workspaces": [ "tests/deps/*", @@ -7030,6 +7371,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yup": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.1.tgz", + "integrity": "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, "node_modules/zeptomatch": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", @@ -7045,7 +7399,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", - "devOptional": true, "license": "MIT" }, "node_modules/zod": { @@ -7056,6 +7409,16 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-v3-to-json-schema": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/zod-v3-to-json-schema/-/zod-v3-to-json-schema-4.0.0.tgz", + "integrity": "sha512-KixLrhX/uPmRFnDgsZrzrk4x5SSJA+PmaE5adbfID9+3KPJcdxqRobaHU397EfWBqfQircrjKqvEqZ/mW5QH6w==", + "license": "ISC", + "optional": true, + "peerDependencies": { + "zod": "^3.25 || ^4.0.14" + } } } } diff --git a/package.json b/package.json index 0878ce5..b0c5cb7 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "svelte": "^5.45.6", "svelte-check": "^4.3.4", "tailwindcss": "^4.1.17", + "tsx": "^4.23.0", "typescript": "^5.9.3", "typescript-eslint": "^8.48.1", "vite": "^7.2.6", @@ -52,10 +53,15 @@ "@prisma/adapter-pg": "^7.2.0", "@prisma/client": "^7.2.0", "@tiptap/core": "^3.15.3", + "@tiptap/extension-color": "^3.27.3", + "@tiptap/extension-highlight": "^3.27.3", + "@tiptap/extension-text-style": "^3.27.3", "@tiptap/starter-kit": "^3.15.3", "better-auth": "^1.4.10", "dotenv": "^17.2.3", "pg": "^8.16.3", - "resend": "^6.17.1" + "resend": "^6.17.1", + "sveltekit-superforms": "^2.30.2", + "zod": "^4.4.3" } } diff --git a/prisma.config.ts b/prisma.config.ts index ec6a8aa..5a115ed 100644 --- a/prisma.config.ts +++ b/prisma.config.ts @@ -6,7 +6,8 @@ import { defineConfig } from 'prisma/config'; export default defineConfig({ schema: 'prisma/schema.prisma', migrations: { - path: 'prisma/migrations' + path: 'prisma/migrations', + seed: 'tsx prisma/seed.ts' }, datasource: { url: process.env['DATABASE_URL'] diff --git a/prisma/migrations/20260707164743_admin_audit_3/migration.sql b/prisma/migrations/20260707164743_admin_audit_3/migration.sql new file mode 100644 index 0000000..3f07e90 --- /dev/null +++ b/prisma/migrations/20260707164743_admin_audit_3/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable: Remove price from Proclamation +ALTER TABLE "Proclamation" DROP COLUMN "price"; + +-- AlterTable: Change SolfeggioFrequency value from Float to Int +ALTER TABLE "SolfeggioFrequency" ALTER COLUMN "value" SET DATA TYPE INTEGER; diff --git a/prisma/migrations/20260707182814_profiles_address_three_defaults/migration.sql b/prisma/migrations/20260707182814_profiles_address_three_defaults/migration.sql new file mode 100644 index 0000000..9bdcc99 --- /dev/null +++ b/prisma/migrations/20260707182814_profiles_address_three_defaults/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - You are about to drop the column `isDefault` on the `Address` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Address" DROP COLUMN "isDefault", +ADD COLUMN "isDefaultBilling" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "isDefaultMailing" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "isDefaultShipping" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 44cd473..563b244 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -47,16 +47,18 @@ model Profile { } model Address { - id String @id @default(uuid()) - profileId String - profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade) - street String - city String - state String - postalCode String - country String - type String @default("Mailing") - isDefault Boolean @default(false) + id String @id @default(uuid()) + profileId String + profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade) + street String + city String + state String + postalCode String + country String + type String @default("Mailing") + isDefaultMailing Boolean @default(false) + isDefaultBilling Boolean @default(false) + isDefaultShipping Boolean @default(false) } model Session { diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..c53f0b3 --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,111 @@ +import 'dotenv/config'; +import pg from 'pg'; +import { PrismaPg } from '@prisma/adapter-pg'; +import { PrismaClient } from '../src/lib/generated/prisma/client'; + +const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL }); +const adapter = new PrismaPg(pool); +const prisma = new PrismaClient({ adapter }); + +const userRoles = [ + { id: 1, name: 'Super' }, + { id: 2, name: 'Admin' }, + { id: 3, name: 'Staff' }, + { id: 4, name: 'User' } +]; + +const solfeggioFrequencies = [ + { id: 1, name: 'Crown', value: 936 }, + { id: 2, name: '3rd Eye', value: 852 }, + { id: 3, name: 'Throat', value: 741 }, + { id: 4, name: 'Heart', value: 639 }, + { id: 5, name: 'Solar Plexus', value: 528 }, + { id: 6, name: 'Sacral', value: 417 }, + { id: 7, name: 'Root', value: 396 } +]; + +const subscriptionLevels = [ + { id: 1, name: 'Basic', description: 'General only' }, + { id: 2, name: 'Advanced', description: 'General + Specific' }, + { id: 3, name: 'Elite', description: 'General + Specific + Precise' } +]; + +const proclamationCategories = [ + { id: 4, name: 'Spiritual', parentId: null }, + { id: 5, name: 'General', parentId: 4 }, + { id: 9, name: 'Specific', parentId: 4 }, + { id: 40, name: 'Precise', parentId: 4 }, + { id: 2, name: 'Physical', parentId: null }, + { id: 3, name: 'General', parentId: 2 }, + { id: 10, name: 'Specific', parentId: 2 }, + { id: 32, name: 'Precise', parentId: 2 }, + { id: 16, name: 'Mental', parentId: null }, + { id: 30, name: 'General', parentId: 16 }, + { id: 31, name: 'Specific', parentId: 16 }, + { id: 38, name: 'Precise', parentId: 16 }, + { id: 17, name: 'Custom (Client Specific)', parentId: null }, + { id: 19, name: 'Financial', parentId: null }, + { id: 28, name: 'General', parentId: 19 }, + { id: 29, name: 'Specific', parentId: 19 }, + { id: 37, name: 'Precise', parentId: 19 }, + { id: 20, name: 'Emotional', parentId: null }, + { id: 24, name: 'General', parentId: 20 }, + { id: 26, name: 'Specific', parentId: 20 }, + { id: 45, name: 'Precise', parentId: 20 }, + { id: 21, name: 'Social', parentId: null }, + { id: 22, name: 'General', parentId: 21 }, + { id: 23, name: 'Specific', parentId: 21 }, + { id: 39, name: 'Precise', parentId: 21 }, + { id: 41, name: 'Biblical', parentId: null }, + { id: 42, name: 'Personal Growth & Development', parentId: null }, + { id: 43, name: 'Prayers', parentId: 41 }, + { id: 44, name: 'Scripture', parentId: 41 }, + { id: 46, name: 'Sports', parentId: null } +]; + +async function main() { + console.log('Seeding UserRole...'); + for (const role of userRoles) { + await prisma.userRole.upsert({ + where: { id: role.id }, + create: role, + update: role + }); + } + + console.log('Seeding SolfeggioFrequency...'); + for (const freq of solfeggioFrequencies) { + await prisma.solfeggioFrequency.upsert({ + where: { id: freq.id }, + create: freq, + update: freq + }); + } + + console.log('Seeding ProclamationCategory...'); + for (const cat of proclamationCategories) { + await prisma.proclamationCategory.upsert({ + where: { id: cat.id }, + create: cat, + update: cat + }); + } + + console.log('Seeding SubscriptionLevel...'); + for (const level of subscriptionLevels) { + await prisma.subscriptionLevel.upsert({ + where: { id: level.id }, + create: level, + update: level + }); + } + + console.log('Seed complete.'); +} + +main() + .catch((e) => { + console.error('Seed failed:', e); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/skills-lock.json b/skills-lock.json index d8535de..d80bcdd 100644 --- a/skills-lock.json +++ b/skills-lock.json @@ -1,41 +1,41 @@ { - "version": 1, - "skills": { - "better-auth-best-practices": { - "source": "better-auth/skills", - "sourceType": "github", - "skillPath": "better-auth/best-practices/SKILL.md", - "computedHash": "a4c830509e85557b59339d8d93a4e243e9e59c686e7678854d39230e12c2a6dc" - }, - "better-auth-security-best-practices": { - "source": "better-auth/skills", - "sourceType": "github", - "skillPath": "security/SKILL.md", - "computedHash": "5717187bba9c22030c7174c74012f01c359f21e2ce87e0eb80e24244d8b8c915" - }, - "create-auth-skill": { - "source": "better-auth/skills", - "sourceType": "github", - "skillPath": "better-auth/create-auth/SKILL.md", - "computedHash": "31c027d02dbf1faa37f58191f574b9443143042fb2b684fe32df53ab0270487c" - }, - "email-and-password-best-practices": { - "source": "better-auth/skills", - "sourceType": "github", - "skillPath": "better-auth/emailAndPassword/SKILL.md", - "computedHash": "747d7f73bd9e2ec5317b8ef88dc70f97df716d00e3d02de4051feebaa48b062d" - }, - "organization-best-practices": { - "source": "better-auth/skills", - "sourceType": "github", - "skillPath": "better-auth/organization/SKILL.md", - "computedHash": "79a5a85b43d10e9fe37582b3506b051a33a991817b938f349099baa5ddba21aa" - }, - "two-factor-authentication-best-practices": { - "source": "better-auth/skills", - "sourceType": "github", - "skillPath": "better-auth/twoFactor/SKILL.md", - "computedHash": "7e297aaf887e11fdc03e52bdbf44974e161e8f7c393170ced7dc66cace4f6d46" - } - } + "version": 1, + "skills": { + "better-auth-best-practices": { + "source": "better-auth/skills", + "sourceType": "github", + "skillPath": "better-auth/best-practices/SKILL.md", + "computedHash": "a4c830509e85557b59339d8d93a4e243e9e59c686e7678854d39230e12c2a6dc" + }, + "better-auth-security-best-practices": { + "source": "better-auth/skills", + "sourceType": "github", + "skillPath": "security/SKILL.md", + "computedHash": "5717187bba9c22030c7174c74012f01c359f21e2ce87e0eb80e24244d8b8c915" + }, + "create-auth-skill": { + "source": "better-auth/skills", + "sourceType": "github", + "skillPath": "better-auth/create-auth/SKILL.md", + "computedHash": "31c027d02dbf1faa37f58191f574b9443143042fb2b684fe32df53ab0270487c" + }, + "email-and-password-best-practices": { + "source": "better-auth/skills", + "sourceType": "github", + "skillPath": "better-auth/emailAndPassword/SKILL.md", + "computedHash": "747d7f73bd9e2ec5317b8ef88dc70f97df716d00e3d02de4051feebaa48b062d" + }, + "organization-best-practices": { + "source": "better-auth/skills", + "sourceType": "github", + "skillPath": "better-auth/organization/SKILL.md", + "computedHash": "79a5a85b43d10e9fe37582b3506b051a33a991817b938f349099baa5ddba21aa" + }, + "two-factor-authentication-best-practices": { + "source": "better-auth/skills", + "sourceType": "github", + "skillPath": "better-auth/twoFactor/SKILL.md", + "computedHash": "7e297aaf887e11fdc03e52bdbf44974e161e8f7c393170ced7dc66cace4f6d46" + } + } } diff --git a/src/app.d.ts b/src/app.d.ts index 27fbade..1dc9c84 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,4 +1,4 @@ -import type { Session, User } from "better-auth"; +import type { Session, User } from 'better-auth'; declare global { namespace App { @@ -9,4 +9,4 @@ declare global { } } -export { }; +export {}; diff --git a/src/app.html b/src/app.html index 3f1e509..b063808 100644 --- a/src/app.html +++ b/src/app.html @@ -1,24 +1,25 @@ + + + + + %sveltekit.head% + - - - - - %sveltekit.head% - - - -
%sveltekit.body%
- - - \ No newline at end of file + +
%sveltekit.body%
+ + diff --git a/src/hooks.server.spec.ts b/src/hooks.server.spec.ts index c8acb97..2b2d155 100644 --- a/src/hooks.server.spec.ts +++ b/src/hooks.server.spec.ts @@ -87,9 +87,7 @@ describe('hooks.server handle', () => { const event = createMockEvent(); await handle({ event, resolve: event.resolve }); - expect(svelteKitHandler).toHaveBeenCalledWith( - expect.objectContaining({ building: false }) - ); + expect(svelteKitHandler).toHaveBeenCalledWith(expect.objectContaining({ building: false })); }); it('calls svelteKitHandler with auth instance', async () => { diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 441d150..d2aa5b6 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,18 +1,18 @@ -import { auth } from "$lib/auth"; -import { svelteKitHandler } from "better-auth/svelte-kit"; -import { building } from "$app/environment"; +import { auth } from '$lib/auth'; +import { svelteKitHandler } from 'better-auth/svelte-kit'; +import { building } from '$app/environment'; export async function handle({ event, resolve }) { - // Fetch current session from Better Auth - const session = await auth.api.getSession({ - headers: event.request.headers, - }); + // Fetch current session from Better Auth + const session = await auth.api.getSession({ + headers: event.request.headers + }); - // Make session and user available on server - if (session) { - event.locals.session = session.session; - event.locals.user = session.user; - } + // Make session and user available on server + if (session) { + event.locals.session = session.session; + event.locals.user = session.user; + } - return svelteKitHandler({ event, resolve, auth, building }); -} \ No newline at end of file + return svelteKitHandler({ event, resolve, auth, building }); +} diff --git a/src/lib/auth-client.ts b/src/lib/auth-client.ts index c951883..4f92518 100644 --- a/src/lib/auth-client.ts +++ b/src/lib/auth-client.ts @@ -1,3 +1,3 @@ -import { createAuthClient } from "better-auth/svelte" +import { createAuthClient } from 'better-auth/svelte'; -export const authClient = createAuthClient({}); \ No newline at end of file +export const authClient = createAuthClient({}); diff --git a/src/lib/auth.ts b/src/lib/auth.ts index f989548..6eb0f47 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -46,9 +46,6 @@ export const auth = betterAuth({ window: 60, max: 100 }, - trustedOrigins: [ - 'http://localhost:5173', - 'https://portal.rhemawavetech.com' - ], + trustedOrigins: ['http://localhost:5173', 'https://portal.rhemawavetech.com'], plugins: [sveltekitCookies(getRequestEvent)] }); diff --git a/src/lib/components/tiptap/TipTap.svelte b/src/lib/components/tiptap/TipTap.svelte new file mode 100644 index 0000000..4279840 --- /dev/null +++ b/src/lib/components/tiptap/TipTap.svelte @@ -0,0 +1,92 @@ + + +
+
+ + + + +
+
+
+ diff --git a/src/lib/generated/prisma/client.ts b/src/lib/generated/prisma/client.ts index f38550c..2bf39f0 100644 --- a/src/lib/generated/prisma/client.ts +++ b/src/lib/generated/prisma/client.ts @@ -28,7 +28,9 @@ export * from "./enums.ts" * Type-safe database client for TypeScript * @example * ``` - * const prisma = new PrismaClient() + * const prisma = new PrismaClient({ + * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) + * }) * // Fetch zero or more Users * const users = await prisma.user.findMany() * ``` diff --git a/src/lib/generated/prisma/commonInputTypes.ts b/src/lib/generated/prisma/commonInputTypes.ts index c4fcee8..12bb059 100644 --- a/src/lib/generated/prisma/commonInputTypes.ts +++ b/src/lib/generated/prisma/commonInputTypes.ts @@ -202,33 +202,6 @@ export type IntWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedIntFilter<$PrismaModel> } -export type FloatFilter<$PrismaModel = never> = { - equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - not?: Prisma.NestedFloatFilter<$PrismaModel> | number -} - -export type FloatWithAggregatesFilter<$PrismaModel = never> = { - equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - not?: Prisma.NestedFloatWithAggregatesFilter<$PrismaModel> | number - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedFloatFilter<$PrismaModel> - _sum?: Prisma.NestedFloatFilter<$PrismaModel> - _min?: Prisma.NestedFloatFilter<$PrismaModel> - _max?: Prisma.NestedFloatFilter<$PrismaModel> -} - export type NestedStringFilter<$PrismaModel = never> = { equals?: string | Prisma.StringFieldRefInput<$PrismaModel> in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> @@ -430,20 +403,4 @@ export type NestedFloatFilter<$PrismaModel = never> = { not?: Prisma.NestedFloatFilter<$PrismaModel> | number } -export type NestedFloatWithAggregatesFilter<$PrismaModel = never> = { - equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - not?: Prisma.NestedFloatWithAggregatesFilter<$PrismaModel> | number - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedFloatFilter<$PrismaModel> - _sum?: Prisma.NestedFloatFilter<$PrismaModel> - _min?: Prisma.NestedFloatFilter<$PrismaModel> - _max?: Prisma.NestedFloatFilter<$PrismaModel> -} - diff --git a/src/lib/generated/prisma/internal/class.ts b/src/lib/generated/prisma/internal/class.ts index c1ff1f9..a926bb3 100644 --- a/src/lib/generated/prisma/internal/class.ts +++ b/src/lib/generated/prisma/internal/class.ts @@ -17,18 +17,26 @@ import type * as Prisma from "./prismaNamespace.ts" const config: runtime.GetPrismaClientConfig = { "previewFeatures": [], - "clientVersion": "7.2.0", - "engineVersion": "0c8ef2ce45c83248ab3df073180d5eda9e8be7a3", + "clientVersion": "7.8.0", + "engineVersion": "3c6e192761c0362d496ed980de936e2f3cebcd3a", "activeProvider": "postgresql", - "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../src/lib/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel User {\n id String @id\n name String\n email String\n emailVerified Boolean @default(false)\n image String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n roleId Int?\n role UserRole? @relation(fields: [roleId], references: [id])\n sessions Session[]\n accounts Account[]\n profile Profile?\n licenseKeys LicenseKey[]\n userProclamations UserProclamations[]\n\n @@unique([email])\n @@map(\"user\")\n}\n\n// I chose to create a Profile table here because honestly, I didn't want to waste\n// a bunch of time trying to figure out how to customize the default Better-Auth model. \nmodel Profile {\n id String @id @default(uuid())\n userId String @unique\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n firstName String\n lastName String\n phoneNumber String\n addresses Address[]\n}\n\nmodel Address {\n id String @id @default(uuid())\n profileId String\n profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)\n street String\n city String\n state String\n postalCode String\n country String\n}\n\nmodel Session {\n id String @id\n expiresAt DateTime\n token String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n ipAddress String?\n userAgent String?\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([token])\n @@index([userId])\n @@map(\"session\")\n}\n\nmodel Account {\n id String @id\n accountId String\n providerId String\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n accessToken String?\n refreshToken String?\n idToken String?\n accessTokenExpiresAt DateTime?\n refreshTokenExpiresAt DateTime?\n scope String?\n password String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([userId])\n @@map(\"account\")\n}\n\nmodel UserRole {\n id Int @id @default(autoincrement())\n name String\n users User[]\n}\n\nmodel Verification {\n id String @id\n identifier String\n value String\n expiresAt DateTime\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([identifier])\n @@map(\"verification\")\n}\n\nmodel Proclamation {\n id String @id @default(uuid())\n name String @unique\n content String\n solfeggioFrequencyId Int\n solfeggioFrequency SolfeggioFrequency @relation(fields: [solfeggioFrequencyId], references: [id])\n categoryId Int\n category ProclamationCategory @relation(fields: [categoryId], references: [id])\n price Float @default(0.99)\n userProclamations UserProclamations[]\n subscriptionLevelId Int @default(1)\n subscriptionLevel SubscriptionLevel @relation(fields: [subscriptionLevelId], references: [id])\n\n @@index(subscriptionLevelId)\n}\n\nmodel UserProclamations {\n userId String\n user User @relation(fields: [userId], references: [id])\n proclamationId String\n proclamation Proclamation @relation(fields: [proclamationId], references: [id])\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@id([userId, proclamationId])\n}\n\nmodel SolfeggioFrequency {\n id Int @id @default(autoincrement())\n name String @unique\n value Float @unique\n proclamations Proclamation[]\n}\n\nmodel ProclamationCategory {\n id Int @id @default(autoincrement())\n name String\n parentId Int?\n parent ProclamationCategory? @relation(\"CategoryHierarchy\", fields: [parentId], references: [id])\n children ProclamationCategory[] @relation(\"CategoryHierarchy\")\n proclamations Proclamation[]\n\n @@unique([parentId, name])\n}\n\nmodel LicenseKey {\n id String @id @default(uuid())\n key String @unique\n active Boolean\n level String\n userId String\n user User @relation(fields: [userId], references: [id])\n}\n\nmodel SubscriptionLevel {\n id Int @id @default(autoincrement())\n name String\n description String?\n proclamations Proclamation[]\n}\n", + "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../src/lib/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel User {\n id String @id\n name String\n email String\n emailVerified Boolean @default(false)\n image String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n roleId Int?\n role UserRole? @relation(fields: [roleId], references: [id])\n sessions Session[]\n accounts Account[]\n profile Profile?\n licenseKeys LicenseKey[]\n userProclamations UserProclamations[]\n\n @@unique([email])\n @@map(\"user\")\n}\n\n// I chose to create a Profile table here because honestly, I didn't want to waste\n// a bunch of time trying to figure out how to customize the default Better-Auth model. \nmodel Profile {\n id String @id @default(uuid())\n userId String @unique\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n firstName String\n lastName String\n phoneNumber String\n ghlContactId String? @map(\"ghl_contact_id\")\n addresses Address[]\n}\n\nmodel Address {\n id String @id @default(uuid())\n profileId String\n profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)\n street String\n city String\n state String\n postalCode String\n country String\n type String @default(\"Mailing\")\n isDefaultMailing Boolean @default(false)\n isDefaultBilling Boolean @default(false)\n isDefaultShipping Boolean @default(false)\n}\n\nmodel Session {\n id String @id\n expiresAt DateTime\n token String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n ipAddress String?\n userAgent String?\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([token])\n @@index([userId])\n @@map(\"session\")\n}\n\nmodel Account {\n id String @id\n accountId String\n providerId String\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n accessToken String?\n refreshToken String?\n idToken String?\n accessTokenExpiresAt DateTime?\n refreshTokenExpiresAt DateTime?\n scope String?\n password String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([userId])\n @@map(\"account\")\n}\n\nmodel UserRole {\n id Int @id @default(autoincrement())\n name String\n users User[]\n}\n\nmodel Verification {\n id String @id\n identifier String\n value String\n expiresAt DateTime\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([identifier])\n @@map(\"verification\")\n}\n\nmodel Proclamation {\n id String @id @default(uuid())\n name String @unique\n content String\n solfeggioFrequencyId Int\n solfeggioFrequency SolfeggioFrequency @relation(fields: [solfeggioFrequencyId], references: [id])\n categoryId Int\n category ProclamationCategory @relation(fields: [categoryId], references: [id])\n userProclamations UserProclamations[]\n subscriptionLevelId Int @default(1)\n subscriptionLevel SubscriptionLevel @relation(fields: [subscriptionLevelId], references: [id])\n\n @@index(subscriptionLevelId)\n}\n\nmodel UserProclamations {\n userId String\n user User @relation(fields: [userId], references: [id])\n proclamationId String\n proclamation Proclamation @relation(fields: [proclamationId], references: [id])\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@id([userId, proclamationId])\n}\n\nmodel SolfeggioFrequency {\n id Int @id @default(autoincrement())\n name String @unique\n value Int @unique\n proclamations Proclamation[]\n}\n\nmodel ProclamationCategory {\n id Int @id @default(autoincrement())\n name String\n parentId Int?\n parent ProclamationCategory? @relation(\"CategoryHierarchy\", fields: [parentId], references: [id])\n children ProclamationCategory[] @relation(\"CategoryHierarchy\")\n proclamations Proclamation[]\n\n @@unique([parentId, name])\n}\n\nmodel LicenseKey {\n id String @id @default(uuid())\n key String @unique\n active Boolean\n level String\n userId String\n user User @relation(fields: [userId], references: [id])\n}\n\nmodel SubscriptionLevel {\n id Int @id @default(autoincrement())\n name String\n description String?\n proclamations Proclamation[]\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, "types": {} + }, + "parameterizationSchema": { + "strings": [], + "graph": "" } } -config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"roleId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"role\",\"kind\":\"object\",\"type\":\"UserRole\",\"relationName\":\"UserToUserRole\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"accounts\",\"kind\":\"object\",\"type\":\"Account\",\"relationName\":\"AccountToUser\"},{\"name\":\"profile\",\"kind\":\"object\",\"type\":\"Profile\",\"relationName\":\"ProfileToUser\"},{\"name\":\"licenseKeys\",\"kind\":\"object\",\"type\":\"LicenseKey\",\"relationName\":\"LicenseKeyToUser\"},{\"name\":\"userProclamations\",\"kind\":\"object\",\"type\":\"UserProclamations\",\"relationName\":\"UserToUserProclamations\"}],\"dbName\":\"user\"},\"Profile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ProfileToUser\"},{\"name\":\"firstName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lastName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"phoneNumber\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"addresses\",\"kind\":\"object\",\"type\":\"Address\",\"relationName\":\"AddressToProfile\"}],\"dbName\":null},\"Address\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profileId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profile\",\"kind\":\"object\",\"type\":\"Profile\",\"relationName\":\"AddressToProfile\"},{\"name\":\"street\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"city\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"state\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"postalCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"country\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null},\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"ipAddress\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userAgent\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":\"session\"},\"Account\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"accountId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"providerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AccountToUser\"},{\"name\":\"accessToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"refreshToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"idToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"accessTokenExpiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenExpiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"scope\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"account\"},\"UserRole\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserRole\"}],\"dbName\":null},\"Verification\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"identifier\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"value\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"verification\"},\"Proclamation\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"content\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"solfeggioFrequencyId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"solfeggioFrequency\",\"kind\":\"object\",\"type\":\"SolfeggioFrequency\",\"relationName\":\"ProclamationToSolfeggioFrequency\"},{\"name\":\"categoryId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"category\",\"kind\":\"object\",\"type\":\"ProclamationCategory\",\"relationName\":\"ProclamationToProclamationCategory\"},{\"name\":\"price\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"userProclamations\",\"kind\":\"object\",\"type\":\"UserProclamations\",\"relationName\":\"ProclamationToUserProclamations\"},{\"name\":\"subscriptionLevelId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"subscriptionLevel\",\"kind\":\"object\",\"type\":\"SubscriptionLevel\",\"relationName\":\"ProclamationToSubscriptionLevel\"}],\"dbName\":null},\"UserProclamations\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserProclamations\"},{\"name\":\"proclamationId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proclamation\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToUserProclamations\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"SolfeggioFrequency\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"value\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"proclamations\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToSolfeggioFrequency\"}],\"dbName\":null},\"ProclamationCategory\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"parentId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"parent\",\"kind\":\"object\",\"type\":\"ProclamationCategory\",\"relationName\":\"CategoryHierarchy\"},{\"name\":\"children\",\"kind\":\"object\",\"type\":\"ProclamationCategory\",\"relationName\":\"CategoryHierarchy\"},{\"name\":\"proclamations\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToProclamationCategory\"}],\"dbName\":null},\"LicenseKey\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"key\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"active\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"level\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"LicenseKeyToUser\"}],\"dbName\":null},\"SubscriptionLevel\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proclamations\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToSubscriptionLevel\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"roleId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"role\",\"kind\":\"object\",\"type\":\"UserRole\",\"relationName\":\"UserToUserRole\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"accounts\",\"kind\":\"object\",\"type\":\"Account\",\"relationName\":\"AccountToUser\"},{\"name\":\"profile\",\"kind\":\"object\",\"type\":\"Profile\",\"relationName\":\"ProfileToUser\"},{\"name\":\"licenseKeys\",\"kind\":\"object\",\"type\":\"LicenseKey\",\"relationName\":\"LicenseKeyToUser\"},{\"name\":\"userProclamations\",\"kind\":\"object\",\"type\":\"UserProclamations\",\"relationName\":\"UserToUserProclamations\"}],\"dbName\":\"user\"},\"Profile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ProfileToUser\"},{\"name\":\"firstName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lastName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"phoneNumber\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"ghlContactId\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"ghl_contact_id\"},{\"name\":\"addresses\",\"kind\":\"object\",\"type\":\"Address\",\"relationName\":\"AddressToProfile\"}],\"dbName\":null},\"Address\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profileId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profile\",\"kind\":\"object\",\"type\":\"Profile\",\"relationName\":\"AddressToProfile\"},{\"name\":\"street\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"city\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"state\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"postalCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"country\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"isDefaultMailing\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"isDefaultBilling\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"isDefaultShipping\",\"kind\":\"scalar\",\"type\":\"Boolean\"}],\"dbName\":null},\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"ipAddress\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userAgent\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":\"session\"},\"Account\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"accountId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"providerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AccountToUser\"},{\"name\":\"accessToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"refreshToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"idToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"accessTokenExpiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenExpiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"scope\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"account\"},\"UserRole\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserRole\"}],\"dbName\":null},\"Verification\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"identifier\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"value\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"verification\"},\"Proclamation\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"content\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"solfeggioFrequencyId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"solfeggioFrequency\",\"kind\":\"object\",\"type\":\"SolfeggioFrequency\",\"relationName\":\"ProclamationToSolfeggioFrequency\"},{\"name\":\"categoryId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"category\",\"kind\":\"object\",\"type\":\"ProclamationCategory\",\"relationName\":\"ProclamationToProclamationCategory\"},{\"name\":\"userProclamations\",\"kind\":\"object\",\"type\":\"UserProclamations\",\"relationName\":\"ProclamationToUserProclamations\"},{\"name\":\"subscriptionLevelId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"subscriptionLevel\",\"kind\":\"object\",\"type\":\"SubscriptionLevel\",\"relationName\":\"ProclamationToSubscriptionLevel\"}],\"dbName\":null},\"UserProclamations\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserProclamations\"},{\"name\":\"proclamationId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proclamation\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToUserProclamations\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"SolfeggioFrequency\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"value\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"proclamations\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToSolfeggioFrequency\"}],\"dbName\":null},\"ProclamationCategory\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"parentId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"parent\",\"kind\":\"object\",\"type\":\"ProclamationCategory\",\"relationName\":\"CategoryHierarchy\"},{\"name\":\"children\",\"kind\":\"object\",\"type\":\"ProclamationCategory\",\"relationName\":\"CategoryHierarchy\"},{\"name\":\"proclamations\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToProclamationCategory\"}],\"dbName\":null},\"LicenseKey\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"key\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"active\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"level\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"LicenseKeyToUser\"}],\"dbName\":null},\"SubscriptionLevel\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proclamations\",\"kind\":\"object\",\"type\":\"Proclamation\",\"relationName\":\"ProclamationToSubscriptionLevel\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.parameterizationSchema = { + strings: JSON.parse("[\"where\",\"orderBy\",\"cursor\",\"users\",\"_count\",\"role\",\"user\",\"sessions\",\"accounts\",\"profile\",\"addresses\",\"licenseKeys\",\"proclamations\",\"solfeggioFrequency\",\"parent\",\"children\",\"category\",\"userProclamations\",\"subscriptionLevel\",\"proclamation\",\"User.findUnique\",\"User.findUniqueOrThrow\",\"User.findFirst\",\"User.findFirstOrThrow\",\"User.findMany\",\"data\",\"User.createOne\",\"User.createMany\",\"User.createManyAndReturn\",\"User.updateOne\",\"User.updateMany\",\"User.updateManyAndReturn\",\"create\",\"update\",\"User.upsertOne\",\"User.deleteOne\",\"User.deleteMany\",\"having\",\"_avg\",\"_sum\",\"_min\",\"_max\",\"User.groupBy\",\"User.aggregate\",\"Profile.findUnique\",\"Profile.findUniqueOrThrow\",\"Profile.findFirst\",\"Profile.findFirstOrThrow\",\"Profile.findMany\",\"Profile.createOne\",\"Profile.createMany\",\"Profile.createManyAndReturn\",\"Profile.updateOne\",\"Profile.updateMany\",\"Profile.updateManyAndReturn\",\"Profile.upsertOne\",\"Profile.deleteOne\",\"Profile.deleteMany\",\"Profile.groupBy\",\"Profile.aggregate\",\"Address.findUnique\",\"Address.findUniqueOrThrow\",\"Address.findFirst\",\"Address.findFirstOrThrow\",\"Address.findMany\",\"Address.createOne\",\"Address.createMany\",\"Address.createManyAndReturn\",\"Address.updateOne\",\"Address.updateMany\",\"Address.updateManyAndReturn\",\"Address.upsertOne\",\"Address.deleteOne\",\"Address.deleteMany\",\"Address.groupBy\",\"Address.aggregate\",\"Session.findUnique\",\"Session.findUniqueOrThrow\",\"Session.findFirst\",\"Session.findFirstOrThrow\",\"Session.findMany\",\"Session.createOne\",\"Session.createMany\",\"Session.createManyAndReturn\",\"Session.updateOne\",\"Session.updateMany\",\"Session.updateManyAndReturn\",\"Session.upsertOne\",\"Session.deleteOne\",\"Session.deleteMany\",\"Session.groupBy\",\"Session.aggregate\",\"Account.findUnique\",\"Account.findUniqueOrThrow\",\"Account.findFirst\",\"Account.findFirstOrThrow\",\"Account.findMany\",\"Account.createOne\",\"Account.createMany\",\"Account.createManyAndReturn\",\"Account.updateOne\",\"Account.updateMany\",\"Account.updateManyAndReturn\",\"Account.upsertOne\",\"Account.deleteOne\",\"Account.deleteMany\",\"Account.groupBy\",\"Account.aggregate\",\"UserRole.findUnique\",\"UserRole.findUniqueOrThrow\",\"UserRole.findFirst\",\"UserRole.findFirstOrThrow\",\"UserRole.findMany\",\"UserRole.createOne\",\"UserRole.createMany\",\"UserRole.createManyAndReturn\",\"UserRole.updateOne\",\"UserRole.updateMany\",\"UserRole.updateManyAndReturn\",\"UserRole.upsertOne\",\"UserRole.deleteOne\",\"UserRole.deleteMany\",\"UserRole.groupBy\",\"UserRole.aggregate\",\"Verification.findUnique\",\"Verification.findUniqueOrThrow\",\"Verification.findFirst\",\"Verification.findFirstOrThrow\",\"Verification.findMany\",\"Verification.createOne\",\"Verification.createMany\",\"Verification.createManyAndReturn\",\"Verification.updateOne\",\"Verification.updateMany\",\"Verification.updateManyAndReturn\",\"Verification.upsertOne\",\"Verification.deleteOne\",\"Verification.deleteMany\",\"Verification.groupBy\",\"Verification.aggregate\",\"Proclamation.findUnique\",\"Proclamation.findUniqueOrThrow\",\"Proclamation.findFirst\",\"Proclamation.findFirstOrThrow\",\"Proclamation.findMany\",\"Proclamation.createOne\",\"Proclamation.createMany\",\"Proclamation.createManyAndReturn\",\"Proclamation.updateOne\",\"Proclamation.updateMany\",\"Proclamation.updateManyAndReturn\",\"Proclamation.upsertOne\",\"Proclamation.deleteOne\",\"Proclamation.deleteMany\",\"Proclamation.groupBy\",\"Proclamation.aggregate\",\"UserProclamations.findUnique\",\"UserProclamations.findUniqueOrThrow\",\"UserProclamations.findFirst\",\"UserProclamations.findFirstOrThrow\",\"UserProclamations.findMany\",\"UserProclamations.createOne\",\"UserProclamations.createMany\",\"UserProclamations.createManyAndReturn\",\"UserProclamations.updateOne\",\"UserProclamations.updateMany\",\"UserProclamations.updateManyAndReturn\",\"UserProclamations.upsertOne\",\"UserProclamations.deleteOne\",\"UserProclamations.deleteMany\",\"UserProclamations.groupBy\",\"UserProclamations.aggregate\",\"SolfeggioFrequency.findUnique\",\"SolfeggioFrequency.findUniqueOrThrow\",\"SolfeggioFrequency.findFirst\",\"SolfeggioFrequency.findFirstOrThrow\",\"SolfeggioFrequency.findMany\",\"SolfeggioFrequency.createOne\",\"SolfeggioFrequency.createMany\",\"SolfeggioFrequency.createManyAndReturn\",\"SolfeggioFrequency.updateOne\",\"SolfeggioFrequency.updateMany\",\"SolfeggioFrequency.updateManyAndReturn\",\"SolfeggioFrequency.upsertOne\",\"SolfeggioFrequency.deleteOne\",\"SolfeggioFrequency.deleteMany\",\"SolfeggioFrequency.groupBy\",\"SolfeggioFrequency.aggregate\",\"ProclamationCategory.findUnique\",\"ProclamationCategory.findUniqueOrThrow\",\"ProclamationCategory.findFirst\",\"ProclamationCategory.findFirstOrThrow\",\"ProclamationCategory.findMany\",\"ProclamationCategory.createOne\",\"ProclamationCategory.createMany\",\"ProclamationCategory.createManyAndReturn\",\"ProclamationCategory.updateOne\",\"ProclamationCategory.updateMany\",\"ProclamationCategory.updateManyAndReturn\",\"ProclamationCategory.upsertOne\",\"ProclamationCategory.deleteOne\",\"ProclamationCategory.deleteMany\",\"ProclamationCategory.groupBy\",\"ProclamationCategory.aggregate\",\"LicenseKey.findUnique\",\"LicenseKey.findUniqueOrThrow\",\"LicenseKey.findFirst\",\"LicenseKey.findFirstOrThrow\",\"LicenseKey.findMany\",\"LicenseKey.createOne\",\"LicenseKey.createMany\",\"LicenseKey.createManyAndReturn\",\"LicenseKey.updateOne\",\"LicenseKey.updateMany\",\"LicenseKey.updateManyAndReturn\",\"LicenseKey.upsertOne\",\"LicenseKey.deleteOne\",\"LicenseKey.deleteMany\",\"LicenseKey.groupBy\",\"LicenseKey.aggregate\",\"SubscriptionLevel.findUnique\",\"SubscriptionLevel.findUniqueOrThrow\",\"SubscriptionLevel.findFirst\",\"SubscriptionLevel.findFirstOrThrow\",\"SubscriptionLevel.findMany\",\"SubscriptionLevel.createOne\",\"SubscriptionLevel.createMany\",\"SubscriptionLevel.createManyAndReturn\",\"SubscriptionLevel.updateOne\",\"SubscriptionLevel.updateMany\",\"SubscriptionLevel.updateManyAndReturn\",\"SubscriptionLevel.upsertOne\",\"SubscriptionLevel.deleteOne\",\"SubscriptionLevel.deleteMany\",\"SubscriptionLevel.groupBy\",\"SubscriptionLevel.aggregate\",\"AND\",\"OR\",\"NOT\",\"id\",\"name\",\"description\",\"equals\",\"in\",\"notIn\",\"lt\",\"lte\",\"gt\",\"gte\",\"contains\",\"startsWith\",\"endsWith\",\"not\",\"every\",\"some\",\"none\",\"key\",\"active\",\"level\",\"userId\",\"parentId\",\"value\",\"proclamationId\",\"createdAt\",\"updatedAt\",\"content\",\"solfeggioFrequencyId\",\"categoryId\",\"subscriptionLevelId\",\"identifier\",\"expiresAt\",\"accountId\",\"providerId\",\"accessToken\",\"refreshToken\",\"idToken\",\"accessTokenExpiresAt\",\"refreshTokenExpiresAt\",\"scope\",\"password\",\"token\",\"ipAddress\",\"userAgent\",\"profileId\",\"street\",\"city\",\"state\",\"postalCode\",\"country\",\"type\",\"isDefaultMailing\",\"isDefaultBilling\",\"isDefaultShipping\",\"firstName\",\"lastName\",\"phoneNumber\",\"ghlContactId\",\"email\",\"emailVerified\",\"image\",\"roleId\",\"parentId_name\",\"userId_proclamationId\",\"is\",\"isNot\",\"connectOrCreate\",\"upsert\",\"createMany\",\"set\",\"disconnect\",\"delete\",\"connect\",\"updateMany\",\"deleteMany\",\"increment\",\"decrement\",\"multiply\",\"divide\"]"), + graph: "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_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_wIAIYgCQAD_AgAhjgJAAP8CACGYAgEA5QIAIZkCAQDmAgAhmgIBAOYCACEDAAAACQAgAQAAjAEAMCUAAI0BACADAAAACQAgAQAACgAwAgAACwAgAQAAAA8AIAEAAAAPACADAAAADQAgAQAADgAwAgAADwAgAwAAAA0AIAEAAA4AMAIAAA8AIAMAAAANACABAAAOADACAAAPACAOBgAAhAUAIO8BAQAAAAGDAgEAAAABhwJAAAAAAYgCQAAAAAGPAgEAAAABkAIBAAAAAZECAQAAAAGSAgEAAAABkwIBAAAAAZQCQAAAAAGVAkAAAAABlgIBAAAAAZcCAQAAAAEBGQAAlQEAIA3vAQEAAAABgwIBAAAAAYcCQAAAAAGIAkAAAAABjwIBAAAAAZACAQAAAAGRAgEAAAABkgIBAAAAAZMCAQAAAAGUAkAAAAABlQJAAAAAAZYCAQAAAAGXAgEAAAABARkAAJcBADABGQAAlwEAMA4GAACDBQAg7wEBALQDACGDAgEAtAMAIYcCQADQAwAhiAJAANADACGPAgEAtAMAIZACAQC0AwAhkQIBALUDACGSAgEAtQMAIZMCAQC1AwAhlAJAAOkEACGVAkAA6QQAIZYCAQC1AwAhlwIBALUDACECAAAADwAgGQAAmgEAIA3vAQEAtAMAIYMCAQC0AwAhhwJAANADACGIAkAA0AMAIY8CAQC0AwAhkAIBALQDACGRAgEAtQMAIZICAQC1AwAhkwIBALUDACGUAkAA6QQAIZUCQADpBAAhlgIBALUDACGXAgEAtQMAIQIAAAANACAZAACcAQAgAgAAAA0AIBkAAJwBACADAAAADwAgIAAAlQEAICEAAJoBACABAAAADwAgAQAAAA0AIAoEAACABQAgKAAAggUAICkAAIEFACCRAgAArgMAIJICAACuAwAgkwIAAK4DACCUAgAArgMAIJUCAACuAwAglgIAAK4DACCXAgAArgMAIBDsAQAAiQMAMO0BAACjAQAQ7gEAAIkDADDvAQEA5QIAIYMCAQDlAgAhhwJAAP8CACGIAkAA_wIAIY8CAQDlAgAhkAIBAOUCACGRAgEA5gIAIZICAQDmAgAhkwIBAOYCACGUAkAAigMAIZUCQACKAwAhlgIBAOYCACGXAgEA5gIAIQMAAAANACABAACiAQAwJQAAowEAIAMAAAANACABAAAOADACAAAPACAGAwAAiAMAIOwBAACHAwAw7QEAAAMAEO4BAACHAwAw7wECAAAAAfABAQDxAgAhAQAAAKYBACABAAAApgEAIAEDAAD_BAAgAwAAAAMAIAEAAKkBADACAACmAQAgAwAAAAMAIAEAAKkBADACAACmAQAgAwAAAAMAIAEAAKkBADACAACmAQAgAwMAAP4EACDvAQIAAAAB8AEBAAAAAQEZAACtAQAgAu8BAgAAAAHwAQEAAAABARkAAK8BADABGQAArwEAMAMDAACmBAAg7wECALYDACHwAQEAtAMAIQIAAACmAQAgGQAAsgEAIALvAQIAtgMAIfABAQC0AwAhAgAAAAMAIBkAALQBACACAAAAAwAgGQAAtAEAIAMAAACmAQAgIAAArQEAICEAALIBACABAAAApgEAIAEAAAADACAFBAAAoQQAICYAAKIEACAnAAClBAAgKAAApAQAICkAAKMEACAF7AEAAIYDADDtAQAAuwEAEO4BAACGAwAw7wECAOQCACHwAQEA5QIAIQMAAAADACABAAC6AQAwJQAAuwEAIAMAAAADACABAACpAQAwAgAApgEAIAnsAQAAhAMAMO0BAADBAQAQ7gEAAIQDADDvAQEAAAABhQIBAPECACGHAkAAhQMAIYgCQACFAwAhjQIBAPECACGOAkAAhQMAIQEAAAC-AQAgAQAAAL4BACAJ7AEAAIQDADDtAQAAwQEAEO4BAACEAwAw7wEBAPECACGFAgEA8QIAIYcCQACFAwAhiAJAAIUDACGNAgEA8QIAIY4CQACFAwAhAAMAAADBAQAgAQAAwgEAMAIAAL4BACADAAAAwQEAIAEAAMIBADACAAC-AQAgAwAAAMEBACABAADCAQAwAgAAvgEAIAbvAQEAAAABhQIBAAAAAYcCQAAAAAGIAkAAAAABjQIBAAAAAY4CQAAAAAEBGQAAxgEAIAbvAQEAAAABhQIBAAAAAYcCQAAAAAGIAkAAAAABjQIBAAAAAY4CQAAAAAEBGQAAyAEAMAEZAADIAQAwBu8BAQC0AwAhhQIBALQDACGHAkAA0AMAIYgCQADQAwAhjQIBALQDACGOAkAA0AMAIQIAAAC-AQAgGQAAywEAIAbvAQEAtAMAIYUCAQC0AwAhhwJAANADACGIAkAA0AMAIY0CAQC0AwAhjgJAANADACECAAAAwQEAIBkAAM0BACACAAAAwQEAIBkAAM0BACADAAAAvgEAICAAAMYBACAhAADLAQAgAQAAAL4BACABAAAAwQEAIAMEAACeBAAgKAAAoAQAICkAAJ8EACAJ7AEAAIMDADDtAQAA1AEAEO4BAACDAwAw7wEBAOUCACGFAgEA5QIAIYcCQAD_AgAhiAJAAP8CACGNAgEA5QIAIY4CQAD_AgAhAwAAAMEBACABAADTAQAwJQAA1AEAIAMAAADBAQAgAQAAwgEAMAIAAL4BACABAAAAIgAgAQAAACIAIAMAAAAgACABAAAhADACAAAiACADAAAAIAAgAQAAIQAwAgAAIgAgAwAAACAAIAEAACEAMAIAACIAIAoNAADWAwAgEAAA1wMAIBEAANgDACASAAD0AwAg7wEBAAAAAfABAQAAAAGJAgEAAAABigICAAAAAYsCAgAAAAGMAgIAAAABARkAANwBACAG7wEBAAAAAfABAQAAAAGJAgEAAAABigICAAAAAYsCAgAAAAGMAgIAAAABARkAAN4BADABGQAA3gEAMAoNAADDAwAgEAAAxAMAIBEAAMUDACASAADyAwAg7wEBALQDACHwAQEAtAMAIYkCAQC0AwAhigICALYDACGLAgIAtgMAIYwCAgC2AwAhAgAAACIAIBkAAOEBACAG7wEBALQDACHwAQEAtAMAIYkCAQC0AwAhigICALYDACGLAgIAtgMAIYwCAgC2AwAhAgAAACAAIBkAAOMBACACAAAAIAAgGQAA4wEAIAMAAAAiACAgAADcAQAgIQAA4QEAIAEAAAAiACABAAAAIAAgBQQAAJkEACAmAACaBAAgJwAAnQQAICgAAJwEACApAACbBAAgCewBAACCAwAw7QEAAOoBABDuAQAAggMAMO8BAQDlAgAh8AEBAOUCACGJAgEA5QIAIYoCAgDkAgAhiwICAOQCACGMAgIA5AIAIQMAAAAgACABAADpAQAwJQAA6gEAIAMAAAAgACABAAAhADACAAAiACABAAAAHgAgAQAAAB4AIAMAAAAcACABAAAdADACAAAeACADAAAAHAAgAQAAHQAwAgAAHgAgAwAAABwAIAEAAB0AMAIAAB4AIAYGAADUAwAgEwAAmAQAIIMCAQAAAAGGAgEAAAABhwJAAAAAAYgCQAAAAAEBGQAA8gEAIASDAgEAAAABhgIBAAAAAYcCQAAAAAGIAkAAAAABARkAAPQBADABGQAA9AEAMAYGAADSAwAgEwAAlwQAIIMCAQC0AwAhhgIBALQDACGHAkAA0AMAIYgCQADQAwAhAgAAAB4AIBkAAPcBACAEgwIBALQDACGGAgEAtAMAIYcCQADQAwAhiAJAANADACECAAAAHAAgGQAA-QEAIAIAAAAcACAZAAD5AQAgAwAAAB4AICAAAPIBACAhAAD3AQAgAQAAAB4AIAEAAAAcACADBAAAlAQAICgAAJYEACApAACVBAAgB-wBAAD-AgAw7QEAAIACABDuAQAA_gIAMIMCAQDlAgAhhgIBAOUCACGHAkAA_wIAIYgCQAD_AgAhAwAAABwAIAEAAP8BADAlAACAAgAgAwAAABwAIAEAAB0AMAIAAB4AIAcMAADzAgAg7AEAAP0CADDtAQAAhgIAEO4BAAD9AgAw7wECAAAAAfABAQAAAAGFAgIAAAABAQAAAIMCACABAAAAgwIAIAcMAADzAgAg7AEAAP0CADDtAQAAhgIAEO4BAAD9AgAw7wECAPACACHwAQEA8QIAIYUCAgDwAgAhAQwAANoDACADAAAAhgIAIAEAAIcCADACAACDAgAgAwAAAIYCACABAACHAgAwAgAAgwIAIAMAAACGAgAgAQAAhwIAMAIAAIMCACAEDAAAkwQAIO8BAgAAAAHwAQEAAAABhQICAAAAAQEZAACLAgAgA-8BAgAAAAHwAQEAAAABhQICAAAAAQEZAACNAgAwARkAAI0CADAEDAAAiQQAIO8BAgC2AwAh8AEBALQDACGFAgIAtgMAIQIAAACDAgAgGQAAkAIAIAPvAQIAtgMAIfABAQC0AwAhhQICALYDACECAAAAhgIAIBkAAJICACACAAAAhgIAIBkAAJICACADAAAAgwIAICAAAIsCACAhAACQAgAgAQAAAIMCACABAAAAhgIAIAUEAACEBAAgJgAAhQQAICcAAIgEACAoAACHBAAgKQAAhgQAIAbsAQAA_AIAMO0BAACZAgAQ7gEAAPwCADDvAQIA5AIAIfABAQDlAgAhhQICAOQCACEDAAAAhgIAIAEAAJgCADAlAACZAgAgAwAAAIYCACABAACHAgAwAgAAgwIAIAEAAAAoACABAAAAKAAgAwAAACUAIAEAACcAMAIAACgAIAMAAAAlACABAAAnADACAAAoACADAAAAJQAgAQAAJwAwAgAAKAAgBgwAAIIEACAOAACDBAAgDwAAgQQAIO8BAgAAAAHwAQEAAAABhAICAAAAAQEZAAChAgAgA-8BAgAAAAHwAQEAAAABhAICAAAAAQEZAACjAgAwARkAAKMCADABAAAAJQAgBgwAAOkDACAOAADnAwAgDwAA6AMAIO8BAgC2AwAh8AEBALQDACGEAgIA5gMAIQIAAAAoACAZAACnAgAgA-8BAgC2AwAh8AEBALQDACGEAgIA5gMAIQIAAAAlACAZAACpAgAgAgAAACUAIBkAAKkCACABAAAAJQAgAwAAACgAICAAAKECACAhAACnAgAgAQAAACgAIAEAAAAlACAGBAAA4QMAICYAAOIDACAnAADlAwAgKAAA5AMAICkAAOMDACCEAgAArgMAIAbsAQAA-AIAMO0BAACxAgAQ7gEAAPgCADDvAQIA5AIAIfABAQDlAgAhhAICAPkCACEDAAAAJQAgAQAAsAIAMCUAALECACADAAAAJQAgAQAAJwAwAgAAKAAgAQAAABoAIAEAAAAaACADAAAAGAAgAQAAGQAwAgAAGgAgAwAAABgAIAEAABkAMAIAABoAIAMAAAAYACABAAAZADACAAAaACAGBgAA4AMAIO8BAQAAAAGAAgEAAAABgQIgAAAAAYICAQAAAAGDAgEAAAABARkAALkCACAF7wEBAAAAAYACAQAAAAGBAiAAAAABggIBAAAAAYMCAQAAAAEBGQAAuwIAMAEZAAC7AgAwBgYAAN8DACDvAQEAtAMAIYACAQC0AwAhgQIgAN4DACGCAgEAtAMAIYMCAQC0AwAhAgAAABoAIBkAAL4CACAF7wEBALQDACGAAgEAtAMAIYECIADeAwAhggIBALQDACGDAgEAtAMAIQIAAAAYACAZAADAAgAgAgAAABgAIBkAAMACACADAAAAGgAgIAAAuQIAICEAAL4CACABAAAAGgAgAQAAABgAIAMEAADbAwAgKAAA3QMAICkAANwDACAI7AEAAPQCADDtAQAAxwIAEO4BAAD0AgAw7wEBAOUCACGAAgEA5QIAIYECIAD1AgAhggIBAOUCACGDAgEA5QIAIQMAAAAYACABAADGAgAwJQAAxwIAIAMAAAAYACABAAAZADACAAAaACAHDAAA8wIAIOwBAADvAgAw7QEAAM0CABDuAQAA7wIAMO8BAgAAAAHwAQEA8QIAIfEBAQDyAgAhAQAAAMoCACABAAAAygIAIAcMAADzAgAg7AEAAO8CADDtAQAAzQIAEO4BAADvAgAw7wECAPACACHwAQEA8QIAIfEBAQDyAgAhAgwAANoDACDxAQAArgMAIAMAAADNAgAgAQAAzgIAMAIAAMoCACADAAAAzQIAIAEAAM4CADACAADKAgAgAwAAAM0CACABAADOAgAwAgAAygIAIAQMAADZAwAg7wECAAAAAfABAQAAAAHxAQEAAAABARkAANICACAD7wECAAAAAfABAQAAAAHxAQEAAAABARkAANQCADABGQAA1AIAMAQMAAC3AwAg7wECALYDACHwAQEAtAMAIfEBAQC1AwAhAgAAAMoCACAZAADXAgAgA-8BAgC2AwAh8AEBALQDACHxAQEAtQMAIQIAAADNAgAgGQAA2QIAIAIAAADNAgAgGQAA2QIAIAMAAADKAgAgIAAA0gIAICEAANcCACABAAAAygIAIAEAAADNAgAgBgQAAK8DACAmAACwAwAgJwAAswMAICgAALIDACApAACxAwAg8QEAAK4DACAG7AEAAOMCADDtAQAA4AIAEO4BAADjAgAw7wECAOQCACHwAQEA5QIAIfEBAQDmAgAhAwAAAM0CACABAADfAgAwJQAA4AIAIAMAAADNAgAgAQAAzgIAMAIAAMoCACAG7AEAAOMCADDtAQAA4AIAEO4BAADjAgAw7wECAOQCACHwAQEA5QIAIfEBAQDmAgAhDQQAAOsCACAmAADuAgAgJwAA6wIAICgAAOsCACApAADrAgAg8gECAAAAAfMBAgAAAAT0AQIAAAAE9QECAAAAAfYBAgAAAAH3AQIAAAAB-AECAAAAAfwBAgDtAgAhDgQAAOsCACAoAADsAgAgKQAA7AIAIPIBAQAAAAHzAQEAAAAE9AEBAAAABPUBAQAAAAH2AQEAAAAB9wEBAAAAAfgBAQAAAAH5AQEAAAAB-gEBAAAAAfsBAQAAAAH8AQEA6gIAIQ4EAADoAgAgKAAA6QIAICkAAOkCACDyAQEAAAAB8wEBAAAABfQBAQAAAAX1AQEAAAAB9gEBAAAAAfcBAQAAAAH4AQEAAAAB-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAOcCACEOBAAA6AIAICgAAOkCACApAADpAgAg8gEBAAAAAfMBAQAAAAX0AQEAAAAF9QEBAAAAAfYBAQAAAAH3AQEAAAAB-AEBAAAAAfkBAQAAAAH6AQEAAAAB-wEBAAAAAfwBAQDnAgAhCPIBAgAAAAHzAQIAAAAF9AECAAAABfUBAgAAAAH2AQIAAAAB9wECAAAAAfgBAgAAAAH8AQIA6AIAIQvyAQEAAAAB8wEBAAAABfQBAQAAAAX1AQEAAAAB9gEBAAAAAfcBAQAAAAH4AQEAAAAB-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAOkCACEOBAAA6wIAICgAAOwCACApAADsAgAg8gEBAAAAAfMBAQAAAAT0AQEAAAAE9QEBAAAAAfYBAQAAAAH3AQEAAAAB-AEBAAAAAfkBAQAAAAH6AQEAAAAB-wEBAAAAAfwBAQDqAgAhCPIBAgAAAAHzAQIAAAAE9AECAAAABPUBAgAAAAH2AQIAAAAB9wECAAAAAfgBAgAAAAH8AQIA6wIAIQvyAQEAAAAB8wEBAAAABPQBAQAAAAT1AQEAAAAB9gEBAAAAAfcBAQAAAAH4AQEAAAAB-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAOwCACENBAAA6wIAICYAAO4CACAnAADrAgAgKAAA6wIAICkAAOsCACDyAQIAAAAB8wECAAAABPQBAgAAAAT1AQIAAAAB9gECAAAAAfcBAgAAAAH4AQIAAAAB_AECAO0CACEI8gEIAAAAAfMBCAAAAAT0AQgAAAAE9QEIAAAAAfYBCAAAAAH3AQgAAAAB-AEIAAAAAfwBCADuAgAhBwwAAPMCACDsAQAA7wIAMO0BAADNAgAQ7gEAAO8CADDvAQIA8AIAIfABAQDxAgAh8QEBAPICACEI8gECAAAAAfMBAgAAAAT0AQIAAAAE9QECAAAAAfYBAgAAAAH3AQIAAAAB-AECAAAAAfwBAgDrAgAhC_IBAQAAAAHzAQEAAAAE9AEBAAAABPUBAQAAAAH2AQEAAAAB9wEBAAAAAfgBAQAAAAH5AQEAAAAB-gEBAAAAAfsBAQAAAAH8AQEA7AIAIQvyAQEAAAAB8wEBAAAABfQBAQAAAAX1AQEAAAAB9gEBAAAAAfcBAQAAAAH4AQEAAAAB-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAOkCACED_QEAACAAIP4BAAAgACD_AQAAIAAgCOwBAAD0AgAw7QEAAMcCABDuAQAA9AIAMO8BAQDlAgAhgAIBAOUCACGBAiAA9QIAIYICAQDlAgAhgwIBAOUCACEFBAAA6wIAICgAAPcCACApAAD3AgAg8gEgAAAAAfwBIAD2AgAhBQQAAOsCACAoAAD3AgAgKQAA9wIAIPIBIAAAAAH8ASAA9gIAIQLyASAAAAAB_AEgAPcCACEG7AEAAPgCADDtAQAAsQIAEO4BAAD4AgAw7wECAOQCACHwAQEA5QIAIYQCAgD5AgAhDQQAAOgCACAmAAD7AgAgJwAA6AIAICgAAOgCACApAADoAgAg8gECAAAAAfMBAgAAAAX0AQIAAAAF9QECAAAAAfYBAgAAAAH3AQIAAAAB-AECAAAAAfwBAgD6AgAhDQQAAOgCACAmAAD7AgAgJwAA6AIAICgAAOgCACApAADoAgAg8gECAAAAAfMBAgAAAAX0AQIAAAAF9QECAAAAAfYBAgAAAAH3AQIAAAAB-AECAAAAAfwBAgD6AgAhCPIBCAAAAAHzAQgAAAAF9AEIAAAABfUBCAAAAAH2AQgAAAAB9wEIAAAAAfgBCAAAAAH8AQgA-wIAIQbsAQAA_AIAMO0BAACZAgAQ7gEAAPwCADDvAQIA5AIAIfABAQDlAgAhhQICAOQCACEHDAAA8wIAIOwBAAD9AgAw7QEAAIYCABDuAQAA_QIAMO8BAgDwAgAh8AEBAPECACGFAgIA8AIAIQfsAQAA_gIAMO0BAACAAgAQ7gEAAP4CADCDAgEA5QIAIYYCAQDlAgAhhwJAAP8CACGIAkAA_wIAIQsEAADrAgAgKAAAgQMAICkAAIEDACDyAUAAAAAB8wFAAAAABPQBQAAAAAT1AUAAAAAB9gFAAAAAAfcBQAAAAAH4AUAAAAAB_AFAAIADACELBAAA6wIAICgAAIEDACApAACBAwAg8gFAAAAAAfMBQAAAAAT0AUAAAAAE9QFAAAAAAfYBQAAAAAH3AUAAAAAB-AFAAAAAAfwBQACAAwAhCPIBQAAAAAHzAUAAAAAE9AFAAAAABPUBQAAAAAH2AUAAAAAB9wFAAAAAAfgBQAAAAAH8AUAAgQMAIQnsAQAAggMAMO0BAADqAQAQ7gEAAIIDADDvAQEA5QIAIfABAQDlAgAhiQIBAOUCACGKAgIA5AIAIYsCAgDkAgAhjAICAOQCACEJ7AEAAIMDADDtAQAA1AEAEO4BAACDAwAw7wEBAOUCACGFAgEA5QIAIYcCQAD_AgAhiAJAAP8CACGNAgEA5QIAIY4CQAD_AgAhCewBAACEAwAw7QEAAMEBABDuAQAAhAMAMO8BAQDxAgAhhQIBAPECACGHAkAAhQMAIYgCQACFAwAhjQIBAPECACGOAkAAhQMAIQjyAUAAAAAB8wFAAAAABPQBQAAAAAT1AUAAAAAB9gFAAAAAAfcBQAAAAAH4AUAAAAAB_AFAAIEDACEF7AEAAIYDADDtAQAAuwEAEO4BAACGAwAw7wECAOQCACHwAQEA5QIAIQYDAACIAwAg7AEAAIcDADDtAQAAAwAQ7gEAAIcDADDvAQIA8AIAIfABAQDxAgAhA_0BAAAFACD-AQAABQAg_wEAAAUAIBDsAQAAiQMAMO0BAACjAQAQ7gEAAIkDADDvAQEA5QIAIYMCAQDlAgAhhwJAAP8CACGIAkAA_wIAIY8CAQDlAgAhkAIBAOUCACGRAgEA5gIAIZICAQDmAgAhkwIBAOYCACGUAkAAigMAIZUCQACKAwAhlgIBAOYCACGXAgEA5gIAIQsEAADoAgAgKAAAjAMAICkAAIwDACDyAUAAAAAB8wFAAAAABfQBQAAAAAX1AUAAAAAB9gFAAAAAAfcBQAAAAAH4AUAAAAAB_AFAAIsDACELBAAA6AIAICgAAIwDACApAACMAwAg8gFAAAAAAfMBQAAAAAX0AUAAAAAF9QFAAAAAAfYBQAAAAAH3AUAAAAAB-AFAAAAAAfwBQACLAwAhCPIBQAAAAAHzAUAAAAAF9AFAAAAABfUBQAAAAAH2AUAAAAAB9wFAAAAAAfgBQAAAAAH8AUAAjAMAIQvsAQAAjQMAMO0BAACNAQAQ7gEAAI0DADDvAQEA5QIAIYMCAQDlAgAhhwJAAP8CACGIAkAA_wIAIY4CQAD_AgAhmAIBAOUCACGZAgEA5gIAIZoCAQDmAgAhDuwBAACOAwAw7QEAAHcAEO4BAACOAwAw7wEBAOUCACGbAgEA5QIAIZwCAQDlAgAhnQIBAOUCACGeAgEA5QIAIZ8CAQDlAgAhoAIBAOUCACGhAgEA5QIAIaICIAD1AgAhowIgAPUCACGkAiAA9QIAIQnsAQAAjwMAMO0BAABhABDuAQAAjwMAMO8BAQDlAgAhgwIBAOUCACGlAgEA5QIAIaYCAQDlAgAhpwIBAOUCACGoAgEA5gIAIQsGAACRAwAgCgAAkgMAIOwBAACQAwAw7QEAABEAEO4BAACQAwAw7wEBAPECACGDAgEA8QIAIaUCAQDxAgAhpgIBAPECACGnAgEA8QIAIagCAQDyAgAhEwUAAKkDACAHAACqAwAgCAAAqwMAIAkAAKwDACALAACtAwAgEQAAnAMAIOwBAACoAwAw7QEAAAUAEO4BAACoAwAw7wEBAPECACHwAQEA8QIAIYcCQACFAwAhiAJAAIUDACGpAgEA8QIAIaoCIACiAwAhqwIBAPICACGsAgIAlgMAIa8CAAAFACCwAgAABQAgA_0BAAATACD-AQAAEwAg_wEAABMAIAvsAQAAkwMAMO0BAABJABDuAQAAkwMAMO8BAQDlAgAh8AEBAOUCACGHAkAA_wIAIYgCQAD_AgAhqQIBAOUCACGqAiAA9QIAIasCAQDmAgAhrAICAPkCACEC8AEBAAAAAYQCAgAAAAEJDAAA8wIAIA4AAJcDACAPAACYAwAg7AEAAJUDADDtAQAAJQAQ7gEAAJUDADDvAQIA8AIAIfABAQDxAgAhhAICAJYDACEI8gECAAAAAfMBAgAAAAX0AQIAAAAF9QECAAAAAfYBAgAAAAH3AQIAAAAB-AECAAAAAfwBAgDoAgAhCwwAAPMCACAOAACXAwAgDwAAmAMAIOwBAACVAwAw7QEAACUAEO4BAACVAwAw7wECAPACACHwAQEA8QIAIYQCAgCWAwAhrwIAACUAILACAAAlACAD_QEAACUAIP4BAAAlACD_AQAAJQAgDQ0AAJoDACAQAACbAwAgEQAAnAMAIBIAAJ0DACDsAQAAmQMAMO0BAAAgABDuAQAAmQMAMO8BAQDxAgAh8AEBAPECACGJAgEA8QIAIYoCAgDwAgAhiwICAPACACGMAgIA8AIAIQkMAADzAgAg7AEAAP0CADDtAQAAhgIAEO4BAAD9AgAw7wECAPACACHwAQEA8QIAIYUCAgDwAgAhrwIAAIYCACCwAgAAhgIAIAsMAADzAgAgDgAAlwMAIA8AAJgDACDsAQAAlQMAMO0BAAAlABDuAQAAlQMAMO8BAgDwAgAh8AEBAPECACGEAgIAlgMAIa8CAAAlACCwAgAAJQAgA_0BAAAcACD-AQAAHAAg_wEAABwAIAkMAADzAgAg7AEAAO8CADDtAQAAzQIAEO4BAADvAgAw7wECAPACACHwAQEA8QIAIfEBAQDyAgAhrwIAAM0CACCwAgAAzQIAIAKDAgEAAAABhgIBAAAAAQkGAACRAwAgEwAAoAMAIOwBAACfAwAw7QEAABwAEO4BAACfAwAwgwIBAPECACGGAgEA8QIAIYcCQACFAwAhiAJAAIUDACEPDQAAmgMAIBAAAJsDACARAACcAwAgEgAAnQMAIOwBAACZAwAw7QEAACAAEO4BAACZAwAw7wEBAPECACHwAQEA8QIAIYkCAQDxAgAhigICAPACACGLAgIA8AIAIYwCAgDwAgAhrwIAACAAILACAAAgACAJBgAAkQMAIOwBAAChAwAw7QEAABgAEO4BAAChAwAw7wEBAPECACGAAgEA8QIAIYECIACiAwAhggIBAPECACGDAgEA8QIAIQLyASAAAAAB_AEgAPcCACEPCQAApAMAIOwBAACjAwAw7QEAABMAEO4BAACjAwAw7wEBAPECACGbAgEA8QIAIZwCAQDxAgAhnQIBAPECACGeAgEA8QIAIZ8CAQDxAgAhoAIBAPECACGhAgEA8QIAIaICIACiAwAhowIgAKIDACGkAiAAogMAIQ0GAACRAwAgCgAAkgMAIOwBAACQAwAw7QEAABEAEO4BAACQAwAw7wEBAPECACGDAgEA8QIAIaUCAQDxAgAhpgIBAPECACGnAgEA8QIAIagCAQDyAgAhrwIAABEAILACAAARACARBgAAkQMAIOwBAAClAwAw7QEAAA0AEO4BAAClAwAw7wEBAPECACGDAgEA8QIAIYcCQACFAwAhiAJAAIUDACGPAgEA8QIAIZACAQDxAgAhkQIBAPICACGSAgEA8gIAIZMCAQDyAgAhlAJAAKYDACGVAkAApgMAIZYCAQDyAgAhlwIBAPICACEI8gFAAAAAAfMBQAAAAAX0AUAAAAAF9QFAAAAAAfYBQAAAAAH3AUAAAAAB-AFAAAAAAfwBQACMAwAhDAYAAJEDACDsAQAApwMAMO0BAAAJABDuAQAApwMAMO8BAQDxAgAhgwIBAPECACGHAkAAhQMAIYgCQACFAwAhjgJAAIUDACGYAgEA8QIAIZkCAQDyAgAhmgIBAPICACERBQAAqQMAIAcAAKoDACAIAACrAwAgCQAArAMAIAsAAK0DACARAACcAwAg7AEAAKgDADDtAQAABQAQ7gEAAKgDADDvAQEA8QIAIfABAQDxAgAhhwJAAIUDACGIAkAAhQMAIakCAQDxAgAhqgIgAKIDACGrAgEA8gIAIawCAgCWAwAhCAMAAIgDACDsAQAAhwMAMO0BAAADABDuAQAAhwMAMO8BAgDwAgAh8AEBAPECACGvAgAAAwAgsAIAAAMAIAP9AQAACQAg_gEAAAkAIP8BAAAJACAD_QEAAA0AIP4BAAANACD_AQAADQAgDQYAAJEDACAKAACSAwAg7AEAAJADADDtAQAAEQAQ7gEAAJADADDvAQEA8QIAIYMCAQDxAgAhpQIBAPECACGmAgEA8QIAIacCAQDxAgAhqAIBAPICACGvAgAAEQAgsAIAABEAIAP9AQAAGAAg_gEAABgAIP8BAAAYACAAAAAAAAABtAIBAAAAAQG0AgEAAAABBbQCAgAAAAG6AgIAAAABuwICAAAAAbwCAgAAAAG9AgIAAAABCyAAALgDADAhAAC9AwAwsQIAALkDADCyAgAAugMAMLMCAAC7AwAgtAIAALwDADC1AgAAvAMAMLYCAAC8AwAwtwIAALwDADC4AgAAvgMAMLkCAAC_AwAwCA0AANYDACAQAADXAwAgEQAA2AMAIO8BAQAAAAHwAQEAAAABiQIBAAAAAYoCAgAAAAGLAgIAAAABAgAAACIAICAAANUDACADAAAAIgAgIAAA1QMAICEAAMIDACABGQAA7gUAMA0NAACaAwAgEAAAmwMAIBEAAJwDACASAACdAwAg7AEAAJkDADDtAQAAIAAQ7gEAAJkDADDvAQEAAAAB8AEBAAAAAYkCAQDxAgAhigICAPACACGLAgIA8AIAIYwCAgDwAgAhAgAAACIAIBkAAMIDACACAAAAwAMAIBkAAMEDACAJ7AEAAL8DADDtAQAAwAMAEO4BAAC_AwAw7wEBAPECACHwAQEA8QIAIYkCAQDxAgAhigICAPACACGLAgIA8AIAIYwCAgDwAgAhCewBAAC_AwAw7QEAAMADABDuAQAAvwMAMO8BAQDxAgAh8AEBAPECACGJAgEA8QIAIYoCAgDwAgAhiwICAPACACGMAgIA8AIAIQXvAQEAtAMAIfABAQC0AwAhiQIBALQDACGKAgIAtgMAIYsCAgC2AwAhCA0AAMMDACAQAADEAwAgEQAAxQMAIO8BAQC0AwAh8AEBALQDACGJAgEAtAMAIYoCAgC2AwAhiwICALYDACEFIAAA4AUAICEAAOwFACCxAgAA4QUAILICAADrBQAgtwIAAIMCACAFIAAA3gUAICEAAOkFACCxAgAA3wUAILICAADoBQAgtwIAACgAIAsgAADGAwAwIQAAywMAMLECAADHAwAwsgIAAMgDADCzAgAAyQMAILQCAADKAwAwtQIAAMoDADC2AgAAygMAMLcCAADKAwAwuAIAAMwDADC5AgAAzQMAMAQGAADUAwAggwIBAAAAAYcCQAAAAAGIAkAAAAABAgAAAB4AICAAANMDACADAAAAHgAgIAAA0wMAICEAANEDACABGQAA5wUAMAoGAACRAwAgEwAAoAMAIOwBAACfAwAw7QEAABwAEO4BAACfAwAwgwIBAPECACGGAgEA8QIAIYcCQACFAwAhiAJAAIUDACGuAgAAngMAIAIAAAAeACAZAADRAwAgAgAAAM4DACAZAADPAwAgB-wBAADNAwAw7QEAAM4DABDuAQAAzQMAMIMCAQDxAgAhhgIBAPECACGHAkAAhQMAIYgCQACFAwAhB-wBAADNAwAw7QEAAM4DABDuAQAAzQMAMIMCAQDxAgAhhgIBAPECACGHAkAAhQMAIYgCQACFAwAhA4MCAQC0AwAhhwJAANADACGIAkAA0AMAIQG0AkAAAAABBAYAANIDACCDAgEAtAMAIYcCQADQAwAhiAJAANADACEFIAAA4gUAICEAAOUFACCxAgAA4wUAILICAADkBQAgtwIAAAEAIAQGAADUAwAggwIBAAAAAYcCQAAAAAGIAkAAAAABAyAAAOIFACCxAgAA4wUAILcCAAABACAIDQAA1gMAIBAAANcDACARAADYAwAg7wEBAAAAAfABAQAAAAGJAgEAAAABigICAAAAAYsCAgAAAAEDIAAA4AUAILECAADhBQAgtwIAAIMCACADIAAA3gUAILECAADfBQAgtwIAACgAIAQgAADGAwAwsQIAAMcDADCzAgAAyQMAILcCAADKAwAwBCAAALgDADCxAgAAuQMAMLMCAAC7AwAgtwIAALwDADAAAAAAAbQCIAAAAAEFIAAA2QUAICEAANwFACCxAgAA2gUAILICAADbBQAgtwIAAAEAIAMgAADZBQAgsQIAANoFACC3AgAAAQAgAAAAAAAFtAICAAAAAboCAgAAAAG7AgIAAAABvAICAAAAAb0CAgAAAAEHIAAAzQUAICEAANcFACCxAgAAzgUAILICAADWBQAgtQIAACUAILYCAAAlACC3AgAAKAAgCyAAAPUDADAhAAD6AwAwsQIAAPYDADCyAgAA9wMAMLMCAAD4AwAgtAIAAPkDADC1AgAA-QMAMLYCAAD5AwAwtwIAAPkDADC4AgAA-wMAMLkCAAD8AwAwCyAAAOoDADAhAADuAwAwsQIAAOsDADCyAgAA7AMAMLMCAADtAwAgtAIAALwDADC1AgAAvAMAMLYCAAC8AwAwtwIAALwDADC4AgAA7wMAMLkCAAC_AwAwCA0AANYDACARAADYAwAgEgAA9AMAIO8BAQAAAAHwAQEAAAABiQIBAAAAAYoCAgAAAAGMAgIAAAABAgAAACIAICAAAPMDACADAAAAIgAgIAAA8wMAICEAAPEDACABGQAA1QUAMAIAAAAiACAZAADxAwAgAgAAAMADACAZAADwAwAgBe8BAQC0AwAh8AEBALQDACGJAgEAtAMAIYoCAgC2AwAhjAICALYDACEIDQAAwwMAIBEAAMUDACASAADyAwAg7wEBALQDACHwAQEAtAMAIYkCAQC0AwAhigICALYDACGMAgIAtgMAIQUgAADQBQAgIQAA0wUAILECAADRBQAgsgIAANIFACC3AgAAygIAIAgNAADWAwAgEQAA2AMAIBIAAPQDACDvAQEAAAAB8AEBAAAAAYkCAQAAAAGKAgIAAAABjAICAAAAAQMgAADQBQAgsQIAANEFACC3AgAAygIAIAQMAACCBAAgDwAAgQQAIO8BAgAAAAHwAQEAAAABAgAAACgAICAAAIAEACADAAAAKAAgIAAAgAQAICEAAP8DACABGQAAzwUAMAoMAADzAgAgDgAAlwMAIA8AAJgDACDsAQAAlQMAMO0BAAAlABDuAQAAlQMAMO8BAgAAAAHwAQEA8QIAIYQCAgCWAwAhrQIAAJQDACACAAAAKAAgGQAA_wMAIAIAAAD9AwAgGQAA_gMAIAbsAQAA_AMAMO0BAAD9AwAQ7gEAAPwDADDvAQIA8AIAIfABAQDxAgAhhAICAJYDACEG7AEAAPwDADDtAQAA_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-QQAIAgAAPoEACAJAAD7BAAgCwAA_AQAIBEAAP0EACDvAQEAAAAB8AEBAAAAAYcCQAAAAAGIAkAAAAABqQIBAAAAAaoCIAAAAAGrAgEAAAABBCAAAOwEADCxAgAA7QQAMLMCAADvBAAgtwIAAPAEADAEIAAA3wQAMLECAADgBAAwswIAAOIEACC3AgAA4wQAMAMgAADMBAAgsQIAAM0EACC3AgAATAAgBCAAAMAEADCxAgAAwQQAMLMCAADDBAAgtwIAAMQEADAEIAAAtwQAMLECAAC4BAAwswIAALoEACC3AgAAygMAMAQgAACnBAAwsQIAAKgEADCzAgAAqgQAILcCAACrBAAwAAAAAAUgAAC8BQAgIQAAvwUAILECAAC9BQAgsgIAAL4FACC3AgAAAQAgAyAAALwFACCxAgAAvQUAILcCAAABACAAAAAFIAAAtwUAICEAALoFACCxAgAAuAUAILICAAC5BQAgtwIAAAEAIAMgAAC3BQAgsQIAALgFACC3AgAAAQAgAAAABSAAALIFACAhAAC1BQAgsQIAALMFACCyAgAAtAUAILcCAABMACADIAAAsgUAILECAACzBQAgtwIAAEwAIAAAAAUgAACtBQAgIQAAsAUAILECAACuBQAgsgIAAK8FACC3AgAAAQAgAyAAAK0FACCxAgAArgUAILcCAAABACAIBQAApAUAIAcAAKUFACAIAACmBQAgCQAAowUAIAsAAKcFACARAACgBQAgqwIAAK4DACCsAgAArgMAIAAAAAAAAAcgAACoBQAgIQAAqwUAILECAACpBQAgsgIAAKoFACC1AgAAAwAgtgIAAAMAILcCAACmAQAgAyAAAKgFACCxAgAAqQUAILcCAACmAQAgBAwAANoDACAOAACdBQAgDwAAngUAIIQCAACuAwAgAAEMAADaAwAgAAIMAADaAwAg8QEAAK4DACAEDQAAnwUAIBAAAJ0FACARAACgBQAgEgAAoQUAIAMGAACUBQAgCgAAlQUAIKgCAACuAwAgAQMAAP8EACAAAAAC7wECAAAAAfABAQAAAAECAAAApgEAICAAAKgFACADAAAAAwAgIAAAqAUAICEAAKwFACAEAAAAAwAgGQAArAUAIO8BAgC2AwAh8AEBALQDACEC7wECALYDACHwAQEAtAMAIQ0FAACcBQAgBwAA-QQAIAgAAPoEACALAAD8BAAgEQAA_QQAIO8BAQAAAAHwAQEAAAABhwJAAAAAAYgCQAAAAAGpAgEAAAABqgIgAAAAAasCAQAAAAGsAgIAAAABAgAAAAEAICAAAK0FACADAAAABQAgIAAArQUAICEAALEFACAPAAAABQAgBQAAmwUAIAcAALIEACAIAACzBAAgCwAAtQQAIBEAALYEACAZAACxBQAg7wEBALQDACHwAQEAtAMAIYcCQADQAwAhiAJAANADACGpAgEAtAMAIaoCIADeAwAhqwIBALUDACGsAgIA5gMAIQ0FAACbBQAgBwAAsgQAIAgAALMEACALAAC1BAAgEQAAtgQAIO8BAQC0AwAh8AEBALQDACGHAkAA0AMAIYgCQADQAwAhqQIBALQDACGqAiAA3gMAIasCAQC1AwAhrAICAOYDACEHBgAAkwUAIO8BAQAAAAGDAgEAAAABpQIBAAAAAaYCAQAAAAGnAgEAAAABqAIBAAAAAQIAAABMACAgAACyBQAgAwAAABEAICAAALIFACAhAAC2BQAgCQAAABEAIAYAAJIFACAZAAC2BQAg7wEBALQDACGDAgEAtAMAIaUCAQC0AwAhpgIBALQDACGnAgEAtAMAIagCAQC1AwAhBwYAAJIFACDvAQEAtAMAIYMCAQC0AwAhpQIBALQDACGmAgEAtAMAIacCAQC0AwAhqAIBALUDACENBQAAnAUAIAgAAPoEACAJAAD7BAAgCwAA_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-Zgc_ZwdAaAdBagdCbBRDbSVEbwdFcRRGciZHcwdIdAdJdRRKeCdLeStMegRNewROfARPfQRQfgRRgAEEUoIBFFODASxUhQEEVYcBFFaIAS1XiQEEWIoBBFmLARRajgEuW48BMlyQAQVdkQEFXpIBBV-TAQVglAEFYZYBBWKYARRjmQEzZJsBBWWdARRmngE0Z58BBWigAQVpoQEUaqQBNWulATlspwECbagBAm6qAQJvqwECcKwBAnGuAQJysAEUc7EBOnSzAQJ1tQEUdrYBO3e3AQJ4uAECebkBFHq8ATx7vQFCfL8BQ33AAUN-wwFDf8QBQ4ABxQFDgQHHAUOCAckBFIMBygFEhAHMAUOFAc4BFIYBzwFFhwHQAUOIAdEBQ4kB0gEUigHVAUaLAdYBSowB1wELjQHYAQuOAdkBC48B2gELkAHbAQuRAd0BC5IB3wEUkwHgAUuUAeIBC5UB5AEUlgHlAUyXAeYBC5gB5wELmQHoARSaAesBTZsB7AFTnAHtAQqdAe4BCp4B7wEKnwHwAQqgAfEBCqEB8wEKogH1ARSjAfYBVKQB-AEKpQH6ARSmAfsBVacB_AEKqAH9AQqpAf4BFKoBgQJWqwGCAlqsAYQCDK0BhQIMrgGIAgyvAYkCDLABigIMsQGMAgyyAY4CFLMBjwJbtAGRAgy1AZMCFLYBlAJctwGVAgy4AZYCDLkBlwIUugGaAl27AZsCY7wBnAIOvQGdAg6-AZ4CDr8BnwIOwAGgAg7BAaICDsIBpAIUwwGlAmTEAagCDsUBqgIUxgGrAmXHAa0CDsgBrgIOyQGvAhTKAbICZssBswJszAG0AgnNAbUCCc4BtgIJzwG3AgnQAbgCCdEBugIJ0gG8AhTTAb0CbdQBvwIJ1QHBAhTWAcICbtcBwwIJ2AHEAgnZAcUCFNoByAJv2wHJAnPcAcsCEN0BzAIQ3gHPAhDfAdACEOAB0QIQ4QHTAhDiAdUCFOMB1gJ05AHYAhDlAdoCFOYB2wJ15wHcAhDoAd0CEOkB3gIU6gHhAnbrAeICfA" +} async function decodeBase64AsWasm(wasmBase64: string): Promise { const { Buffer } = await import('node:buffer') @@ -37,12 +45,14 @@ async function decodeBase64AsWasm(wasmBase64: string): Promise await import("@prisma/client/runtime/query_compiler_bg.postgresql.mjs"), + getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.mjs"), getQueryCompilerWasmModule: async () => { - const { wasm } = await import("@prisma/client/runtime/query_compiler_bg.postgresql.wasm-base64.mjs") + const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.wasm-base64.mjs") return await decodeBase64AsWasm(wasm) - } + }, + + importName: "./query_compiler_fast_bg.js" } @@ -57,7 +67,9 @@ export interface PrismaClientConstructor { * Type-safe database client for TypeScript * @example * ``` - * const prisma = new PrismaClient() + * const prisma = new PrismaClient({ + * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) + * }) * // Fetch zero or more Users * const users = await prisma.user.findMany() * ``` @@ -79,7 +91,9 @@ export interface PrismaClientConstructor { * Type-safe database client for TypeScript * @example * ``` - * const prisma = new PrismaClient() + * const prisma = new PrismaClient({ + * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) + * }) * // Fetch zero or more Users * const users = await prisma.user.findMany() * ``` @@ -164,9 +178,9 @@ export interface PrismaClient< * ]) * ``` * - * Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions). + * Read more in our [docs](https://www.prisma.io/docs/orm/prisma-client/queries/transactions). */ - $transaction

[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise> + $transaction

[]>(arg: [...P], options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise> $transaction(fn: (prisma: Omit) => runtime.Types.Utils.JsPromise, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise diff --git a/src/lib/generated/prisma/internal/prismaNamespace.ts b/src/lib/generated/prisma/internal/prismaNamespace.ts index 4737b35..309eae5 100644 --- a/src/lib/generated/prisma/internal/prismaNamespace.ts +++ b/src/lib/generated/prisma/internal/prismaNamespace.ts @@ -80,12 +80,12 @@ export type PrismaVersion = { } /** - * Prisma Client JS version: 7.2.0 - * Query Engine version: 0c8ef2ce45c83248ab3df073180d5eda9e8be7a3 + * Prisma Client JS version: 7.8.0 + * Query Engine version: 3c6e192761c0362d496ed980de936e2f3cebcd3a */ export const prismaVersion: PrismaVersion = { - client: "7.2.0", - engine: "0c8ef2ce45c83248ab3df073180d5eda9e8be7a3" + client: "7.8.0", + engine: "3c6e192761c0362d496ed980de936e2f3cebcd3a" } /** @@ -1436,7 +1436,8 @@ export const ProfileScalarFieldEnum = { userId: 'userId', firstName: 'firstName', lastName: 'lastName', - phoneNumber: 'phoneNumber' + phoneNumber: 'phoneNumber', + ghlContactId: 'ghlContactId' } as const export type ProfileScalarFieldEnum = (typeof ProfileScalarFieldEnum)[keyof typeof ProfileScalarFieldEnum] @@ -1449,7 +1450,11 @@ export const AddressScalarFieldEnum = { city: 'city', state: 'state', postalCode: 'postalCode', - country: 'country' + country: 'country', + type: 'type', + isDefaultMailing: 'isDefaultMailing', + isDefaultBilling: 'isDefaultBilling', + isDefaultShipping: 'isDefaultShipping' } as const export type AddressScalarFieldEnum = (typeof AddressScalarFieldEnum)[keyof typeof AddressScalarFieldEnum] @@ -1514,7 +1519,6 @@ export const ProclamationScalarFieldEnum = { content: 'content', solfeggioFrequencyId: 'solfeggioFrequencyId', categoryId: 'categoryId', - price: 'price', subscriptionLevelId: 'subscriptionLevelId' } as const @@ -1754,6 +1758,21 @@ export type PrismaClientOptions = ({ * ``` */ comments?: runtime.SqlCommenterPlugin[] + /** + * Optional maximum size for the query plan cache. If not provided, a default size will be used. + * A value of `0` can be used to disable the cache entirely. A higher cache size can improve + * performance for applications that execute a large number of unique queries, while a smaller + * cache size can reduce memory usage. + * + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter, + * queryPlanCacheMaxSize: 100, + * }) + * ``` + */ + queryPlanCacheMaxSize?: number } export type GlobalOmitConfig = { user?: Prisma.UserOmit diff --git a/src/lib/generated/prisma/internal/prismaNamespaceBrowser.ts b/src/lib/generated/prisma/internal/prismaNamespaceBrowser.ts index 10955d2..638bfa4 100644 --- a/src/lib/generated/prisma/internal/prismaNamespaceBrowser.ts +++ b/src/lib/generated/prisma/internal/prismaNamespaceBrowser.ts @@ -72,12 +72,12 @@ export type ModelName = (typeof ModelName)[keyof typeof ModelName] * Enums */ -export const TransactionIsolationLevel = { +export const TransactionIsolationLevel = runtime.makeStrictEnum({ ReadUncommitted: 'ReadUncommitted', ReadCommitted: 'ReadCommitted', RepeatableRead: 'RepeatableRead', Serializable: 'Serializable' -} as const +} as const) export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel] @@ -101,7 +101,8 @@ export const ProfileScalarFieldEnum = { userId: 'userId', firstName: 'firstName', lastName: 'lastName', - phoneNumber: 'phoneNumber' + phoneNumber: 'phoneNumber', + ghlContactId: 'ghlContactId' } as const export type ProfileScalarFieldEnum = (typeof ProfileScalarFieldEnum)[keyof typeof ProfileScalarFieldEnum] @@ -114,7 +115,11 @@ export const AddressScalarFieldEnum = { city: 'city', state: 'state', postalCode: 'postalCode', - country: 'country' + country: 'country', + type: 'type', + isDefaultMailing: 'isDefaultMailing', + isDefaultBilling: 'isDefaultBilling', + isDefaultShipping: 'isDefaultShipping' } as const export type AddressScalarFieldEnum = (typeof AddressScalarFieldEnum)[keyof typeof AddressScalarFieldEnum] @@ -179,7 +184,6 @@ export const ProclamationScalarFieldEnum = { content: 'content', solfeggioFrequencyId: 'solfeggioFrequencyId', categoryId: 'categoryId', - price: 'price', subscriptionLevelId: 'subscriptionLevelId' } as const diff --git a/src/lib/generated/prisma/models/Account.ts b/src/lib/generated/prisma/models/Account.ts index 28f3b06..5807782 100644 --- a/src/lib/generated/prisma/models/Account.ts +++ b/src/lib/generated/prisma/models/Account.ts @@ -214,7 +214,7 @@ export type AccountGroupByOutputType = { _max: AccountMaxAggregateOutputType | null } -type GetAccountGroupByPayload = Prisma.PrismaPromise< +export type GetAccountGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1406,6 +1406,11 @@ export type AccountFindManyArgs = Prisma.PrismaPromise< +export type GetAddressGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -198,6 +226,10 @@ export type AddressWhereInput = { state?: Prisma.StringFilter<"Address"> | string postalCode?: Prisma.StringFilter<"Address"> | string country?: Prisma.StringFilter<"Address"> | string + type?: Prisma.StringFilter<"Address"> | string + isDefaultMailing?: Prisma.BoolFilter<"Address"> | boolean + isDefaultBilling?: Prisma.BoolFilter<"Address"> | boolean + isDefaultShipping?: Prisma.BoolFilter<"Address"> | boolean profile?: Prisma.XOR } @@ -209,6 +241,10 @@ export type AddressOrderByWithRelationInput = { state?: Prisma.SortOrder postalCode?: Prisma.SortOrder country?: Prisma.SortOrder + type?: Prisma.SortOrder + isDefaultMailing?: Prisma.SortOrder + isDefaultBilling?: Prisma.SortOrder + isDefaultShipping?: Prisma.SortOrder profile?: Prisma.ProfileOrderByWithRelationInput } @@ -223,6 +259,10 @@ export type AddressWhereUniqueInput = Prisma.AtLeast<{ state?: Prisma.StringFilter<"Address"> | string postalCode?: Prisma.StringFilter<"Address"> | string country?: Prisma.StringFilter<"Address"> | string + type?: Prisma.StringFilter<"Address"> | string + isDefaultMailing?: Prisma.BoolFilter<"Address"> | boolean + isDefaultBilling?: Prisma.BoolFilter<"Address"> | boolean + isDefaultShipping?: Prisma.BoolFilter<"Address"> | boolean profile?: Prisma.XOR }, "id"> @@ -234,6 +274,10 @@ export type AddressOrderByWithAggregationInput = { state?: Prisma.SortOrder postalCode?: Prisma.SortOrder country?: Prisma.SortOrder + type?: Prisma.SortOrder + isDefaultMailing?: Prisma.SortOrder + isDefaultBilling?: Prisma.SortOrder + isDefaultShipping?: Prisma.SortOrder _count?: Prisma.AddressCountOrderByAggregateInput _max?: Prisma.AddressMaxOrderByAggregateInput _min?: Prisma.AddressMinOrderByAggregateInput @@ -250,6 +294,10 @@ export type AddressScalarWhereWithAggregatesInput = { state?: Prisma.StringWithAggregatesFilter<"Address"> | string postalCode?: Prisma.StringWithAggregatesFilter<"Address"> | string country?: Prisma.StringWithAggregatesFilter<"Address"> | string + type?: Prisma.StringWithAggregatesFilter<"Address"> | string + isDefaultMailing?: Prisma.BoolWithAggregatesFilter<"Address"> | boolean + isDefaultBilling?: Prisma.BoolWithAggregatesFilter<"Address"> | boolean + isDefaultShipping?: Prisma.BoolWithAggregatesFilter<"Address"> | boolean } export type AddressCreateInput = { @@ -259,6 +307,10 @@ export type AddressCreateInput = { state: string postalCode: string country: string + type?: string + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean profile: Prisma.ProfileCreateNestedOneWithoutAddressesInput } @@ -270,6 +322,10 @@ export type AddressUncheckedCreateInput = { state: string postalCode: string country: string + type?: string + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean } export type AddressUpdateInput = { @@ -279,6 +335,10 @@ export type AddressUpdateInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean profile?: Prisma.ProfileUpdateOneRequiredWithoutAddressesNestedInput } @@ -290,6 +350,10 @@ export type AddressUncheckedUpdateInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean } export type AddressCreateManyInput = { @@ -300,6 +364,10 @@ export type AddressCreateManyInput = { state: string postalCode: string country: string + type?: string + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean } export type AddressUpdateManyMutationInput = { @@ -309,6 +377,10 @@ export type AddressUpdateManyMutationInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean } export type AddressUncheckedUpdateManyInput = { @@ -319,6 +391,10 @@ export type AddressUncheckedUpdateManyInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean } export type AddressListRelationFilter = { @@ -339,6 +415,10 @@ export type AddressCountOrderByAggregateInput = { state?: Prisma.SortOrder postalCode?: Prisma.SortOrder country?: Prisma.SortOrder + type?: Prisma.SortOrder + isDefaultMailing?: Prisma.SortOrder + isDefaultBilling?: Prisma.SortOrder + isDefaultShipping?: Prisma.SortOrder } export type AddressMaxOrderByAggregateInput = { @@ -349,6 +429,10 @@ export type AddressMaxOrderByAggregateInput = { state?: Prisma.SortOrder postalCode?: Prisma.SortOrder country?: Prisma.SortOrder + type?: Prisma.SortOrder + isDefaultMailing?: Prisma.SortOrder + isDefaultBilling?: Prisma.SortOrder + isDefaultShipping?: Prisma.SortOrder } export type AddressMinOrderByAggregateInput = { @@ -359,6 +443,10 @@ export type AddressMinOrderByAggregateInput = { state?: Prisma.SortOrder postalCode?: Prisma.SortOrder country?: Prisma.SortOrder + type?: Prisma.SortOrder + isDefaultMailing?: Prisma.SortOrder + isDefaultBilling?: Prisma.SortOrder + isDefaultShipping?: Prisma.SortOrder } export type AddressCreateNestedManyWithoutProfileInput = { @@ -410,6 +498,10 @@ export type AddressCreateWithoutProfileInput = { state: string postalCode: string country: string + type?: string + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean } export type AddressUncheckedCreateWithoutProfileInput = { @@ -419,6 +511,10 @@ export type AddressUncheckedCreateWithoutProfileInput = { state: string postalCode: string country: string + type?: string + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean } export type AddressCreateOrConnectWithoutProfileInput = { @@ -458,6 +554,10 @@ export type AddressScalarWhereInput = { state?: Prisma.StringFilter<"Address"> | string postalCode?: Prisma.StringFilter<"Address"> | string country?: Prisma.StringFilter<"Address"> | string + type?: Prisma.StringFilter<"Address"> | string + isDefaultMailing?: Prisma.BoolFilter<"Address"> | boolean + isDefaultBilling?: Prisma.BoolFilter<"Address"> | boolean + isDefaultShipping?: Prisma.BoolFilter<"Address"> | boolean } export type AddressCreateManyProfileInput = { @@ -467,6 +567,10 @@ export type AddressCreateManyProfileInput = { state: string postalCode: string country: string + type?: string + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean } export type AddressUpdateWithoutProfileInput = { @@ -476,6 +580,10 @@ export type AddressUpdateWithoutProfileInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean } export type AddressUncheckedUpdateWithoutProfileInput = { @@ -485,6 +593,10 @@ export type AddressUncheckedUpdateWithoutProfileInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean } export type AddressUncheckedUpdateManyWithoutProfileInput = { @@ -494,6 +606,10 @@ export type AddressUncheckedUpdateManyWithoutProfileInput = { state?: Prisma.StringFieldUpdateOperationsInput | string postalCode?: Prisma.StringFieldUpdateOperationsInput | string country?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + isDefaultMailing?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultBilling?: Prisma.BoolFieldUpdateOperationsInput | boolean + isDefaultShipping?: Prisma.BoolFieldUpdateOperationsInput | boolean } @@ -506,6 +622,10 @@ export type AddressSelect }, ExtArgs["result"]["address"]> @@ -517,6 +637,10 @@ export type AddressSelectCreateManyAndReturn }, ExtArgs["result"]["address"]> @@ -528,6 +652,10 @@ export type AddressSelectUpdateManyAndReturn }, ExtArgs["result"]["address"]> @@ -539,9 +667,13 @@ export type AddressSelectScalar = { state?: boolean postalCode?: boolean country?: boolean + type?: boolean + isDefaultMailing?: boolean + isDefaultBilling?: boolean + isDefaultShipping?: boolean } -export type AddressOmit = runtime.Types.Extensions.GetOmit<"id" | "profileId" | "street" | "city" | "state" | "postalCode" | "country", ExtArgs["result"]["address"]> +export type AddressOmit = runtime.Types.Extensions.GetOmit<"id" | "profileId" | "street" | "city" | "state" | "postalCode" | "country" | "type" | "isDefaultMailing" | "isDefaultBilling" | "isDefaultShipping", ExtArgs["result"]["address"]> export type AddressInclude = { profile?: boolean | Prisma.ProfileDefaultArgs } @@ -565,6 +697,10 @@ export type $AddressPayload composites: {} } @@ -996,6 +1132,10 @@ export interface AddressFieldRefs { readonly state: Prisma.FieldRef<"Address", 'String'> readonly postalCode: Prisma.FieldRef<"Address", 'String'> readonly country: Prisma.FieldRef<"Address", 'String'> + readonly type: Prisma.FieldRef<"Address", 'String'> + readonly isDefaultMailing: Prisma.FieldRef<"Address", 'Boolean'> + readonly isDefaultBilling: Prisma.FieldRef<"Address", 'Boolean'> + readonly isDefaultShipping: Prisma.FieldRef<"Address", 'Boolean'> } @@ -1192,6 +1332,11 @@ export type AddressFindManyArgs = Prisma.PrismaPromise< +export type GetLicenseKeyGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1122,6 +1122,11 @@ export type LicenseKeyFindManyArgs = Prisma.PrismaPromise< +export type GetProclamationGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -242,7 +231,6 @@ export type ProclamationWhereInput = { content?: Prisma.StringFilter<"Proclamation"> | string solfeggioFrequencyId?: Prisma.IntFilter<"Proclamation"> | number categoryId?: Prisma.IntFilter<"Proclamation"> | number - price?: Prisma.FloatFilter<"Proclamation"> | number subscriptionLevelId?: Prisma.IntFilter<"Proclamation"> | number solfeggioFrequency?: Prisma.XOR category?: Prisma.XOR @@ -256,7 +244,6 @@ export type ProclamationOrderByWithRelationInput = { content?: Prisma.SortOrder solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder solfeggioFrequency?: Prisma.SolfeggioFrequencyOrderByWithRelationInput category?: Prisma.ProclamationCategoryOrderByWithRelationInput @@ -273,7 +260,6 @@ export type ProclamationWhereUniqueInput = Prisma.AtLeast<{ content?: Prisma.StringFilter<"Proclamation"> | string solfeggioFrequencyId?: Prisma.IntFilter<"Proclamation"> | number categoryId?: Prisma.IntFilter<"Proclamation"> | number - price?: Prisma.FloatFilter<"Proclamation"> | number subscriptionLevelId?: Prisma.IntFilter<"Proclamation"> | number solfeggioFrequency?: Prisma.XOR category?: Prisma.XOR @@ -287,7 +273,6 @@ export type ProclamationOrderByWithAggregationInput = { content?: Prisma.SortOrder solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder _count?: Prisma.ProclamationCountOrderByAggregateInput _avg?: Prisma.ProclamationAvgOrderByAggregateInput @@ -305,7 +290,6 @@ export type ProclamationScalarWhereWithAggregatesInput = { content?: Prisma.StringWithAggregatesFilter<"Proclamation"> | string solfeggioFrequencyId?: Prisma.IntWithAggregatesFilter<"Proclamation"> | number categoryId?: Prisma.IntWithAggregatesFilter<"Proclamation"> | number - price?: Prisma.FloatWithAggregatesFilter<"Proclamation"> | number subscriptionLevelId?: Prisma.IntWithAggregatesFilter<"Proclamation"> | number } @@ -313,7 +297,6 @@ export type ProclamationCreateInput = { id?: string name: string content: string - price?: number solfeggioFrequency: Prisma.SolfeggioFrequencyCreateNestedOneWithoutProclamationsInput category: Prisma.ProclamationCategoryCreateNestedOneWithoutProclamationsInput userProclamations?: Prisma.UserProclamationsCreateNestedManyWithoutProclamationInput @@ -326,7 +309,6 @@ export type ProclamationUncheckedCreateInput = { content: string solfeggioFrequencyId: number categoryId: number - price?: number subscriptionLevelId?: number userProclamations?: Prisma.UserProclamationsUncheckedCreateNestedManyWithoutProclamationInput } @@ -335,7 +317,6 @@ export type ProclamationUpdateInput = { id?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string - price?: Prisma.FloatFieldUpdateOperationsInput | number solfeggioFrequency?: Prisma.SolfeggioFrequencyUpdateOneRequiredWithoutProclamationsNestedInput category?: Prisma.ProclamationCategoryUpdateOneRequiredWithoutProclamationsNestedInput userProclamations?: Prisma.UserProclamationsUpdateManyWithoutProclamationNestedInput @@ -348,7 +329,6 @@ export type ProclamationUncheckedUpdateInput = { content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number userProclamations?: Prisma.UserProclamationsUncheckedUpdateManyWithoutProclamationNestedInput } @@ -359,7 +339,6 @@ export type ProclamationCreateManyInput = { content: string solfeggioFrequencyId: number categoryId: number - price?: number subscriptionLevelId?: number } @@ -367,7 +346,6 @@ export type ProclamationUpdateManyMutationInput = { id?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string - price?: Prisma.FloatFieldUpdateOperationsInput | number } export type ProclamationUncheckedUpdateManyInput = { @@ -376,7 +354,6 @@ export type ProclamationUncheckedUpdateManyInput = { content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number } @@ -386,14 +363,12 @@ export type ProclamationCountOrderByAggregateInput = { content?: Prisma.SortOrder solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder } export type ProclamationAvgOrderByAggregateInput = { solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder } @@ -403,7 +378,6 @@ export type ProclamationMaxOrderByAggregateInput = { content?: Prisma.SortOrder solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder } @@ -413,14 +387,12 @@ export type ProclamationMinOrderByAggregateInput = { content?: Prisma.SortOrder solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder } export type ProclamationSumOrderByAggregateInput = { solfeggioFrequencyId?: Prisma.SortOrder categoryId?: Prisma.SortOrder - price?: Prisma.SortOrder subscriptionLevelId?: Prisma.SortOrder } @@ -439,14 +411,6 @@ export type ProclamationOrderByRelationAggregateInput = { _count?: Prisma.SortOrder } -export type FloatFieldUpdateOperationsInput = { - set?: number - increment?: number - decrement?: number - multiply?: number - divide?: number -} - export type ProclamationCreateNestedOneWithoutUserProclamationsInput = { create?: Prisma.XOR connectOrCreate?: Prisma.ProclamationCreateOrConnectWithoutUserProclamationsInput @@ -591,7 +555,6 @@ export type ProclamationCreateWithoutUserProclamationsInput = { id?: string name: string content: string - price?: number solfeggioFrequency: Prisma.SolfeggioFrequencyCreateNestedOneWithoutProclamationsInput category: Prisma.ProclamationCategoryCreateNestedOneWithoutProclamationsInput subscriptionLevel?: Prisma.SubscriptionLevelCreateNestedOneWithoutProclamationsInput @@ -603,7 +566,6 @@ export type ProclamationUncheckedCreateWithoutUserProclamationsInput = { content: string solfeggioFrequencyId: number categoryId: number - price?: number subscriptionLevelId?: number } @@ -627,7 +589,6 @@ export type ProclamationUpdateWithoutUserProclamationsInput = { id?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string - price?: Prisma.FloatFieldUpdateOperationsInput | number solfeggioFrequency?: Prisma.SolfeggioFrequencyUpdateOneRequiredWithoutProclamationsNestedInput category?: Prisma.ProclamationCategoryUpdateOneRequiredWithoutProclamationsNestedInput subscriptionLevel?: Prisma.SubscriptionLevelUpdateOneRequiredWithoutProclamationsNestedInput @@ -639,7 +600,6 @@ export type ProclamationUncheckedUpdateWithoutUserProclamationsInput = { content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number } @@ -647,7 +607,6 @@ export type ProclamationCreateWithoutSolfeggioFrequencyInput = { id?: string name: string content: string - price?: number category: Prisma.ProclamationCategoryCreateNestedOneWithoutProclamationsInput userProclamations?: Prisma.UserProclamationsCreateNestedManyWithoutProclamationInput subscriptionLevel?: Prisma.SubscriptionLevelCreateNestedOneWithoutProclamationsInput @@ -658,7 +617,6 @@ export type ProclamationUncheckedCreateWithoutSolfeggioFrequencyInput = { name: string content: string categoryId: number - price?: number subscriptionLevelId?: number userProclamations?: Prisma.UserProclamationsUncheckedCreateNestedManyWithoutProclamationInput } @@ -698,7 +656,6 @@ export type ProclamationScalarWhereInput = { content?: Prisma.StringFilter<"Proclamation"> | string solfeggioFrequencyId?: Prisma.IntFilter<"Proclamation"> | number categoryId?: Prisma.IntFilter<"Proclamation"> | number - price?: Prisma.FloatFilter<"Proclamation"> | number subscriptionLevelId?: Prisma.IntFilter<"Proclamation"> | number } @@ -706,7 +663,6 @@ export type ProclamationCreateWithoutCategoryInput = { id?: string name: string content: string - price?: number solfeggioFrequency: Prisma.SolfeggioFrequencyCreateNestedOneWithoutProclamationsInput userProclamations?: Prisma.UserProclamationsCreateNestedManyWithoutProclamationInput subscriptionLevel?: Prisma.SubscriptionLevelCreateNestedOneWithoutProclamationsInput @@ -717,7 +673,6 @@ export type ProclamationUncheckedCreateWithoutCategoryInput = { name: string content: string solfeggioFrequencyId: number - price?: number subscriptionLevelId?: number userProclamations?: Prisma.UserProclamationsUncheckedCreateNestedManyWithoutProclamationInput } @@ -752,7 +707,6 @@ export type ProclamationCreateWithoutSubscriptionLevelInput = { id?: string name: string content: string - price?: number solfeggioFrequency: Prisma.SolfeggioFrequencyCreateNestedOneWithoutProclamationsInput category: Prisma.ProclamationCategoryCreateNestedOneWithoutProclamationsInput userProclamations?: Prisma.UserProclamationsCreateNestedManyWithoutProclamationInput @@ -764,7 +718,6 @@ export type ProclamationUncheckedCreateWithoutSubscriptionLevelInput = { content: string solfeggioFrequencyId: number categoryId: number - price?: number userProclamations?: Prisma.UserProclamationsUncheckedCreateNestedManyWithoutProclamationInput } @@ -799,7 +752,6 @@ export type ProclamationCreateManySolfeggioFrequencyInput = { name: string content: string categoryId: number - price?: number subscriptionLevelId?: number } @@ -807,7 +759,6 @@ export type ProclamationUpdateWithoutSolfeggioFrequencyInput = { id?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string - price?: Prisma.FloatFieldUpdateOperationsInput | number category?: Prisma.ProclamationCategoryUpdateOneRequiredWithoutProclamationsNestedInput userProclamations?: Prisma.UserProclamationsUpdateManyWithoutProclamationNestedInput subscriptionLevel?: Prisma.SubscriptionLevelUpdateOneRequiredWithoutProclamationsNestedInput @@ -818,7 +769,6 @@ export type ProclamationUncheckedUpdateWithoutSolfeggioFrequencyInput = { name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number userProclamations?: Prisma.UserProclamationsUncheckedUpdateManyWithoutProclamationNestedInput } @@ -828,7 +778,6 @@ export type ProclamationUncheckedUpdateManyWithoutSolfeggioFrequencyInput = { name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number } @@ -837,7 +786,6 @@ export type ProclamationCreateManyCategoryInput = { name: string content: string solfeggioFrequencyId: number - price?: number subscriptionLevelId?: number } @@ -845,7 +793,6 @@ export type ProclamationUpdateWithoutCategoryInput = { id?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string - price?: Prisma.FloatFieldUpdateOperationsInput | number solfeggioFrequency?: Prisma.SolfeggioFrequencyUpdateOneRequiredWithoutProclamationsNestedInput userProclamations?: Prisma.UserProclamationsUpdateManyWithoutProclamationNestedInput subscriptionLevel?: Prisma.SubscriptionLevelUpdateOneRequiredWithoutProclamationsNestedInput @@ -856,7 +803,6 @@ export type ProclamationUncheckedUpdateWithoutCategoryInput = { name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number userProclamations?: Prisma.UserProclamationsUncheckedUpdateManyWithoutProclamationNestedInput } @@ -866,7 +812,6 @@ export type ProclamationUncheckedUpdateManyWithoutCategoryInput = { name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number subscriptionLevelId?: Prisma.IntFieldUpdateOperationsInput | number } @@ -876,14 +821,12 @@ export type ProclamationCreateManySubscriptionLevelInput = { content: string solfeggioFrequencyId: number categoryId: number - price?: number } export type ProclamationUpdateWithoutSubscriptionLevelInput = { id?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string content?: Prisma.StringFieldUpdateOperationsInput | string - price?: Prisma.FloatFieldUpdateOperationsInput | number solfeggioFrequency?: Prisma.SolfeggioFrequencyUpdateOneRequiredWithoutProclamationsNestedInput category?: Prisma.ProclamationCategoryUpdateOneRequiredWithoutProclamationsNestedInput userProclamations?: Prisma.UserProclamationsUpdateManyWithoutProclamationNestedInput @@ -895,7 +838,6 @@ export type ProclamationUncheckedUpdateWithoutSubscriptionLevelInput = { content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number userProclamations?: Prisma.UserProclamationsUncheckedUpdateManyWithoutProclamationNestedInput } @@ -905,7 +847,6 @@ export type ProclamationUncheckedUpdateManyWithoutSubscriptionLevelInput = { content?: Prisma.StringFieldUpdateOperationsInput | string solfeggioFrequencyId?: Prisma.IntFieldUpdateOperationsInput | number categoryId?: Prisma.IntFieldUpdateOperationsInput | number - price?: Prisma.FloatFieldUpdateOperationsInput | number } @@ -945,7 +886,6 @@ export type ProclamationSelect category?: boolean | Prisma.ProclamationCategoryDefaultArgs @@ -960,7 +900,6 @@ export type ProclamationSelectCreateManyAndReturn category?: boolean | Prisma.ProclamationCategoryDefaultArgs @@ -973,7 +912,6 @@ export type ProclamationSelectUpdateManyAndReturn category?: boolean | Prisma.ProclamationCategoryDefaultArgs @@ -986,11 +924,10 @@ export type ProclamationSelectScalar = { content?: boolean solfeggioFrequencyId?: boolean categoryId?: boolean - price?: boolean subscriptionLevelId?: boolean } -export type ProclamationOmit = runtime.Types.Extensions.GetOmit<"id" | "name" | "content" | "solfeggioFrequencyId" | "categoryId" | "price" | "subscriptionLevelId", ExtArgs["result"]["proclamation"]> +export type ProclamationOmit = runtime.Types.Extensions.GetOmit<"id" | "name" | "content" | "solfeggioFrequencyId" | "categoryId" | "subscriptionLevelId", ExtArgs["result"]["proclamation"]> export type ProclamationInclude = { solfeggioFrequency?: boolean | Prisma.SolfeggioFrequencyDefaultArgs category?: boolean | Prisma.ProclamationCategoryDefaultArgs @@ -1023,7 +960,6 @@ export type $ProclamationPayload composites: {} @@ -1457,7 +1393,6 @@ export interface ProclamationFieldRefs { readonly content: Prisma.FieldRef<"Proclamation", 'String'> readonly solfeggioFrequencyId: Prisma.FieldRef<"Proclamation", 'Int'> readonly categoryId: Prisma.FieldRef<"Proclamation", 'Int'> - readonly price: Prisma.FieldRef<"Proclamation", 'Float'> readonly subscriptionLevelId: Prisma.FieldRef<"Proclamation", 'Int'> } @@ -1655,6 +1590,11 @@ export type ProclamationFindManyArgs = Prisma.PrismaPromise< +export type GetProclamationCategoryGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1297,6 +1297,11 @@ export type ProclamationCategoryFindManyArgs = Prisma.PrismaPromise< +export type GetProfileGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -182,6 +189,7 @@ export type ProfileWhereInput = { firstName?: Prisma.StringFilter<"Profile"> | string lastName?: Prisma.StringFilter<"Profile"> | string phoneNumber?: Prisma.StringFilter<"Profile"> | string + ghlContactId?: Prisma.StringNullableFilter<"Profile"> | string | null user?: Prisma.XOR addresses?: Prisma.AddressListRelationFilter } @@ -192,6 +200,7 @@ export type ProfileOrderByWithRelationInput = { firstName?: Prisma.SortOrder lastName?: Prisma.SortOrder phoneNumber?: Prisma.SortOrder + ghlContactId?: Prisma.SortOrderInput | Prisma.SortOrder user?: Prisma.UserOrderByWithRelationInput addresses?: Prisma.AddressOrderByRelationAggregateInput } @@ -205,6 +214,7 @@ export type ProfileWhereUniqueInput = Prisma.AtLeast<{ firstName?: Prisma.StringFilter<"Profile"> | string lastName?: Prisma.StringFilter<"Profile"> | string phoneNumber?: Prisma.StringFilter<"Profile"> | string + ghlContactId?: Prisma.StringNullableFilter<"Profile"> | string | null user?: Prisma.XOR addresses?: Prisma.AddressListRelationFilter }, "id" | "userId"> @@ -215,6 +225,7 @@ export type ProfileOrderByWithAggregationInput = { firstName?: Prisma.SortOrder lastName?: Prisma.SortOrder phoneNumber?: Prisma.SortOrder + ghlContactId?: Prisma.SortOrderInput | Prisma.SortOrder _count?: Prisma.ProfileCountOrderByAggregateInput _max?: Prisma.ProfileMaxOrderByAggregateInput _min?: Prisma.ProfileMinOrderByAggregateInput @@ -229,6 +240,7 @@ export type ProfileScalarWhereWithAggregatesInput = { firstName?: Prisma.StringWithAggregatesFilter<"Profile"> | string lastName?: Prisma.StringWithAggregatesFilter<"Profile"> | string phoneNumber?: Prisma.StringWithAggregatesFilter<"Profile"> | string + ghlContactId?: Prisma.StringNullableWithAggregatesFilter<"Profile"> | string | null } export type ProfileCreateInput = { @@ -236,6 +248,7 @@ export type ProfileCreateInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null user: Prisma.UserCreateNestedOneWithoutProfileInput addresses?: Prisma.AddressCreateNestedManyWithoutProfileInput } @@ -246,6 +259,7 @@ export type ProfileUncheckedCreateInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null addresses?: Prisma.AddressUncheckedCreateNestedManyWithoutProfileInput } @@ -254,6 +268,7 @@ export type ProfileUpdateInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null user?: Prisma.UserUpdateOneRequiredWithoutProfileNestedInput addresses?: Prisma.AddressUpdateManyWithoutProfileNestedInput } @@ -264,6 +279,7 @@ export type ProfileUncheckedUpdateInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null addresses?: Prisma.AddressUncheckedUpdateManyWithoutProfileNestedInput } @@ -273,6 +289,7 @@ export type ProfileCreateManyInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null } export type ProfileUpdateManyMutationInput = { @@ -280,6 +297,7 @@ export type ProfileUpdateManyMutationInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null } export type ProfileUncheckedUpdateManyInput = { @@ -288,6 +306,7 @@ export type ProfileUncheckedUpdateManyInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null } export type ProfileNullableScalarRelationFilter = { @@ -301,6 +320,7 @@ export type ProfileCountOrderByAggregateInput = { firstName?: Prisma.SortOrder lastName?: Prisma.SortOrder phoneNumber?: Prisma.SortOrder + ghlContactId?: Prisma.SortOrder } export type ProfileMaxOrderByAggregateInput = { @@ -309,6 +329,7 @@ export type ProfileMaxOrderByAggregateInput = { firstName?: Prisma.SortOrder lastName?: Prisma.SortOrder phoneNumber?: Prisma.SortOrder + ghlContactId?: Prisma.SortOrder } export type ProfileMinOrderByAggregateInput = { @@ -317,6 +338,7 @@ export type ProfileMinOrderByAggregateInput = { firstName?: Prisma.SortOrder lastName?: Prisma.SortOrder phoneNumber?: Prisma.SortOrder + ghlContactId?: Prisma.SortOrder } export type ProfileScalarRelationFilter = { @@ -375,6 +397,7 @@ export type ProfileCreateWithoutUserInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null addresses?: Prisma.AddressCreateNestedManyWithoutProfileInput } @@ -383,6 +406,7 @@ export type ProfileUncheckedCreateWithoutUserInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null addresses?: Prisma.AddressUncheckedCreateNestedManyWithoutProfileInput } @@ -407,6 +431,7 @@ export type ProfileUpdateWithoutUserInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null addresses?: Prisma.AddressUpdateManyWithoutProfileNestedInput } @@ -415,6 +440,7 @@ export type ProfileUncheckedUpdateWithoutUserInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null addresses?: Prisma.AddressUncheckedUpdateManyWithoutProfileNestedInput } @@ -423,6 +449,7 @@ export type ProfileCreateWithoutAddressesInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null user: Prisma.UserCreateNestedOneWithoutProfileInput } @@ -432,6 +459,7 @@ export type ProfileUncheckedCreateWithoutAddressesInput = { firstName: string lastName: string phoneNumber: string + ghlContactId?: string | null } export type ProfileCreateOrConnectWithoutAddressesInput = { @@ -455,6 +483,7 @@ export type ProfileUpdateWithoutAddressesInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null user?: Prisma.UserUpdateOneRequiredWithoutProfileNestedInput } @@ -464,6 +493,7 @@ export type ProfileUncheckedUpdateWithoutAddressesInput = { firstName?: Prisma.StringFieldUpdateOperationsInput | string lastName?: Prisma.StringFieldUpdateOperationsInput | string phoneNumber?: Prisma.StringFieldUpdateOperationsInput | string + ghlContactId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null } @@ -503,6 +533,7 @@ export type ProfileSelect addresses?: boolean | Prisma.Profile$addressesArgs _count?: boolean | Prisma.ProfileCountOutputTypeDefaultArgs @@ -514,6 +545,7 @@ export type ProfileSelectCreateManyAndReturn }, ExtArgs["result"]["profile"]> @@ -523,6 +555,7 @@ export type ProfileSelectUpdateManyAndReturn }, ExtArgs["result"]["profile"]> @@ -532,9 +565,10 @@ export type ProfileSelectScalar = { firstName?: boolean lastName?: boolean phoneNumber?: boolean + ghlContactId?: boolean } -export type ProfileOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "firstName" | "lastName" | "phoneNumber", ExtArgs["result"]["profile"]> +export type ProfileOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "firstName" | "lastName" | "phoneNumber" | "ghlContactId", ExtArgs["result"]["profile"]> export type ProfileInclude = { user?: boolean | Prisma.UserDefaultArgs addresses?: boolean | Prisma.Profile$addressesArgs @@ -559,6 +593,7 @@ export type $ProfilePayload composites: {} } @@ -989,6 +1024,7 @@ export interface ProfileFieldRefs { readonly firstName: Prisma.FieldRef<"Profile", 'String'> readonly lastName: Prisma.FieldRef<"Profile", 'String'> readonly phoneNumber: Prisma.FieldRef<"Profile", 'String'> + readonly ghlContactId: Prisma.FieldRef<"Profile", 'String'> } @@ -1185,6 +1221,11 @@ export type ProfileFindManyArgs = Prisma.PrismaPromise< +export type GetSessionGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1227,6 +1227,11 @@ export type SessionFindManyArgs = Prisma.PrismaPromise< +export type GetSolfeggioFrequencyGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -203,7 +203,7 @@ export type SolfeggioFrequencyWhereInput = { NOT?: Prisma.SolfeggioFrequencyWhereInput | Prisma.SolfeggioFrequencyWhereInput[] id?: Prisma.IntFilter<"SolfeggioFrequency"> | number name?: Prisma.StringFilter<"SolfeggioFrequency"> | string - value?: Prisma.FloatFilter<"SolfeggioFrequency"> | number + value?: Prisma.IntFilter<"SolfeggioFrequency"> | number proclamations?: Prisma.ProclamationListRelationFilter } @@ -241,7 +241,7 @@ export type SolfeggioFrequencyScalarWhereWithAggregatesInput = { NOT?: Prisma.SolfeggioFrequencyScalarWhereWithAggregatesInput | Prisma.SolfeggioFrequencyScalarWhereWithAggregatesInput[] id?: Prisma.IntWithAggregatesFilter<"SolfeggioFrequency"> | number name?: Prisma.StringWithAggregatesFilter<"SolfeggioFrequency"> | string - value?: Prisma.FloatWithAggregatesFilter<"SolfeggioFrequency"> | number + value?: Prisma.IntWithAggregatesFilter<"SolfeggioFrequency"> | number } export type SolfeggioFrequencyCreateInput = { @@ -259,14 +259,14 @@ export type SolfeggioFrequencyUncheckedCreateInput = { export type SolfeggioFrequencyUpdateInput = { name?: Prisma.StringFieldUpdateOperationsInput | string - value?: Prisma.FloatFieldUpdateOperationsInput | number + value?: Prisma.IntFieldUpdateOperationsInput | number proclamations?: Prisma.ProclamationUpdateManyWithoutSolfeggioFrequencyNestedInput } export type SolfeggioFrequencyUncheckedUpdateInput = { id?: Prisma.IntFieldUpdateOperationsInput | number name?: Prisma.StringFieldUpdateOperationsInput | string - value?: Prisma.FloatFieldUpdateOperationsInput | number + value?: Prisma.IntFieldUpdateOperationsInput | number proclamations?: Prisma.ProclamationUncheckedUpdateManyWithoutSolfeggioFrequencyNestedInput } @@ -278,13 +278,13 @@ export type SolfeggioFrequencyCreateManyInput = { export type SolfeggioFrequencyUpdateManyMutationInput = { name?: Prisma.StringFieldUpdateOperationsInput | string - value?: Prisma.FloatFieldUpdateOperationsInput | number + value?: Prisma.IntFieldUpdateOperationsInput | number } export type SolfeggioFrequencyUncheckedUpdateManyInput = { id?: Prisma.IntFieldUpdateOperationsInput | number name?: Prisma.StringFieldUpdateOperationsInput | string - value?: Prisma.FloatFieldUpdateOperationsInput | number + value?: Prisma.IntFieldUpdateOperationsInput | number } export type SolfeggioFrequencyScalarRelationFilter = { @@ -363,13 +363,13 @@ export type SolfeggioFrequencyUpdateToOneWithWhereWithoutProclamationsInput = { export type SolfeggioFrequencyUpdateWithoutProclamationsInput = { name?: Prisma.StringFieldUpdateOperationsInput | string - value?: Prisma.FloatFieldUpdateOperationsInput | number + value?: Prisma.IntFieldUpdateOperationsInput | number } export type SolfeggioFrequencyUncheckedUpdateWithoutProclamationsInput = { id?: Prisma.IntFieldUpdateOperationsInput | number name?: Prisma.StringFieldUpdateOperationsInput | string - value?: Prisma.FloatFieldUpdateOperationsInput | number + value?: Prisma.IntFieldUpdateOperationsInput | number } @@ -872,7 +872,7 @@ export interface Prisma__SolfeggioFrequencyClient readonly name: Prisma.FieldRef<"SolfeggioFrequency", 'String'> - readonly value: Prisma.FieldRef<"SolfeggioFrequency", 'Float'> + readonly value: Prisma.FieldRef<"SolfeggioFrequency", 'Int'> } @@ -1069,6 +1069,11 @@ export type SolfeggioFrequencyFindManyArgs = Prisma.PrismaPromise< +export type GetSubscriptionLevelGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1063,6 +1063,11 @@ export type SubscriptionLevelFindManyArgs = Prisma.PrismaPromise< +export type GetUserGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1883,6 +1883,11 @@ export type UserFindManyArgs = Prisma.PrismaPromise< +export type GetUserProclamationsGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1207,6 +1207,11 @@ export type UserProclamationsFindManyArgs = Prisma.PrismaPromise< +export type GetUserRoleGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -1041,6 +1041,11 @@ export type UserRoleFindManyArgs = Prisma.PrismaPromise< +export type GetVerificationGroupByPayload = Prisma.PrismaPromise< Array< Prisma.PickEnumerable & { @@ -982,6 +982,11 @@ export type VerificationFindManyArgs { - /** - * chargeCreditDebitCard attempts to request payment from a valid card, - * for the amount specified. - */ - console.log(`charged card ${card} for $${amount}`); - await new Promise(resolve => setTimeout(resolve, 1000)); - return null; +export async function chargeCreditDebitCard(card: CreditDebitCard, amount: Decimal): Promise { + /** + * chargeCreditDebitCard attempts to request payment from a valid card, + * for the amount specified. + */ + console.log(`charged card ${card} for $${amount}`); + await new Promise((resolve) => setTimeout(resolve, 1000)); + return null; } -export async function chargedStoredCard(cardNumber: number, profileID: string, amount: Decimal): Promise { - /** - * chargedStoredCard attempts to request payment from a valid card, - * for the amount specified. - * The card is identified by the last four digits of the card - * number, and the profile ID. - * NOTE: This should be enough to identify a saved card, but the - * function signature may change in the future. - */ - console.log(`charged ${profileID}'s card ${cardNumber} for ${cardNumber} $${amount}`); - return null; +export async function chargedStoredCard( + cardNumber: number, + profileID: string, + amount: Decimal +): Promise { + /** + * chargedStoredCard attempts to request payment from a valid card, + * for the amount specified. + * The card is identified by the last four digits of the card + * number, and the profile ID. + * NOTE: This should be enough to identify a saved card, but the + * function signature may change in the future. + */ + console.log(`charged ${profileID}'s card ${cardNumber} for ${cardNumber} $${amount}`); + return null; } export async function deleteCardFromProfile(cardNumber: number, profileID: string): Promise { - /** - * deleteCardFromProfile deletes a stored card on a user's profile. - */ - console.log(`Deleted card ${cardNumber} from ${profileID}'s profile.`); - return null; + /** + * deleteCardFromProfile deletes a stored card on a user's profile. + */ + console.log(`Deleted card ${cardNumber} from ${profileID}'s profile.`); + return null; } export async function storeCardToProfile(card: CreditDebitCard, profileID: string): Promise { - /** - * storeCardToProfile stores a new card to a user's profile - * for easy re-use later. - */ - console.log(`Deleted card ${card.card_number} from ${profileID}'s profile.`); - return null; + /** + * storeCardToProfile stores a new card to a user's profile + * for easy re-use later. + */ + console.log(`Deleted card ${card.card_number} from ${profileID}'s profile.`); + return null; } export async function requestRefund(card: CreditDebitCard, amount: Decimal): Promise { - /** - * requestRefund attempts to process a refund for the amount to the - * provided card. - */ - console.log(`Refunded ${amount} to ${card.card_number}`); - return null; -} \ No newline at end of file + /** + * requestRefund attempts to process a refund for the amount to the + * provided card. + */ + console.log(`Refunded ${amount} to ${card.card_number}`); + return null; +} diff --git a/src/lib/server/email-verification.ts b/src/lib/server/email-verification.ts index 9e9fbfc..f0bd2d7 100644 --- a/src/lib/server/email-verification.ts +++ b/src/lib/server/email-verification.ts @@ -1,10 +1,7 @@ import { BETTER_AUTH_URL } from '$env/static/private'; import { sendMail } from './resend'; -export async function sendVerificationEmail(options: { - email: string; - token: string; -}) { +export async function sendVerificationEmail(options: { email: string; token: string }) { const verificationUrl = `${BETTER_AUTH_URL}/api/auth/verify-email?token=${options.token}&callbackURL=/login?verified=true`; await sendMail({ diff --git a/src/lib/server/resend.ts b/src/lib/server/resend.ts index 49b6f50..dc8d7f4 100644 --- a/src/lib/server/resend.ts +++ b/src/lib/server/resend.ts @@ -2,11 +2,11 @@ * AUTHOR: Neil Clack * EMAIL: nclack@radiantwavetech.com * DATE: 07/06/2027 - * + * * A server side library and client for Resend * Includes the Resend client, as well as functions * for different email scenarios. - * + * */ import { Resend } from 'resend'; import { RESEND_API_KEY, EMAIL_FROM, RESEND_TEMPLATE_ID } from '$env/static/private'; @@ -31,26 +31,26 @@ export const resend = new Resend(RESEND_API_KEY); * @throws {Error} If the Resend API call fails. */ export async function sendMail(options: { - to: string; - subject?: string; - templateId?: string; - data?: Record; + to: string; + subject?: string; + templateId?: string; + data?: Record; }) { - const { to, subject, templateId, data } = options; + const { to, subject, templateId, data } = options; - const result = await resend.emails.send({ - from: EMAIL_FROM, - to: [to], - subject: subject ?? 'Template Email', - template: { - id: templateId ?? RESEND_TEMPLATE_ID, - variables: data ?? {} - } - }); + const result = await resend.emails.send({ + from: EMAIL_FROM, + to: [to], + subject: subject ?? 'Template Email', + template: { + id: templateId ?? RESEND_TEMPLATE_ID, + variables: data ?? {} + } + }); - if (result.error) { - throw new Error(result.error.message); - } + if (result.error) { + throw new Error(result.error.message); + } - return result.data; -} \ No newline at end of file + return result.data; +} diff --git a/src/lib/svelte-admin/README.md b/src/lib/svelte-admin/README.md index 340082d..db33127 100644 --- a/src/lib/svelte-admin/README.md +++ b/src/lib/svelte-admin/README.md @@ -1,8 +1,8 @@ # svelte-admin A config-driven admin panel framework for SvelteKit + Prisma. Define your models once in a -registry and get full CRUD UI with dynamic routing, role-based access control, searchable -dropdowns, and related-record panels — no per-model route files needed. +registry and get full CRUD UI with per-model static pages, role-based access control, searchable +tables, FK dropdowns, TipTap editor for rich text, and related-record panels. ## Architecture @@ -13,27 +13,30 @@ src/lib/svelte-admin/ # Framework core ├── roles.ts # Role hierarchy and access helpers ├── prisma-delegate.ts # Dynamic Prisma delegate lookup ├── introspect.ts # Field label generation and dot-notation resolution -├── form-data.ts # FormData → typed object parser +├── form-data.ts # FormData -> typed object parser +├── crud.ts # CRUD action factory (load, upsert, delete) └── index.ts # Barrel exports -src/routes/(protected)/admin/ # Dynamic admin routes +src/routes/(protected)/admin/ # Per-model admin pages (no dynamic [model] routing) ├── +layout.server.ts # Role-based access guard ├── +layout.svelte # Layout shell ├── +page.server.ts # Admin home (model grid) ├── +page.svelte # Admin home UI -├── [model]/ -│ ├── +page.server.ts # List view + create action -│ ├── +page.svelte # List view UI -│ └── [id]/ -│ ├── +page.server.ts # Edit view + update/delete actions -│ └── +page.svelte # Edit view UI +├── users/ # Each model gets its own page directory +├── profiles/ +├── addresses/ +├── user-roles/ +├── proclamations/ +├── solfeggio-frequencies/ +├── proclamation-categories/ +├── subscription-levels/ +└── license-keys/ # listOnly — no create/edit modal src/lib/components/admin/ # Reusable admin UI components ├── AdminTable.svelte # Sortable, searchable data table ├── AdminForm.svelte # Dynamic form with type-aware inputs -├── ComboBox.svelte # Searchable dropdown for FK fields -├── RelatedHasOne.svelte # Display panel for 1:1 related records -└── RelatedHasMany.svelte # Display table for 1:N related records +├── AdminModal.svelte # Modal overlay for CRUD forms +├── TipTap.svelte # Rich-text editor (in components/tiptap/) ``` ## Adding a New Model @@ -74,10 +77,11 @@ src/lib/components/admin/ # Reusable admin UI components } ``` -3. **Done.** Visit `/admin/widgets`. The dynamic `[model]` routes handle list, create, edit, - and delete automatically. +3. **Create the page directory** `src/routes/(protected)/admin/widgets/` with: + - `+page.server.ts` — load records + form actions using `crud.ts` helpers + - `+page.svelte` — render AdminTable + AdminModal with AdminForm -No new route files, no new components. The registry is the only thing you touch. +4. **Done.** Visit `/admin/widgets`. The page handles list, create, edit via modal. ## Configuration Reference @@ -95,25 +99,26 @@ No new route files, no new components. The registry is the only thing you touch. | `searchFields` | `string[]` | Yes | Fields searched by the client-side search filter. | | `formFields` | `string[]` | Yes | Fields rendered in create/edit forms, in display order. | | `readonlyFields` | `string[]` | No | Fields shown as read-only on the edit page. | -| `listOnly` | `boolean` | No | If `true`, suppresses edit links in the table. | +| `listOnly` | `boolean` | No | If `true`, suppresses edit links in the table and no modal. | | `fieldTypes` | `Record` | Yes | Maps field names to scalar types. Controls input rendering and FormData parsing. | -| `relationOptions` | `Record` | No | FK fields that render as ComboBox dropdowns. | -| `relatedRecords` | `RelatedRecordConfig[]` | No | Has-one/has-many panels shown on edit pages. | +| `relationOptions` | `Record` | No | FK fields that render as `` | `raw.toString()` | -| `Int` | `` | `parseInt()`, empty → `null` | -| `Float` | `` | `parseFloat()`, empty → `null` | -| `Boolean` | `` | `'on'` or `'true'` → `true` | -| `DateTime` | `` | `new Date()`, empty → `null` | +| Type | HTML Input | Parse Logic | +| ---------- | ------------------------------------- | ------------------------------ | +| `String` | `` | `raw.toString()` | +| `Int` | `` | `parseInt()`, empty -> `null` | +| `Float` | `` | `parseFloat()`, empty -> `null` | +| `Boolean` | `` | `'on'` or `'true'` -> `true` | +| `DateTime` | `` | `new Date()`, empty -> `null` | +| `Tiptap` | TipTap rich-text editor (hidden input)| `raw.toString()` | ### RelationOptionConfig @@ -142,14 +147,18 @@ Controls both form input rendering and FormData parsing: The `fieldTypes` mapping is the central mechanism connecting Prisma scalar types to HTML inputs and form data parsing. Every field in `formFields` must have a corresponding entry in `fieldTypes`. -When a field also has a `relationOptions` entry, the framework renders a `ComboBox` (searchable -dropdown) instead of the default input for that type. +When a field also has a `relationOptions` entry, the framework renders a `` dropdown: ```ts { @@ -165,7 +174,8 @@ When a form field is a foreign key, add a `relationOptions` entry to render a se } ``` -The route loader automatically queries the related model and passes options to the ComboBox. +The `crud.ts` `loadRecords` function automatically queries the related model and passes options +to the page as `relationOptionsData`. ### Eager Loading (include) @@ -200,9 +210,7 @@ relatedRecords: [ ]; ``` -The `relationKey` must match a key in `include` so the data is actually loaded. `has-one` renders -a key-value panel via `RelatedHasOne`; `has-many` renders a table via `RelatedHasMany`. Both -support an optional `editSlug` to link to the related record's edit page. +The `relationKey` must match a key in `include` so the data is actually loaded. ## Access Control @@ -228,23 +236,23 @@ Use `accessFilter` to restrict which records a viewer can see: ```ts accessFilter: (viewerRoleId: number) => { - if (viewerRoleId <= ROLES.SUPER) return undefined; // no filter - if (viewerRoleId <= ROLES.ADMIN) { - return { roleId: { gte: ROLES.STAFF } }; // can't see other admins - } - return { roleId: { gt: ROLES.STAFF } }; // staff sees only regular users + if (viewerRoleId <= ROLES.SUPER) return undefined; + if (viewerRoleId <= ROLES.ADMIN) { + return { roleId: { gte: ROLES.STAFF } }; + } + return { roleId: { gt: ROLES.STAFF } }; }; ``` -## How Dynamic Routing Works +## How Static Pages Work -1. User visits `/admin/proclamations` (or `/admin/proclamations/abc123`) -2. SvelteKit matches the `[model]` (and `[id]`) route params -3. `+page.server.ts` calls `getModelConfig(params.model)` to look up the config -4. `getDelegate(config)` returns `prisma[lcfirst(config.modelName)]` (e.g., `prisma.proclamation`) -5. The delegate runs `findMany` (list), `findUnique` (edit), `create`, `update`, or `delete` -6. Data + config are passed to the Svelte page component -7. Components (`AdminTable`, `AdminForm`, etc.) render based on config +1. User visits `/admin/proclamations` +2. SvelteKit matches the static route `/admin/proclamations/+page.server.ts` +3. `+page.server.ts` calls `getModelConfig('proclamations')` to look up the config +4. `loadRecords(config)` calls `prisma.proclamation.findMany()` with the config's `include` and `accessFilter` +5. For each FK field with a `relationOptions`, it also queries the related model for dropdown options +6. Data + config are passed to `+page.svelte` +7. The page renders `AdminTable` with records and `AdminModal` + `AdminForm` for create/edit ## Component API @@ -255,11 +263,13 @@ accessFilter: (viewerRoleId: number) => { | `records` | `Record[]` | Data rows | | `listFields` | `string[]` | Column keys (dot-notation supported) | | `searchFields` | `string[]` | Fields for client-side search | -| `modelSlug` | `string` | Used for building edit links | -| `listOnly` | `boolean?` | Suppress edit links | +| `fieldTypes` | `Record` | Type mapping for cell formatting | +| `singular` | `string` | Singular label for UI text | +| `onRowClick` | `(record) => void?` | Click handler for edit modal | +| `onNew` | `() => void?` | Click handler for create modal | Features: client-side search, click-to-sort columns, auto-formatted cells (dates, booleans, -decimals), filtered count display. +decimals), empty state. ### AdminForm @@ -270,46 +280,31 @@ decimals), filtered count display. | `relationOptions` | `Record?` | FK dropdown configs | | `relationOptionsData` | `Record?` | Loaded dropdown options | | `record` | `Record?` | Pre-fill values (edit mode) | -| `form` | `ActionData?` | Carries validation errors | -| `action` | `string` | Form action (e.g., `'?/create'`) | +| `readonlyFields` | `string[]?` | Read-only field names | +| `action` | `string` | Form action (e.g., `'?/upsert'`) | | `submitLabel` | `string?` | Button text | -### ComboBox +### AdminModal -| Prop | Type | Description | -| ------------- | -------------------- | ------------------ | -| `id` | `string` | Element ID | -| `name` | `string` | Form field name | -| `options` | `{ label; value }[]` | Dropdown items | -| `placeholder` | `string?` | Placeholder text | -| `value` | `string \| number?` | Pre-selected value | +| Prop | Type | Description | +| --------- | ----------------- | ------------------------ | +| `open` | `boolean` | Show/hide modal | +| `title` | `string` | Modal heading | +| `onClose` | `() => void` | Close handler | +| `children`| `Snippet` | Modal body content | -Features: type-to-search filtering, keyboard navigation (ArrowUp/Down, Enter, Escape), -clear button, scroll-to-highlight. +### TipTap -### RelatedHasOne - -| Prop | Type | Description | -| --------------- | --------------------------------- | ------------------------------------ | -| `label` | `string` | Section heading | -| `record` | `Record \| null` | Related record | -| `displayFields` | `string[]` | Fields to display as key-value pairs | -| `editSlug` | `string?` | Links to edit the related record | - -### RelatedHasMany - -| Prop | Type | Description | -| --------------- | --------------------------- | ----------------------------- | -| `label` | `string` | Section heading (shows count) | -| `records` | `Record[]` | Related records | -| `displayFields` | `string[]` | Table columns | -| `editSlug` | `string?` | Per-row edit links | +| Prop | Type | Description | +| ---------------- | -------- | --------------------------------- | +| `initialContent` | `string` | Initial HTML content | +| `name` | `string` | Hidden input name for form submit | ## Utility Functions | Function | Module | Description | | ------------------------------------------ | -------------------- | ----------------------------------------------------------------------------- | -| `fieldNameToLabel(name)` | `introspect.ts` | `'solfeggioFrequencyId'` → `'Solfeggio Frequency'` (strips `Id`, adds spaces) | +| `fieldNameToLabel(name)` | `introspect.ts` | `'solfeggioFrequencyId'` -> `'Solfeggio Frequency'` (strips `Id`, adds spaces) | | `resolveFieldValue(record, path)` | `introspect.ts` | Resolves dot-notation paths like `'category.name'` on nested objects | | `extractFormData(formData, fields, types)` | `form-data.ts` | Parses `FormData` with type-aware conversion per `PrismaScalarType` | | `getDelegate(config)` | `prisma-delegate.ts` | Returns `prisma[lcfirst(modelName)]` delegate | @@ -318,6 +313,32 @@ clear button, scroll-to-highlight. | `getAllModelConfigs()` | `registry.ts` | Returns all registered model configs | | `hasRole(roleId, required)` | `roles.ts` | `true` if `roleId <= required` | | `canAccessAdmin(roleId)` | `roles.ts` | `true` if `roleId <= ROLES.STAFF` | +| `loadRecords(locals, config)` | `crud.ts` | Fetches records + FK dropdown options for a model | +| `upsertRecord(formData, config, locals)` | `crud.ts` | Creates or updates a record based on presence of `id` in form data | +| `deleteRecord(formData, config, locals)` | `crud.ts` | Deletes a record by ID | + +## Models in Admin + +| Registry Slug | Prisma Model | Notes | +| -------------------------- | ---------------------- | ---------------------------------- | +| `users` | User | Role assignment, view-only fields | +| `profiles` | Profile | Linked to user FK | +| `addresses` | Address | Linked to profile FK | +| `user-roles` | UserRole | | +| `proclamations` | Proclamation | TipTap rich-text editor for content| +| `solfeggio-frequencies` | SolfeggioFrequency | | +| `proclamation-categories` | ProclamationCategory | Parent category hierarchy | +| `license-keys` | LicenseKey | listOnly — read-only table, no CRUD| +| `subscription-levels` | SubscriptionLevel | | + +### Excluded from Admin + +| Model | Reason | +| ------------------ | -------------------------------------------- | +| Session | Better Auth internal — not for manual editing| +| Account | Better Auth internal | +| Verification | Better Auth internal | +| UserProclamations | Composite key — managed via other models | ## Complete Example @@ -364,7 +385,7 @@ A hypothetical `Product` model showing all configuration features: ], accessFilter: (viewerRoleId: number) => { if (viewerRoleId <= 2) return undefined; - return { active: true }; // staff only sees active products + return { active: true }; } } ``` diff --git a/src/lib/svelte-admin/crud.spec.ts b/src/lib/svelte-admin/crud.spec.ts new file mode 100644 index 0000000..ac41251 --- /dev/null +++ b/src/lib/svelte-admin/crud.spec.ts @@ -0,0 +1,124 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { createLocals, mockUser } from '$lib/test-utils'; +import { getModelConfig } from './registry'; + +vi.mock('$lib/db', () => ({ + prisma: { + userRole: { + findMany: vi.fn(), + create: vi.fn(), + update: vi.fn(), + delete: vi.fn(), + findUnique: vi.fn(), + findFirst: vi.fn() + } + } +})); + +import { prisma } from '$lib/db'; +import { loadRecords, upsertRecord, deleteRecord } from './crud'; + +const findMany = prisma.userRole.findMany as ReturnType; +const create = prisma.userRole.create as ReturnType; +const update = prisma.userRole.update as ReturnType; +const deletes = prisma.userRole.delete as ReturnType; +const findUnique = prisma.userRole.findUnique as ReturnType; +const findFirst = prisma.userRole.findFirst as ReturnType; + +const config = getModelConfig('user-roles')!; + +describe('crud loadRecords', () => { + beforeEach(() => { + findMany.mockReset(); + }); + + it('returns records', async () => { + findMany.mockResolvedValue([{ id: 1, name: 'Admin' }]); + + const locals = createLocals(mockUser() as any); + const result = await loadRecords(locals, config); + + expect(result.records).toEqual([{ id: 1, name: 'Admin' }]); + }); + + it('returns empty records array', async () => { + findMany.mockResolvedValue([]); + + const locals = createLocals(mockUser() as any); + const result = await loadRecords(locals, config); + + expect(result.records).toEqual([]); + }); +}); + +describe('crud upsertRecord', () => { + beforeEach(() => { + create.mockReset(); + update.mockReset(); + findUnique.mockReset(); + findFirst.mockReset(); + }); + + it('creates a new record when no id', async () => { + create.mockResolvedValue({ id: 2, name: 'Editor' }); + + const fd = new FormData(); + fd.set('name', 'Editor'); + const locals = createLocals(mockUser() as any); + const result = await upsertRecord(fd, config, locals); + + expect(create).toHaveBeenCalledWith({ data: { name: 'Editor' } }); + expect(result).toEqual({ success: true }); + }); + + it('updates an existing record when id is present', async () => { + findUnique.mockResolvedValue({ id: 1, name: 'Old Name' }); + + const fd = new FormData(); + fd.set('id', '1'); + fd.set('name', 'New Name'); + const locals = createLocals(mockUser() as any); + const result = await upsertRecord(fd, config, locals); + + expect(update).toHaveBeenCalledWith({ where: { id: 1 }, data: { name: 'New Name' } }); + expect(result).toEqual({ success: true }); + }); + + it('returns error when updating non-existent record', async () => { + findUnique.mockResolvedValue(null); + + const fd = new FormData(); + fd.set('id', '999'); + fd.set('name', 'Ghost'); + const locals = createLocals(mockUser() as any); + const result = await upsertRecord(fd, config, locals); + + expect(result).toEqual({ success: false, error: 'Record not found' }); + }); +}); + +describe('crud deleteRecord', () => { + beforeEach(() => { + deletes.mockReset(); + }); + + it('deletes a record by id', async () => { + deletes.mockResolvedValue({ id: 1, name: 'Admin' }); + + const fd = new FormData(); + fd.set('id', '1'); + const locals = createLocals(mockUser() as any); + const result = await deleteRecord(fd, config, locals); + + expect(deletes).toHaveBeenCalledWith({ where: { id: 1 } }); + expect(result).toEqual({ success: true }); + }); + + it('returns error when id is missing', async () => { + const fd = new FormData(); + const locals = createLocals(mockUser() as any); + const result = await deleteRecord(fd, config, locals); + + expect(result).toEqual({ success: false, error: 'Missing id' }); + }); +}); diff --git a/src/lib/svelte-admin/crud.ts b/src/lib/svelte-admin/crud.ts new file mode 100644 index 0000000..b57a08c --- /dev/null +++ b/src/lib/svelte-admin/crud.ts @@ -0,0 +1,202 @@ +import { getDelegate, parseId } from './prisma-delegate'; +import { extractFormData } from './form-data'; +import type { AdminModelConfig } from './types'; +import { superValidate } from 'sveltekit-superforms'; +import { zod4 } from 'sveltekit-superforms/adapters'; +import * as Schemas from './schemas'; +import type { z } from 'zod'; + +const modelSchemas: Record> = { + User: Schemas.User, + Profile: Schemas.Profile, + UserRole: Schemas.UserRole, + Proclamation: Schemas.Proclamation, + ProclamationCategory: Schemas.ProclamationCategory, + SolfeggioFrequency: Schemas.SolfeggioFrequency, + SubscriptionLevel: Schemas.SubscriptionLevel, + LicenseKey: Schemas.LicenseKey +}; + +export function superFormErrorsToFieldErrors(superErrors: Record): { + error: string; + fieldErrors: Record; +} { + const fieldErrors: Record = {}; + let formError = ''; + for (const [key, value] of Object.entries(superErrors)) { + if (key === '_errors' && Array.isArray(value)) { + formError = (value[0] as string) ?? ''; + } else if ( + value && + typeof value === 'object' && + '_errors' in value && + Array.isArray((value as Record)._errors) + ) { + const errMsg = ((value as Record)._errors as string[])[0]; + fieldErrors[key] = errMsg; + } + } + return { error: formError, fieldErrors }; +} + +export async function loadRecords(locals: App.Locals, config: AdminModelConfig) { + const delegate = getDelegate(config); + + const viewerRoleId = (locals.user as { roleId?: number } | null)?.roleId ?? 4; + const where = config.accessFilter?.(viewerRoleId); + + const records = await delegate.findMany({ + where, + include: config.include, + orderBy: { id: 'asc' } + }); + + const relationOptionsData: Record = {}; + // For cascade child fields: maps field -> { childValue -> parentValue } + const cascadeOptionParentMap: Record> = {}; + + for (const [field, relConfig] of Object.entries(config.relationOptions ?? {})) { + const relDelegate = getDelegate({ ...config, modelName: relConfig.model }); + const selectFields: Record = { + [relConfig.valueField]: true, + [relConfig.labelField]: true + }; + // Check if this field is a cascade child (needs parentId) + const cascadeEntry = Object.entries(config.cascadeFields ?? {}).find( + ([, c]) => c.parentField === field + ); + if (cascadeEntry) { + selectFields['parentId'] = true; + } + const options = await relDelegate.findMany({ + select: selectFields, + orderBy: { [relConfig.labelField]: 'asc' } + }); + const mapped = (options as Record[]).map((opt: Record) => ({ + label: String(opt[relConfig.labelField]), + value: opt[relConfig.valueField] as string | number + })); + relationOptionsData[field] = mapped; + + // Build parent map if cascade child + if (cascadeEntry) { + const childField = cascadeEntry[0]; + const parentMap: Record = {}; + const rows = options as Record[]; + for (const row of rows) { + const childVal = row[relConfig.valueField] as string | number; + const parentVal = row['parentId'] as number | null; + if (parentVal != null) { + parentMap[childVal] = parentVal; + } + } + cascadeOptionParentMap[childField] = parentMap; + } + } + + return { + records: records as Record[], + relationOptionsData, + cascadeOptionParentMap + }; +} + +export async function upsertRecord( + requestOrFormData: Request | FormData, + config: AdminModelConfig, + locals: App.Locals +) { + const schema = modelSchemas[config.modelName]; + const form = schema ? await superValidate(requestOrFormData, zod4(schema)) : null; + + if (form && !form.valid) { + const { error, fieldErrors } = superFormErrorsToFieldErrors( + form.errors as Record + ); + return { ...form, success: false, error, fieldErrors }; + } + + const formData = + requestOrFormData instanceof FormData ? requestOrFormData : await requestOrFormData.formData(); + const rawId = formData.get('id')?.toString(); + const data = + form?.data ?? + (extractFormData(formData, config.formFields, config.fieldTypes) as Record); + + // Strip virtual/UI-only fields from Prisma payload + for (const f of config.dataOnlyFields ?? []) { + delete data[f]; + } + + const delegate = getDelegate(config); + const viewerRoleId = (locals.user as { roleId?: number } | null)?.roleId ?? 4; + const where = config.accessFilter?.(viewerRoleId); + + if (rawId) { + const id = parseId(config, rawId); + + const existing = await delegate.findUnique({ + where: { id }, + ...((config.include ? { include: config.include } : {}) as object) + }); + if (!existing) { + return { success: false, error: 'Record not found' }; + } + + if (where) { + const match = await delegate.findFirst({ + where: { id, ...where } + }); + if (!match) { + return { success: false, error: 'Access denied' }; + } + } + + await delegate.update({ + where: { id }, + data + }); + + return { success: true }; + } else { + try { + await delegate.create({ data }); + } catch (e: unknown) { + if (e && typeof e === 'object' && 'code' in e && (e as { code: string }).code === 'P2002') { + const meta = (e as { meta?: { target?: string[] } }).meta; + const fields = meta?.target ?? []; + return { + success: false, + error: `A record with this ${fields.join(', ')} already exists.`, + fieldErrors: Object.fromEntries(fields.map((f) => [f, 'Already taken'])) + }; + } + throw e; + } + return { success: true }; + } +} + +export async function deleteRecord( + requestOrFormData: Request | FormData, + config: AdminModelConfig, + locals: App.Locals +) { + const delegate = getDelegate(config); + const formData = + requestOrFormData instanceof FormData ? requestOrFormData : await requestOrFormData.formData(); + const rawId = formData.get('id')?.toString(); + if (!rawId) return { success: false, error: 'Missing id' }; + + const id = parseId(config, rawId); + + const viewerRoleId = (locals.user as { roleId?: number } | null)?.roleId ?? 4; + const where = config.accessFilter?.(viewerRoleId); + if (where) { + const match = await delegate.findFirst({ where: { id, ...where } }); + if (!match) return { success: false, error: 'Access denied' }; + } + + await delegate.delete({ where: { id } }); + return { success: true }; +} diff --git a/src/lib/svelte-admin/form-data.ts b/src/lib/svelte-admin/form-data.ts index 356e578..6328a12 100644 --- a/src/lib/svelte-admin/form-data.ts +++ b/src/lib/svelte-admin/form-data.ts @@ -31,6 +31,10 @@ export function extractFormData( data[field] = val === '' ? null : new Date(val); break; } + case 'Tiptap': { + data[field] = raw?.toString() ?? ''; + break; + } default: { data[field] = raw?.toString() ?? ''; break; diff --git a/src/lib/svelte-admin/schemas.ts b/src/lib/svelte-admin/schemas.ts new file mode 100644 index 0000000..5d91b58 --- /dev/null +++ b/src/lib/svelte-admin/schemas.ts @@ -0,0 +1,74 @@ +import { z } from 'zod'; + +const email = z.string().email('Invalid email address'); +const phone = z + .string() + .min(10, 'Phone number must be at least 10 digits') + .regex(/^[\d\-\+\(\) ]+$/, 'Invalid phone number format'); +const name = z.string().min(1, 'Required').max(100, 'Too long'); + +export const UserRole = z.object({ + name: z.string().min(1, 'Required') +}); + +export const User = z.object({ + name: z.string().min(1, 'Required'), + email, + roleId: z.coerce.number().int().min(1) +}); + +export const Profile = z.object({ + userId: z.string().min(1, 'Required'), + firstName: name, + lastName: name, + phoneNumber: phone +}); + +export const Address = z.object({ + profileId: z.string().min(1), + street: z.string().min(1, 'Street is required'), + city: z.string().min(1, 'City is required'), + state: z.string().min(1, 'State is required'), + postalCode: z.string().min(1, 'Postal code is required'), + country: z.string().min(1, 'Country is required'), + type: z.enum(['Mailing', 'Billing', 'Shipping']).default('Mailing'), + isDefaultMailing: z.coerce.boolean().default(false), + isDefaultBilling: z.coerce.boolean().default(false), + isDefaultShipping: z.coerce.boolean().default(false) +}); + +export const SolfeggioFrequency = z.object({ + name: z.string().min(1, 'Required'), + value: z.coerce.number().int('Must be a whole number') +}); + +export const SubscriptionLevel = z.object({ + name: z.string().min(1, 'Required'), + description: z.string().optional().default('') +}); + +export const ProclamationCategory = z.object({ + name: z.string().min(1, 'Required'), + parentId: z.coerce.number().int().optional() +}); + +export const Proclamation = z.object({ + name: z.string().min(1, 'Required'), + solfeggioFrequencyId: z.coerce.number().int(), + parentCategoryId: z.coerce.number().int(), + categoryId: z.coerce.number().int(), + subscriptionLevelId: z.coerce.number().int(), + content: z.string().optional().default('') +}); + +export const LicenseKey = z.object({ + active: z.coerce.boolean(), + level: z.string().min(1, 'Required'), + userId: z.string().min(1, 'Required') +}); + +export const UserUpdate = z.object({ + id: z.string().min(1), + name: z.string().min(1, 'Required').optional(), + email: z.string().email().optional() +}); diff --git a/src/lib/svelte-admin/types.ts b/src/lib/svelte-admin/types.ts index 6be7231..748cc71 100644 --- a/src/lib/svelte-admin/types.ts +++ b/src/lib/svelte-admin/types.ts @@ -19,6 +19,12 @@ export type RelatedRecordConfig = { editSlug?: string; }; +export type ActionResult = { + success: boolean; + error?: string; + fieldErrors?: Record; +}; + export type AdminModelConfig = { slug: string; modelName: string; @@ -35,4 +41,7 @@ export type AdminModelConfig = { relationOptions?: Record; relatedRecords?: RelatedRecordConfig[]; accessFilter?: (viewerRoleId: number) => Record | undefined; + /** Fields that should be excluded from Prisma create/update (virtual/UI-only) */ + dataOnlyFields?: string[]; + cascadeFields?: Record; }; diff --git a/src/routes/(protected)/(user)/account/+page.svelte b/src/routes/(protected)/(user)/account/+page.svelte index 05c5b01..0c4c578 100644 --- a/src/routes/(protected)/(user)/account/+page.svelte +++ b/src/routes/(protected)/(user)/account/+page.svelte @@ -37,12 +37,16 @@

Profile

{#if form?.action === 'updateProfile' && form?.success} -
+
Profile updated successfully.
{/if} {#if form?.action === 'updateProfile' && form?.error} -
+
{form.error}
{/if} @@ -115,12 +119,16 @@
{#if form?.action === 'addAddress' && form?.success} -
+
Address added successfully.
{/if} {#if form?.action === 'addAddress' && form?.error} -
+
{form.error}
{/if} @@ -133,7 +141,9 @@ >
- +
- +
- +
-
- + 0}
{#each data.user.profile.addresses as address} -
+

{address.street}

- {address.city}, {address.state} {address.postalCode} + {address.city}, {address.state} + {address.postalCode}

{address.country}

diff --git a/src/routes/(protected)/(user)/account/page.server.spec.ts b/src/routes/(protected)/(user)/account/page.server.spec.ts index 71ff2d1..3fd4b5e 100644 --- a/src/routes/(protected)/(user)/account/page.server.spec.ts +++ b/src/routes/(protected)/(user)/account/page.server.spec.ts @@ -168,9 +168,9 @@ describe('(protected)/account page server', () => { country: 'US' }); - const err = await Promise.resolve( - invokeAction('addAddress', request, createLocals()) - ).catch((e: unknown) => e); + const err = await Promise.resolve(invokeAction('addAddress', request, createLocals())).catch( + (e: unknown) => e + ); expect(isHttpError(err, 403)).toBe(true); }); @@ -201,9 +201,9 @@ describe('(protected)/account page server', () => { }); const locals = createLocals(mockUser() as any); - const err = await Promise.resolve( - invokeAction('addAddress', request, locals) - ).catch((e: unknown) => e); + const err = await Promise.resolve(invokeAction('addAddress', request, locals)).catch( + (e: unknown) => e + ); expect(isHttpError(err, 400)).toBe(true); }); diff --git a/src/routes/(protected)/(user)/account/setup/+page.svelte b/src/routes/(protected)/(user)/account/setup/+page.svelte index a7d5b3d..c2abf6b 100644 --- a/src/routes/(protected)/(user)/account/setup/+page.svelte +++ b/src/routes/(protected)/(user)/account/setup/+page.svelte @@ -1,4 +1,3 @@ -
- +
- +
@@ -91,14 +95,16 @@ class="flex flex-col rounded-lg border border-gray-200 bg-white p-5 shadow-sm transition-shadow hover:shadow-md dark:border-gray-700 dark:bg-gray-900" >

{proclamation.name}

-

{displayCategoryName(proclamation.category)}

+

+ {displayCategoryName(proclamation.category)} +

{proclamation.solfeggioFrequency.value} Hz — {proclamation.solfeggioFrequency.name} - - ${proclamation.price.toFixed(2)} + + {proclamation.subscriptionLevel?.name ?? 'Standard'}
diff --git a/src/routes/(protected)/(user)/proclamations/[id]/+page.server.ts b/src/routes/(protected)/(user)/proclamations/[id]/+page.server.ts index 1071c0f..87b8c3f 100644 --- a/src/routes/(protected)/(user)/proclamations/[id]/+page.server.ts +++ b/src/routes/(protected)/(user)/proclamations/[id]/+page.server.ts @@ -14,7 +14,8 @@ export const load: PageServerLoad = async ({ params, parent }) => { where: { id: params.id }, include: { solfeggioFrequency: true, - category: { include: { parent: true } } + category: { include: { parent: true } }, + subscriptionLevel: true } }); diff --git a/src/routes/(protected)/(user)/proclamations/[id]/+page.svelte b/src/routes/(protected)/(user)/proclamations/[id]/+page.svelte index f100c9e..71bdb74 100644 --- a/src/routes/(protected)/(user)/proclamations/[id]/+page.svelte +++ b/src/routes/(protected)/(user)/proclamations/[id]/+page.svelte @@ -19,27 +19,35 @@
-

{data.proclamation.name}

+

+ {data.proclamation.name} +

{categoryBreadcrumb}

-
+

Frequency

{data.proclamation.solfeggioFrequency.value} Hz — {data.proclamation.solfeggioFrequency.name}

-
-

Price

+
+

Level

- ${data.proclamation.price.toFixed(2)} + {data.proclamation.subscriptionLevel?.name ?? 'Standard'}

-
+
{@html data.proclamation.content}
diff --git a/src/routes/(protected)/(user)/proclamations/[id]/page.server.spec.ts b/src/routes/(protected)/(user)/proclamations/[id]/page.server.spec.ts index 2c84034..5b0c232 100644 --- a/src/routes/(protected)/(user)/proclamations/[id]/page.server.spec.ts +++ b/src/routes/(protected)/(user)/proclamations/[id]/page.server.spec.ts @@ -21,9 +21,9 @@ describe('(protected)/admin/proclamations/[id] page server load', () => { it('throws 404 when proclamation is not found', async () => { findUnique.mockResolvedValue(null); - const err = await Promise.resolve( - load({ params: { id: 'nonexistent' } } as any) - ).catch((e: unknown) => e); + const err = await Promise.resolve(load({ params: { id: 'nonexistent' } } as any)).catch( + (e: unknown) => e + ); expect(isHttpError(err, 404)).toBe(true); }); @@ -44,7 +44,8 @@ describe('(protected)/admin/proclamations/[id] page server load', () => { where: { id: 'proc-1' }, include: { solfeggioFrequency: true, - category: { include: { parent: true } } + category: { include: { parent: true } }, + subscriptionLevel: true } }); }); diff --git a/src/routes/(protected)/(user)/proclamations/page.server.spec.ts b/src/routes/(protected)/(user)/proclamations/page.server.spec.ts index 85f27b5..8d45000 100644 --- a/src/routes/(protected)/(user)/proclamations/page.server.spec.ts +++ b/src/routes/(protected)/(user)/proclamations/page.server.spec.ts @@ -14,7 +14,7 @@ import { load } from './+page.server'; const proclamationFindMany = prisma.proclamation.findMany as ReturnType; const categoryFindMany = prisma.proclamationCategory.findMany as ReturnType; - describe('(protected)/admin/proclamations page server load', () => { +describe('(protected)/admin/proclamations page server load', () => { beforeEach(() => { proclamationFindMany.mockReset(); categoryFindMany.mockReset(); @@ -29,10 +29,12 @@ const categoryFindMany = prisma.proclamationCategory.findMany as ReturnType diff --git a/src/routes/(protected)/admin/+layout.server.ts b/src/routes/(protected)/admin/+layout.server.ts index 92d4a97..031dfc1 100644 --- a/src/routes/(protected)/admin/+layout.server.ts +++ b/src/routes/(protected)/admin/+layout.server.ts @@ -3,10 +3,10 @@ import { error } from '@sveltejs/kit'; import { prisma } from '$lib/db'; import { canAccessAdmin } from '$lib/svelte-admin/roles'; -/** +/** * This Layout Server-Side page checks if the user is logged in * and if that user has a sufficient permission level to view any pages - * rendering this layout, redirecting them to a 403 error page if not. + * rendering this layout, redirecting them to a 403 error page if not. * It also makes the `adminUser` (the currently logged in user) available * to all of those pages via page data. */ @@ -18,7 +18,9 @@ export const load: LayoutServerLoad = async ({ locals }) => { }); if (!user || !canAccessAdmin(user.roleId)) { - console.log(`Attempted to access /admin via ${user?.id} : ${user?.name} with a role of ${user?.role}`); + console.log( + `Attempted to access /admin via ${user?.id} : ${user?.name} with a role of ${user?.role}` + ); throw error(403, 'not authorized'); } diff --git a/src/routes/(protected)/admin/+page.server.ts b/src/routes/(protected)/admin/+page.server.ts new file mode 100644 index 0000000..4c57c8e --- /dev/null +++ b/src/routes/(protected)/admin/+page.server.ts @@ -0,0 +1,7 @@ +import type { PageServerLoad } from './$types'; +import { getAllModelConfigs } from '$lib/svelte-admin/registry'; + +export const load: PageServerLoad = async () => { + const models = getAllModelConfigs().filter((m) => m.slug !== 'license-keys'); + return { models }; +}; diff --git a/src/routes/(protected)/admin/+page.svelte b/src/routes/(protected)/admin/+page.svelte index 86889e4..1f034ca 100644 --- a/src/routes/(protected)/admin/+page.svelte +++ b/src/routes/(protected)/admin/+page.svelte @@ -1 +1,21 @@ -

Admin Dashboard

\ No newline at end of file + + +

Admin Dashboard

+
+ {#each models as model (model.slug)} + +

{model.displayName}

+

+ {model.listFields.length} fields +

+
+ {/each} +
diff --git a/src/routes/(protected)/admin/categories/+page.server.ts b/src/routes/(protected)/admin/categories/+page.server.ts deleted file mode 100644 index e92438f..0000000 --- a/src/routes/(protected)/admin/categories/+page.server.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { PageServerLoad } from "./$types"; -import { prisma } from "$lib/db"; - -export const load: PageServerLoad = async ({ locals }) => { - console.log(locals.user?.name); - // Load proclamation categories - const categories = await prisma.proclamationCategory.findMany(); - console.log(categories); - return { categories }; -} \ No newline at end of file diff --git a/src/routes/(protected)/admin/categories/+page.svelte b/src/routes/(protected)/admin/categories/+page.svelte deleted file mode 100644 index 4827b80..0000000 --- a/src/routes/(protected)/admin/categories/+page.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - - -
- - - - - - - - - - {#if data.categories} - {#each data.categories as category, i (category.id)} - - - - {#if category.parentId} - - {:else} - - {/if} - - {/each} - {/if} - -
NameParent Category
{category.name}{getCategoryNameFromId(category.parentId)}
-
diff --git a/src/routes/(protected)/admin/license-keys/+page.server.ts b/src/routes/(protected)/admin/license-keys/+page.server.ts new file mode 100644 index 0000000..e3f4f3b --- /dev/null +++ b/src/routes/(protected)/admin/license-keys/+page.server.ts @@ -0,0 +1,68 @@ +import type { PageServerLoad } from './$types'; +import { getModelConfig } from '$lib/svelte-admin/registry'; +import { loadRecords } from '$lib/svelte-admin/crud'; +import { prisma } from '$lib/db'; +import { sendMail } from '$lib/server/resend'; +import { error } from '@sveltejs/kit'; + +const config = getModelConfig('license-keys')!; + +export const load: PageServerLoad = async ({ locals }) => { + return loadRecords(locals, config); +}; + +export const actions = { + createKey: async ({ request, locals }) => { + if (!locals.user) throw error(401, 'Unauthorized'); + + const formData = await request.formData(); + const email = formData.get('email')?.toString(); + const deactivateOld = formData.get('deactivateOld') === 'on'; + + if (!email) { + return { success: false, error: 'Email is required' }; + } + + const user = await prisma.user.findUnique({ where: { email } }); + if (!user) { + return { success: false, error: 'No user found with that email' }; + } + + // Deactivate old keys if requested + if (deactivateOld) { + await prisma.licenseKey.updateMany({ + where: { userId: user.id, active: true }, + data: { active: false } + }); + } + + // Generate 16-char hex UUID grouped as 4-4-4-4 + const hex = crypto.randomUUID().replace(/-/g, '').slice(0, 16).toUpperCase(); + const key = `${hex.slice(0, 4)}-${hex.slice(4, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}`; + + const licenseKey = await prisma.licenseKey.create({ + data: { + key, + active: true, + level: 'standard', + userId: user.id + } + }); + + // Send email with license key + try { + await sendMail({ + to: email, + subject: 'Your License Key', + data: { + firstName: user.name ?? 'Valued Customer', + licenseKey: key + } + }); + } catch (e) { + console.error('Failed to send license key email:', e); + } + + return { success: true, error: undefined }; + } +}; diff --git a/src/routes/(protected)/admin/license-keys/+page.svelte b/src/routes/(protected)/admin/license-keys/+page.svelte new file mode 100644 index 0000000..147d09f --- /dev/null +++ b/src/routes/(protected)/admin/license-keys/+page.svelte @@ -0,0 +1,100 @@ + + +
+
+

{config.displayName}

+ +
+ + {#if showCreateForm} +
+

+ Create New License Key +

+ {#if createError} +
+ {createError} +
+ {/if} +
+
+ + +
+ +
+ +
+
+
+ {/if} + + +
+ +{#if toastMessage} + +{/if} diff --git a/src/routes/(protected)/admin/proclamation-categories/+page.server.ts b/src/routes/(protected)/admin/proclamation-categories/+page.server.ts new file mode 100644 index 0000000..9eab432 --- /dev/null +++ b/src/routes/(protected)/admin/proclamation-categories/+page.server.ts @@ -0,0 +1,18 @@ +import type { PageServerLoad } from './$types'; +import { getModelConfig } from '$lib/svelte-admin/registry'; +import { loadRecords, upsertRecord, deleteRecord } from '$lib/svelte-admin/crud'; + +const config = getModelConfig('proclamation-categories')!; + +export const load: PageServerLoad = async ({ locals }) => { + return loadRecords(locals, config); +}; + +export const actions = { + upsert: async ({ request, locals }) => { + return upsertRecord(request, config, locals); + }, + delete: async ({ request, locals }) => { + return deleteRecord(request, config, locals); + } +}; diff --git a/src/routes/(protected)/admin/proclamation-categories/+page.svelte b/src/routes/(protected)/admin/proclamation-categories/+page.svelte new file mode 100644 index 0000000..8295311 --- /dev/null +++ b/src/routes/(protected)/admin/proclamation-categories/+page.svelte @@ -0,0 +1,8 @@ + + + diff --git a/src/routes/(protected)/admin/proclamations/+page.server.ts b/src/routes/(protected)/admin/proclamations/+page.server.ts new file mode 100644 index 0000000..4bc9534 --- /dev/null +++ b/src/routes/(protected)/admin/proclamations/+page.server.ts @@ -0,0 +1,18 @@ +import type { PageServerLoad } from './$types'; +import { getModelConfig } from '$lib/svelte-admin/registry'; +import { loadRecords, upsertRecord, deleteRecord } from '$lib/svelte-admin/crud'; + +const config = getModelConfig('proclamations')!; + +export const load: PageServerLoad = async ({ locals }) => { + return loadRecords(locals, config); +}; + +export const actions = { + upsert: async ({ request, locals }) => { + return upsertRecord(request, config, locals); + }, + delete: async ({ request, locals }) => { + return deleteRecord(request, config, locals); + } +}; diff --git a/src/routes/(protected)/admin/proclamations/+page.svelte b/src/routes/(protected)/admin/proclamations/+page.svelte new file mode 100644 index 0000000..5262785 --- /dev/null +++ b/src/routes/(protected)/admin/proclamations/+page.svelte @@ -0,0 +1,8 @@ + + + diff --git a/src/routes/(protected)/admin/profiles/+page.server.ts b/src/routes/(protected)/admin/profiles/+page.server.ts index 63aaf03..c824c2c 100644 --- a/src/routes/(protected)/admin/profiles/+page.server.ts +++ b/src/routes/(protected)/admin/profiles/+page.server.ts @@ -1,8 +1,16 @@ import type { PageServerLoad } from './$types'; import { getModelConfig } from '$lib/svelte-admin/registry'; -import { loadRecords, upsertRecord, deleteRecord } from '$lib/svelte-admin/crud'; +import { + loadRecords, + upsertRecord, + deleteRecord, + superFormErrorsToFieldErrors +} from '$lib/svelte-admin/crud'; import { prisma } from '$lib/db'; import { error } from '@sveltejs/kit'; +import { superValidate } from 'sveltekit-superforms'; +import { zod4 } from 'sveltekit-superforms/adapters'; +import * as Schemas from '$lib/svelte-admin/schemas'; const config = getModelConfig('profiles')!; @@ -12,67 +20,73 @@ export const load: PageServerLoad = async ({ locals }) => { export const actions = { upsert: async ({ request, locals }) => { - const formData = await request.formData(); - return upsertRecord(formData, config, locals); + return upsertRecord(request, config, locals); }, delete: async ({ request, locals }) => { - const formData = await request.formData(); - return deleteRecord(formData, config, locals); + return deleteRecord(request, config, locals); }, upsertAddress: async ({ request, locals }) => { if (!locals.user) throw error(401, 'Unauthorized'); - const formData = await request.formData(); - const id = formData.get('id')?.toString(); - const profileId = formData.get('profileId')?.toString(); + const form = await superValidate(request, zod4(Schemas.Address)); + if (!form.valid) { + const { error: addrError, fieldErrors } = superFormErrorsToFieldErrors( + form.errors as Record + ); + return { success: false, addressError: addrError, addressFieldErrors: fieldErrors }; + } + + const { profileId, isDefaultMailing, isDefaultBilling, isDefaultShipping, ...addressData } = + form.data; + if (!profileId) { return { success: false, addressError: 'Missing profile ID' }; } - const type = formData.get('type')?.toString() || 'Mailing'; - const street = formData.get('street')?.toString() || ''; - const city = formData.get('city')?.toString() || ''; - const state = formData.get('state')?.toString() || ''; - const postalCode = formData.get('postalCode')?.toString() || ''; - const country = formData.get('country')?.toString() || ''; - const isDefault = formData.get('isDefault') === 'on'; - - if (!street || !city || !state || !postalCode || !country) { - return { - success: false, - addressError: 'All address fields are required' - }; - } - - if (isDefault) { + // Unique-default enforcement: clear defaults of same type before setting + if (isDefaultMailing) { await prisma.address.updateMany({ - where: { profileId, type, isDefault: true }, - data: { isDefault: false } + where: { profileId, isDefaultMailing: true }, + data: { isDefaultMailing: false } + }); + } + if (isDefaultBilling) { + await prisma.address.updateMany({ + where: { profileId, isDefaultBilling: true }, + data: { isDefaultBilling: false } + }); + } + if (isDefaultShipping) { + await prisma.address.updateMany({ + where: { profileId, isDefaultShipping: true }, + data: { isDefaultShipping: false } }); } - if (id) { - const updated = await prisma.address.update({ - where: { id }, - data: { type, street, city, state, postalCode, country, isDefault } - }); - return { success: true, address: updated }; - } + const payload = { + ...addressData, + profileId, + isDefaultMailing, + isDefaultBilling, + isDefaultShipping + }; - const created = await prisma.address.create({ - data: { profileId, type, street, city, state, postalCode, country, isDefault } - }); + const created = await prisma.address.create({ data: payload }); return { success: true, address: created }; }, updateUser: async ({ request, locals }) => { if (!locals.user) throw error(401, 'Unauthorized'); - const formData = await request.formData(); - const userId = formData.get('id')?.toString(); - const email = formData.get('email')?.toString(); - const name = formData.get('name')?.toString(); + const form = await superValidate(request, zod4(Schemas.UserUpdate)); + if (!form.valid) { + const { error: userErr, fieldErrors } = superFormErrorsToFieldErrors( + form.errors as Record + ); + return { success: false, userError: userErr, userFieldErrors: fieldErrors }; + } - if (!userId) { + const { id, email, name } = form.data; + if (!id) { return { success: false, userError: 'Missing user ID' }; } @@ -83,7 +97,7 @@ export const actions = { return { success: false, userError: 'No fields to update' }; } - await prisma.user.update({ where: { id: userId }, data }); + await prisma.user.update({ where: { id }, data }); return { success: true }; } }; diff --git a/src/routes/(protected)/admin/profiles/+page.svelte b/src/routes/(protected)/admin/profiles/+page.svelte index 597f0a4..69e75d2 100644 --- a/src/routes/(protected)/admin/profiles/+page.svelte +++ b/src/routes/(protected)/admin/profiles/+page.svelte @@ -30,8 +30,9 @@ state: '', postalCode: '', country: '', - type: 'Mailing', - isDefault: 'false' + isDefaultMailing: 'false', + isDefaultBilling: 'false', + isDefaultShipping: 'false' }); let userEmail = $state(''); @@ -44,11 +45,9 @@ } else if ((form as any).userError) { userError = (form as any).userError; } else if (form.success) { - toastMessage = (form as any).addressError - ? 'Address saved' - : 'Saved successfully'; toastType = 'success'; if ((form as any).address) { + toastMessage = 'Address saved'; const addr = (form as any).address as Record; if (editingRecord) { const addrs = (editingRecord.addresses as Record[]) ?? []; @@ -59,7 +58,8 @@ } addressFormOpen = false; addressError = ''; - } else if (!(form as any).addressError && !(form as any).userError) { + } else { + toastMessage = 'Saved successfully'; closeModal(); } } else if (!(form as any).addressError && !(form as any).userError) { @@ -86,8 +86,8 @@ userFormOpen = false; addressError = ''; userError = ''; - userEmail = (record.user as Record)?.email as string ?? ''; - userName = (record.user as Record)?.name as string ?? ''; + userEmail = ((record.user as Record)?.email as string) ?? ''; + userName = ((record.user as Record)?.name as string) ?? ''; modalOpen = true; } @@ -162,11 +162,16 @@

- {user?.name as string ?? ''} ({user?.email as string ?? ''}) + {(user?.name as string) ?? ''} ({(user?.email as string) ?? ''})

{#if userFormOpen} -
+ {#if userError}
@@ -175,7 +180,10 @@ {/if}
-
-