From bd8df1f026806bd84aaeb5d56f740b38ae17415f Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Sun, 6 Sep 2026 17:03:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(songs):=20=E6=AD=8C=E6=9B=B2=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=94=AF=E6=8C=81=E6=89=B9=E9=87=8F=E9=A9=B3=E5=9B=9E?= =?UTF-8?q?=E3=80=81=E6=8A=95=E7=A8=BF=E7=95=99=E8=A8=80=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=AE=A1=E6=9F=A5=E4=B8=8E=E6=8E=92=E6=9C=9F=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=E5=8F=AF=E8=A7=81=E6=80=A7=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 /api/admin/songs/batch-reject.post 批量驳回接口(事务清排期/投票/扣接纳数/黑名单去重/异步通知) - requireSongAdmin 三角色校验 + createApiError 统一错误包装 - scheduleDaysBefore/After 四字段排期可见范围限制(开放 API 与公开排期接口三处缓存路径 + DB 条件过滤) - submissionNoteAutoModeration 基于黑名单 KEYWORD/LANGUAGE/GENRE 自动判定留言 publicStatus,命中自动关闭 submissionNotePublic - 更新 songs/request.post 与 songs/[id]/update.put 接入自动审查逻辑 --- app/components/Admin/SongManagement.vue | 85 +- app/components/Auth/OAuthButtons.vue | 13 +- app/composables/useSiteConfig.js | 36 +- app/composables/useTheme.ts | 156 +- .../20260906084643_auto-migration.sql | 318 ++ .../meta/20260906084643_snapshot.json | 3953 +++++++++++++++++ app/drizzle/migrations/meta/_journal.json | 9 +- app/drizzle/schema.ts | 66 +- app/plugins/sentry.client.ts | 29 + app/utils/password-policy.ts | 2 + nuxt.config.ts | 63 +- package-lock.json | 3917 +++++++++++++++- package.json | 4 + server/api/admin/songs/batch-reject.post.ts | 135 + server/api/auth/2fa/verify.post.ts | 8 +- server/api/auth/[provider]/callback.get.ts | 9 +- server/api/auth/bind.post.ts | 9 +- server/api/auth/login.post.ts | 4 +- server/api/auth/register.post.ts | 4 +- server/api/auth/verify.get.ts | 11 +- server/api/auth/webauthn/login/verify.post.ts | 4 +- server/api/open/schedules.get.ts | 41 +- server/api/site-config.get.ts | 16 +- server/api/songs/[id]/update.put.ts | 44 +- server/api/songs/public.get.ts | 39 +- server/api/songs/request.post.ts | 47 +- server/config/constants.ts | 10 + server/plugins/sentry.ts | 24 + server/services/cardCodeDeleteService.ts | 20 + server/utils/admin-password-policy.ts | 35 + server/utils/apiError.ts | 15 + server/utils/auth-route-policy.ts | 99 + server/utils/card-code-delete-handler.ts | 68 + server/utils/create-auth-session.ts | 83 + server/utils/email-verification.ts | 171 + server/utils/grade-class-core.ts | 36 + server/utils/grade-class-options.ts | 45 + server/utils/important-notification-policy.ts | 72 + server/utils/initial-password-policy.ts | 33 + server/utils/instance-id.ts | 112 + server/utils/jwt-enhanced.ts | 14 +- server/utils/notification-history-policy.ts | 108 + server/utils/oauth-identity.ts | 85 + server/utils/oauth-providers.ts | 126 + server/utils/oauth-strategies.ts | 141 + server/utils/redis.ts | 6 + server/utils/requireSongAdmin.ts | 15 + server/utils/schedule-visibility.ts | 52 + server/utils/serverTime.ts | 3 + server/utils/submissionNoteAutoModeration.ts | 150 + server/utils/system-settings-defaults.ts | 70 + server/utils/user-agent-info.ts | 71 + server/utils/user-avatar.ts | 45 + 53 files changed, 10486 insertions(+), 245 deletions(-) create mode 100644 app/drizzle/migrations/20260906084643_auto-migration.sql create mode 100644 app/drizzle/migrations/meta/20260906084643_snapshot.json create mode 100644 app/plugins/sentry.client.ts create mode 100644 app/utils/password-policy.ts create mode 100644 server/api/admin/songs/batch-reject.post.ts create mode 100644 server/plugins/sentry.ts create mode 100644 server/services/cardCodeDeleteService.ts create mode 100644 server/utils/admin-password-policy.ts create mode 100644 server/utils/apiError.ts create mode 100644 server/utils/auth-route-policy.ts create mode 100644 server/utils/card-code-delete-handler.ts create mode 100644 server/utils/create-auth-session.ts create mode 100644 server/utils/email-verification.ts create mode 100644 server/utils/grade-class-core.ts create mode 100644 server/utils/grade-class-options.ts create mode 100644 server/utils/important-notification-policy.ts create mode 100644 server/utils/initial-password-policy.ts create mode 100644 server/utils/instance-id.ts create mode 100644 server/utils/notification-history-policy.ts create mode 100644 server/utils/oauth-identity.ts create mode 100644 server/utils/oauth-providers.ts create mode 100644 server/utils/requireSongAdmin.ts create mode 100644 server/utils/schedule-visibility.ts create mode 100644 server/utils/serverTime.ts create mode 100644 server/utils/submissionNoteAutoModeration.ts create mode 100644 server/utils/system-settings-defaults.ts create mode 100644 server/utils/user-agent-info.ts create mode 100644 server/utils/user-avatar.ts diff --git a/app/components/Admin/SongManagement.vue b/app/components/Admin/SongManagement.vue index ad4445c..80f9589 100644 --- a/app/components/Admin/SongManagement.vue +++ b/app/components/Admin/SongManagement.vue @@ -61,6 +61,12 @@ > 未播放 ({{ selectedSongs.length }}) + - + @@ -39,7 +49,6 @@ const hasEnabledProviders = computed(() => { }) const loginWith = (provider: string) => { - // 外部导航到 API 端点 navigateTo(`/api/auth/${provider}`, { external: true }) } diff --git a/app/composables/useSiteConfig.js b/app/composables/useSiteConfig.js index 3202f60..428a851 100644 --- a/app/composables/useSiteConfig.js +++ b/app/composables/useSiteConfig.js @@ -19,7 +19,9 @@ const siteConfig = ref({ siteVersion: '', submissionGuidelines: '', icpNumber: '', - gonganNumber: '' + gonganNumber: '', + defaultTheme: null, + enabledThemes: null }) const isLoaded = ref(false) @@ -57,7 +59,9 @@ export const useSiteConfig = () => { gonganNumber: '', enableReplayRequests: false, enableCollaborativeSubmission: true, - enableSubmissionRemarks: false + enableSubmissionRemarks: false, + defaultTheme: 'System', + enabledThemes: '["System","ClassicDark","ClassicLight","ModernLight"]' } isLoaded.value = true } finally { @@ -96,6 +100,32 @@ export const useSiteConfig = () => { const enableSubmissionRemarks = computed(() => siteConfig.value.enableSubmissionRemarks === true) const smtpEnabled = computed(() => !!siteConfig.value.smtpEnabled) + function parseEnabledThemes(raw) { + if (Array.isArray(raw)) return raw.filter(Boolean) + if (typeof raw === 'string') { + const s = raw.trim() + if (!s) return [] + if (s.startsWith('[') || s.startsWith('{')) { + try { + const parsed = JSON.parse(s) + if (Array.isArray(parsed)) return parsed.filter(Boolean) + if (parsed && Array.isArray(parsed.items)) return parsed.items.filter(Boolean) + } catch (_) { + // fallback to comma split + } + } + return s.split(',').map((x) => x.trim()).filter(Boolean) + } + return [] + } + + const defaultTheme = computed(() => + typeof siteConfig.value.defaultTheme === 'string' && siteConfig.value.defaultTheme + ? siteConfig.value.defaultTheme + : null + ) + const enabledThemes = computed(() => parseEnabledThemes(siteConfig.value.enabledThemes)) + // 初始化配置(仅在客户端执行) const initSiteConfig = async () => { if (typeof window !== 'undefined' && !isLoaded.value) { @@ -126,6 +156,8 @@ export const useSiteConfig = () => { enableCollaborativeSubmission, enableSubmissionRemarks, smtpEnabled, + defaultTheme, + enabledThemes, fetchSiteConfig, initSiteConfig, refreshSiteConfig diff --git a/app/composables/useTheme.ts b/app/composables/useTheme.ts index 9c25b36..5cdca88 100644 --- a/app/composables/useTheme.ts +++ b/app/composables/useTheme.ts @@ -1,4 +1,4 @@ -import { computed, ref, watch } from 'vue' +import { computed, ref, watch, nextTick } from 'vue' const STORAGE_KEY = 'voicehub:theme' type ThemeName = string & {} @@ -15,6 +15,25 @@ function getMetaThemeColor() { return document.querySelector('meta[name="theme-color"]') } +function parseEnabledThemesRaw(raw: unknown): string[] { + if (Array.isArray(raw)) return raw.filter(Boolean) as string[] + if (typeof raw === 'string') { + const s = raw.trim() + if (!s) return [] + if (s.startsWith('[') || s.startsWith('{')) { + try { + const parsed = JSON.parse(s) + if (Array.isArray(parsed)) return parsed.filter(Boolean) as string[] + if (parsed && Array.isArray((parsed as any).items)) return (parsed as any).items.filter(Boolean) as string[] + } catch (_) { + // fallback + } + } + return s.split(',').map((x) => x.trim()).filter(Boolean) + } + return [] +} + function applyTheme(theme: string) { if (!isBrowser()) return @@ -24,11 +43,12 @@ function applyTheme(theme: string) { root.setAttribute('data-theme', theme) if (appRoot) appRoot.setAttribute('data-theme', theme) - if (theme === 'dark') { + const effective = resolveEffectiveTheme(theme) + if (effective === 'dark') { root.classList.add('dark') root.classList.remove('light') root.style.colorScheme = 'dark' - } else if (theme === 'light') { + } else if (effective === 'light') { root.classList.add('light') root.classList.remove('dark') root.style.colorScheme = 'light' @@ -39,11 +59,7 @@ function applyTheme(theme: string) { const meta = getMetaThemeColor() if (meta) { - if (theme === 'light') { - meta.content = '#f8fafc' - } else { - meta.content = '#111111' - } + meta.content = effective === 'light' ? '#f8fafc' : '#111111' } try { @@ -59,18 +75,37 @@ function detectSystemTheme(): 'dark' | 'light' { return prefersDark ? 'dark' : 'light' } +function resolveEffectiveTheme(theme: string): 'dark' | 'light' | string { + if (theme === 'System' || theme === 'system') { + return detectSystemTheme() + } + if (theme === 'dark' || theme.endsWith('Dark')) return 'dark' + if (theme === 'light' || theme.endsWith('Light')) return 'light' + return theme +} + export function useTheme() { const config = useRuntimeConfig() + const { isLoaded: siteConfigLoaded, defaultTheme: siteDefaultTheme, enabledThemes: siteEnabledThemes, initSiteConfig } = useSiteConfig() const enabledThemes = computed(() => { - const list = (config.public?.enabledThemes as unknown) as string[] | undefined - return Array.isArray(list) && list.length > 0 ? list : ['dark', 'light'] + if (siteConfigLoaded.value && siteEnabledThemes.value.length > 0) { + return [...new Set(siteEnabledThemes.value)] + } + const fromRuntime = parseEnabledThemesRaw(config.public?.enabledThemes) + if (fromRuntime.length > 0) return fromRuntime + return ['System', 'dark', 'light'] }) const defaultTheme = computed(() => { - const value = config.public?.defaultTheme as string | undefined - if (value && enabledThemes.value.includes(value)) return value - return enabledThemes.value.includes('dark') ? 'dark' : enabledThemes.value[0] || 'dark' + if (siteConfigLoaded.value && siteDefaultTheme.value) { + return siteDefaultTheme.value + } + const fromRuntime = config.public?.defaultTheme + if (typeof fromRuntime === 'string' && fromRuntime) { + return fromRuntime + } + return 'System' }) const theme = computed({ @@ -79,21 +114,22 @@ export function useTheme() { }) const isDark = computed(() => { - const t = theme.value - if (t === 'dark') return true - if (t === 'light') return false - return detectSystemTheme() === 'dark' + return resolveEffectiveTheme(theme.value) === 'dark' }) function isThemeEnabled(name: string) { return enabledThemes.value.includes(name) } + function firstValidTheme(candidate: string): string { + const list = enabledThemes.value + if (list.includes(candidate)) return candidate + if (list.includes(defaultTheme.value)) return defaultTheme.value + return list[0] ?? 'System' + } + function setTheme(next: string, { persist = true } = {}) { - let candidate = next - if (!enabledThemes.value.includes(candidate)) { - candidate = defaultTheme.value - } + const candidate = firstValidTheme(next) if (currentTheme.value === candidate && initialized.value) return @@ -110,7 +146,7 @@ export function useTheme() { } function toggleTheme() { - const order = enabledThemes.value.length >= 2 ? enabledThemes.value : ['dark', 'light'] + const order = enabledThemes.value.length >= 2 ? enabledThemes.value : ['System', 'dark', 'light'] const current = theme.value const idx = order.indexOf(current) const next = order[(idx + 1) % order.length] @@ -121,8 +157,31 @@ export function useTheme() { setTheme(defaultTheme.value, { persist: false }) } - function init() { + function onSystemThemeChange() { + const stored = (() => { + try { + return localStorage.getItem(STORAGE_KEY) + } catch { + return null + } + })() + if (!stored) { + applyTheme(theme.value) + } + } + + async function init() { if (initialized.value || !isBrowser()) return + + if (!siteConfigLoaded.value) { + try { + await initSiteConfig() + await nextTick() + } catch (_) { + /* ignore */ + } + } + initialized.value = true let stored: string | null = null @@ -132,34 +191,43 @@ export function useTheme() { stored = null } - if (stored && enabledThemes.value.includes(stored)) { - setTheme(stored) - return + if (stored) { + const valid = firstValidTheme(stored) + if (valid === stored || enabledThemes.value.includes(stored)) { + setTheme(stored) + watchSystemTheme() + return + } } setTheme(defaultTheme.value, { persist: false }) + watchSystemTheme() + } - if (window.matchMedia) { - const mql = window.matchMedia('(prefers-color-scheme: dark)') - const onChange = () => { - let s: string | null = null - try { - s = localStorage.getItem(STORAGE_KEY) - } catch { - s = null - } - if (!s) { - setTheme(defaultTheme.value, { persist: false }) - } - } - if (typeof mql.addEventListener === 'function') { - mql.addEventListener('change', onChange) - } else if (typeof mql.addListener === 'function') { - mql.addListener(onChange) - } + function watchSystemTheme() { + if (!isBrowser() || !window.matchMedia) return + const mql = window.matchMedia('(prefers-color-scheme: dark)') + if (typeof mql.addEventListener === 'function') { + mql.addEventListener('change', onSystemThemeChange) + } else if (typeof (mql as any).addListener === 'function') { + ;(mql as any).addListener(onSystemThemeChange) } } + watch(defaultTheme, () => { + if (!initialized.value) return + const stored = (() => { + try { + return localStorage.getItem(STORAGE_KEY) + } catch { + return null + } + })() + if (!stored) { + setTheme(defaultTheme.value, { persist: false }) + } + }) + return { theme, currentTheme, diff --git a/app/drizzle/migrations/20260906084643_auto-migration.sql b/app/drizzle/migrations/20260906084643_auto-migration.sql new file mode 100644 index 0000000..e854472 --- /dev/null +++ b/app/drizzle/migrations/20260906084643_auto-migration.sql @@ -0,0 +1,318 @@ +CREATE TYPE "public"."card_code_status" AS ENUM('AVAILABLE', 'LOCKED', 'REDEEMED', 'INVALID');--> statement-breakpoint +ALTER TYPE "public"."BlacklistType" ADD VALUE 'LANGUAGE';--> statement-breakpoint +ALTER TYPE "public"."BlacklistType" ADD VALUE 'GENRE';--> statement-breakpoint +ALTER TYPE "public"."user_status" ADD VALUE 'pending';--> statement-breakpoint +ALTER TYPE "public"."user_status" ADD VALUE 'rejected';--> statement-breakpoint +CREATE TABLE "auth_sessions" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" integer NOT NULL, + "session_token" varchar(255) NOT NULL, + "expires_at" timestamp with time zone NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "ip_address" text, + "user_agent" text, + "last_active_at" timestamp with time zone DEFAULT now() NOT NULL, + "is_revoked" boolean DEFAULT false NOT NULL, + "browser" text, + "operating_system" text, + "device" text, + "login_method" text DEFAULT 'password' NOT NULL, + "revoked_at" timestamp with time zone, + "revoked_reason" text, + CONSTRAINT "auth_sessions_session_token_unique" UNIQUE("session_token") +); +--> statement-breakpoint +CREATE TABLE "backup_records" ( + "id" serial PRIMARY KEY NOT NULL, + "filename" text NOT NULL, + "file_path" text NOT NULL, + "file_size" bigint NOT NULL, + "type" text DEFAULT 'MANUAL' NOT NULL, + "status" text DEFAULT 'COMPLETED' NOT NULL, + "error_message" text, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "started_at" timestamp with time zone, + "completed_at" timestamp with time zone, + "created_by" integer, + "expires_at" timestamp with time zone +); +--> statement-breakpoint +CREATE TABLE "card_code_redemptions" ( + "id" serial PRIMARY KEY NOT NULL, + "card_code_id" integer NOT NULL, + "user_id" integer NOT NULL, + "redeemed_at" timestamp with time zone DEFAULT now() NOT NULL, + "song_id" integer, + "purpose" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "card_codes" ( + "id" serial PRIMARY KEY NOT NULL, + "code" varchar(64) NOT NULL, + "status" "card_code_status" DEFAULT 'AVAILABLE' NOT NULL, + "type" text NOT NULL, + "value" integer DEFAULT 1 NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "expires_at" timestamp with time zone, + "locked_at" timestamp with time zone, + "locked_by" integer, + "batch_id" varchar(64), + "note" text, + CONSTRAINT "card_codes_code_unique" UNIQUE("code") +); +--> statement-breakpoint +CREATE TABLE "ChangelogEntry" ( + "id" serial PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "version" text NOT NULL, + "title" text NOT NULL, + "content" text NOT NULL, + "published" boolean DEFAULT false NOT NULL, + "publishedAt" timestamp, + "createdBy" integer +); +--> statement-breakpoint +CREATE TABLE "ExpectedPlayDate" ( + "id" serial PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "date" text NOT NULL, + "availableSequences" text NOT NULL, + "enabled" boolean DEFAULT true NOT NULL, + CONSTRAINT "ExpectedPlayDate_date_unique" UNIQUE("date") +); +--> statement-breakpoint +CREATE TABLE "GradeClass" ( + "id" serial PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "grade" text NOT NULL, + "class" text NOT NULL, + "enabled" boolean DEFAULT true NOT NULL, + CONSTRAINT "grade_class_unique" UNIQUE("grade","class") +); +--> statement-breakpoint +CREATE TABLE "oauth_providers" ( + "id" serial PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "displayName" text, + "enabled" boolean DEFAULT true NOT NULL, + "clientId" text, + "clientSecret" text, + "authorizationEndpoint" text, + "tokenEndpoint" text, + "userInfoEndpoint" text, + "scope" text, + "redirectUri" text, + "usernameClaim" text DEFAULT 'preferred_username', + "nameClaim" text DEFAULT 'name', + "emailClaim" text DEFAULT 'email', + "avatarClaim" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "sortOrder" integer DEFAULT 0 NOT NULL, + "icon" text +); +--> statement-breakpoint +CREATE TABLE "passkey_challenges" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "challenge" text NOT NULL, + "type" text NOT NULL, + "user_id" integer, + "expires_at" timestamp with time zone NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "schedule_song_pool" ( + "id" serial PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "song_id" integer NOT NULL, + "target_play_date" timestamp, + "priority" integer DEFAULT 0 NOT NULL, + "added_by" integer, + "note" text, + "status" text DEFAULT 'PENDING' NOT NULL +); +--> statement-breakpoint +CREATE TABLE "SongComment" ( + "id" serial PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "songId" integer NOT NULL, + "userId" integer NOT NULL, + "content" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "submission_restriction_exemptions" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "exemption_type" text NOT NULL, + "reason" text, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "expires_at" timestamp with time zone, + "created_by" integer, + CONSTRAINT "submission_restriction_exemptions_user_type_unique" UNIQUE("user_id","exemption_type") +); +--> statement-breakpoint +CREATE TABLE "user_passkeys" ( + "id" text PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "name" text, + "public_key" text NOT NULL, + "credential_device_type" text NOT NULL, + "credential_backed_up" boolean NOT NULL, + "transports" text, + "counter" integer DEFAULT 0 NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "last_used_at" timestamp with time zone +); +--> statement-breakpoint +ALTER TABLE "User" ALTER COLUMN "forcePasswordChange" SET DEFAULT false;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "batch_id" uuid;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "source" text DEFAULT 'SYSTEM' NOT NULL;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "sender_id" integer;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "sender_name" text;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "sender_username" text;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "title" text;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "important" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "Notification" ADD COLUMN "user_deleted" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "Schedule" ADD COLUMN "replay_request_id" integer;--> statement-breakpoint +ALTER TABLE "Song" ADD COLUMN "expectedPlayDate" text;--> statement-breakpoint +ALTER TABLE "Song" ADD COLUMN "expectedPlaySequence" integer;--> statement-breakpoint +ALTER TABLE "Song" ADD COLUMN "durationSeconds" integer;--> statement-breakpoint +ALTER TABLE "Song" ADD COLUMN "submissionNotePublicStatus" text;--> statement-breakpoint +ALTER TABLE "Song" ADD COLUMN "cardCodeId" integer;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "siteVersion" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionNoteRequiresApproval" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "instanceId" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "telemetryEnabled" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "showBeianIcon" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysDisplay" integer DEFAULT 7 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysEditable" integer DEFAULT 3 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysRequestable" integer DEFAULT 14 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysBeforeEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysBefore" integer DEFAULT 1 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysAfterEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "scheduleDaysAfter" integer DEFAULT 1 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "forcePasswordChangeOnFirstLogin" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "enableSubmissionRestriction" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionRestrictionScope" text DEFAULT 'all' NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "sameSongRestrictionHours" integer;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "sameArtistRestrictionHours" integer;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "cardCodeEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "cardCodeSubmissionRequired" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "cardCodeVoteEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "cardCodeReplayEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "enableCardCodeRequests" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "requireCardCodeForRequests" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "enableCardCodeLimitBypass" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionRestrictionEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionRestrictionGradeEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionRestrictionClassEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionRestrictionGraduateEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "submissionRestrictionWithdrawnEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "captchaProvider" text DEFAULT 'TURNSTILE';--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "captchaEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "turnstileSiteKey" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "turnstileSecretKey" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "allowRegister" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerRequireEmail" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerRequireEmailVerify" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerDefaultRole" text DEFAULT 'USER';--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerEnabledGradeClasses" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerRequiresApproval" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthRegisterRequiresApproval" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerEmailRequired" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "registerRequiresGradeClass" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthAllowRegister" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthAllowLogin" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthAllowBind" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "allowOAuthRegistration" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthRedirectUri" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthStateSecret" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "oauthProviders" text DEFAULT '[]';--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "githubOAuthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "githubClientId" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "githubClientSecret" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "casdoorOAuthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "casdoorServerUrl" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "casdoorClientId" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "casdoorClientSecret" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "casdoorOrganizationName" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "googleOAuthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "googleClientId" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "googleClientSecret" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "aggregateOAuthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "aggregateOAuthAppId" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "aggregateOAuthAppKey" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "aggregateOAuthLoginType" text DEFAULT 'qq';--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "aggregateOAuthEndpoint" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthDisplayName" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthAuthorizeUrl" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthTokenUrl" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthUserInfoUrl" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthScope" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthClientId" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthClientSecret" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthUserIdField" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthUsernameField" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthNameField" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthEmailField" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "customOAuthAvatarField" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "captchaMaxFailures" integer DEFAULT 3 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "autoBackupEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "autoBackupIntervalHours" integer DEFAULT 24 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "autoBackupRetentionDays" integer DEFAULT 30 NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "autoBackupConfig" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "statisticsCode" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "statisticsCodeEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "defaultTheme" text DEFAULT 'System' NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "enabledThemes" text DEFAULT '["System","ClassicDark","ClassicLight","ModernLight"]' NOT NULL;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "enabledPlatforms" text;--> statement-breakpoint +ALTER TABLE "SystemSettings" ADD COLUMN "platformOrder" text;--> statement-breakpoint +ALTER TABLE "User" ADD COLUMN "studentId" text;--> statement-breakpoint +ALTER TABLE "User" ADD COLUMN "tokenVersion" integer DEFAULT 0 NOT NULL;--> statement-breakpoint +ALTER TABLE "User" ADD COLUMN "avatarProvider" text;--> statement-breakpoint +ALTER TABLE "User" ADD COLUMN "avatarProviderUserId" text;--> statement-breakpoint +ALTER TABLE "User" ADD COLUMN "remark" text;--> statement-breakpoint +ALTER TABLE "auth_sessions" ADD CONSTRAINT "auth_sessions_user_id_User_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "card_code_redemptions" ADD CONSTRAINT "card_code_redemptions_card_code_id_card_codes_id_fk" FOREIGN KEY ("card_code_id") REFERENCES "public"."card_codes"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "card_code_redemptions" ADD CONSTRAINT "card_code_redemptions_user_id_User_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "card_code_redemptions" ADD CONSTRAINT "card_code_redemptions_song_id_Song_id_fk" FOREIGN KEY ("song_id") REFERENCES "public"."Song"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "schedule_song_pool" ADD CONSTRAINT "schedule_song_pool_song_id_Song_id_fk" FOREIGN KEY ("song_id") REFERENCES "public"."Song"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "submission_restriction_exemptions" ADD CONSTRAINT "submission_restriction_exemptions_user_id_User_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "user_passkeys" ADD CONSTRAINT "user_passkeys_user_id_User_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "auth_sessions_user_active_idx" ON "auth_sessions" USING btree ("user_id","is_revoked","expires_at");--> statement-breakpoint +CREATE INDEX "auth_sessions_expires_at_idx" ON "auth_sessions" USING btree ("expires_at");--> statement-breakpoint +CREATE INDEX "auth_sessions_last_active_idx" ON "auth_sessions" USING btree ("last_active_at");--> statement-breakpoint +CREATE UNIQUE INDEX "auth_sessions_session_token_unique" ON "auth_sessions" USING btree ("session_token");--> statement-breakpoint +CREATE INDEX "backup_records_created_at_idx" ON "backup_records" USING btree ("created_at");--> statement-breakpoint +CREATE INDEX "backup_records_status_idx" ON "backup_records" USING btree ("status");--> statement-breakpoint +CREATE INDEX "card_code_redemptions_user_id_idx" ON "card_code_redemptions" USING btree ("user_id");--> statement-breakpoint +CREATE INDEX "card_code_redemptions_card_code_id_idx" ON "card_code_redemptions" USING btree ("card_code_id");--> statement-breakpoint +CREATE INDEX "card_codes_status_idx" ON "card_codes" USING btree ("status");--> statement-breakpoint +CREATE INDEX "card_codes_batch_id_idx" ON "card_codes" USING btree ("batch_id");--> statement-breakpoint +CREATE INDEX "card_codes_expires_at_idx" ON "card_codes" USING btree ("expires_at");--> statement-breakpoint +CREATE INDEX "passkey_challenges_challenge_idx" ON "passkey_challenges" USING btree ("challenge");--> statement-breakpoint +CREATE INDEX "passkey_challenges_expires_at_idx" ON "passkey_challenges" USING btree ("expires_at");--> statement-breakpoint +CREATE INDEX "schedule_song_pool_song_id_idx" ON "schedule_song_pool" USING btree ("song_id");--> statement-breakpoint +CREATE INDEX "schedule_song_pool_target_date_idx" ON "schedule_song_pool" USING btree ("target_play_date");--> statement-breakpoint +CREATE INDEX "submission_restriction_exemptions_user_id_idx" ON "submission_restriction_exemptions" USING btree ("user_id");--> statement-breakpoint +CREATE INDEX "user_passkeys_user_id_idx" ON "user_passkeys" USING btree ("user_id");--> statement-breakpoint +ALTER TABLE "Song" ADD CONSTRAINT "Song_cardCodeId_card_codes_id_fk" FOREIGN KEY ("cardCodeId") REFERENCES "public"."card_codes"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "notification_user_important_read_created_idx" ON "Notification" USING btree ("userId","important","read","createdAt");--> statement-breakpoint +CREATE INDEX "notification_batch_id_idx" ON "Notification" USING btree ("batch_id");--> statement-breakpoint +CREATE INDEX "schedule_published_song_idx" ON "Schedule" USING btree ("publishedAt","songId");--> statement-breakpoint +CREATE INDEX "schedule_published_date_idx" ON "Schedule" USING btree ("publishedAt","playDate");--> statement-breakpoint +CREATE INDEX "song_card_code_id_idx" ON "Song" USING btree ("cardCodeId");--> statement-breakpoint +CREATE INDEX "song_semester_created_at_idx" ON "Song" USING btree ("semester","createdAt");--> statement-breakpoint +CREATE INDEX "song_requester_id_idx" ON "Song" USING btree ("requesterId");--> statement-breakpoint +CREATE UNIQUE INDEX "User_username_unique" ON "User" USING btree ("username");--> statement-breakpoint +CREATE INDEX "vote_user_song_idx" ON "Vote" USING btree ("userId","songId");--> statement-breakpoint +ALTER TABLE "Vote" ADD CONSTRAINT "vote_song_user_unique" UNIQUE("songId","userId"); \ No newline at end of file diff --git a/app/drizzle/migrations/meta/20260906084643_snapshot.json b/app/drizzle/migrations/meta/20260906084643_snapshot.json new file mode 100644 index 0000000..3d7de32 --- /dev/null +++ b/app/drizzle/migrations/meta/20260906084643_snapshot.json @@ -0,0 +1,3953 @@ +{ + "id": "e55ad241-91ce-4c7e-9d3a-79433b19976e", + "prevId": "9a604776-4a2c-47e2-ac0f-87bdc9c94abf", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.api_key_permissions": { + "name": "api_key_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key_hash": { + "name": "key_hash", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "key_prefix": { + "name": "key_prefix", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "usage_count": { + "name": "usage_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_hash_unique": { + "name": "api_keys_key_hash_unique", + "nullsNotDistinct": false, + "columns": [ + "key_hash" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_logs": { + "name": "api_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "response_time_ms": { + "name": "response_time_ms", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "request_body": { + "name": "request_body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_body": { + "name": "response_body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth_sessions": { + "name": "auth_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "session_token": { + "name": "session_token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_active_at": { + "name": "last_active_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_revoked": { + "name": "is_revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "browser": { + "name": "browser", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "operating_system": { + "name": "operating_system", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "login_method": { + "name": "login_method", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'password'" + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "revoked_reason": { + "name": "revoked_reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "auth_sessions_user_active_idx": { + "name": "auth_sessions_user_active_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_revoked", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auth_sessions_expires_at_idx": { + "name": "auth_sessions_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auth_sessions_last_active_idx": { + "name": "auth_sessions_last_active_idx", + "columns": [ + { + "expression": "last_active_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auth_sessions_session_token_unique": { + "name": "auth_sessions_session_token_unique", + "columns": [ + { + "expression": "session_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "auth_sessions_user_id_User_id_fk": { + "name": "auth_sessions_user_id_User_id_fk", + "tableFrom": "auth_sessions", + "tableTo": "User", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_sessions_session_token_unique": { + "name": "auth_sessions_session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "session_token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup_records": { + "name": "backup_records", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'MANUAL'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'COMPLETED'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "backup_records_created_at_idx": { + "name": "backup_records_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "backup_records_status_idx": { + "name": "backup_records_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.card_code_redemptions": { + "name": "card_code_redemptions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "card_code_id": { + "name": "card_code_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "redeemed_at": { + "name": "redeemed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "song_id": { + "name": "song_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "purpose": { + "name": "purpose", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "card_code_redemptions_user_id_idx": { + "name": "card_code_redemptions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "card_code_redemptions_card_code_id_idx": { + "name": "card_code_redemptions_card_code_id_idx", + "columns": [ + { + "expression": "card_code_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "card_code_redemptions_card_code_id_card_codes_id_fk": { + "name": "card_code_redemptions_card_code_id_card_codes_id_fk", + "tableFrom": "card_code_redemptions", + "tableTo": "card_codes", + "columnsFrom": [ + "card_code_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "card_code_redemptions_user_id_User_id_fk": { + "name": "card_code_redemptions_user_id_User_id_fk", + "tableFrom": "card_code_redemptions", + "tableTo": "User", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "card_code_redemptions_song_id_Song_id_fk": { + "name": "card_code_redemptions_song_id_Song_id_fk", + "tableFrom": "card_code_redemptions", + "tableTo": "Song", + "columnsFrom": [ + "song_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.card_codes": { + "name": "card_codes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "card_code_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'AVAILABLE'" + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "locked_at": { + "name": "locked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "locked_by": { + "name": "locked_by", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "batch_id": { + "name": "batch_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "card_codes_status_idx": { + "name": "card_codes_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "card_codes_batch_id_idx": { + "name": "card_codes_batch_id_idx", + "columns": [ + { + "expression": "batch_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "card_codes_expires_at_idx": { + "name": "card_codes_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "card_codes_code_unique": { + "name": "card_codes_code_unique", + "nullsNotDistinct": false, + "columns": [ + "code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ChangelogEntry": { + "name": "ChangelogEntry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "publishedAt": { + "name": "publishedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "createdBy": { + "name": "createdBy", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.collaboration_logs": { + "name": "collaboration_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "collaborator_id": { + "name": "collaborator_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "operator_id": { + "name": "operator_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.EmailTemplate": { + "name": "EmailTemplate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "key": { + "name": "key", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(200)", + "primaryKey": false, + "notNull": true + }, + "subject": { + "name": "subject", + "type": "varchar(300)", + "primaryKey": false, + "notNull": true + }, + "html": { + "name": "html", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updatedByUserId": { + "name": "updatedByUserId", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ExpectedPlayDate": { + "name": "ExpectedPlayDate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "availableSequences": { + "name": "availableSequences", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "ExpectedPlayDate_date_unique": { + "name": "ExpectedPlayDate_date_unique", + "nullsNotDistinct": false, + "columns": [ + "date" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.GradeClass": { + "name": "GradeClass", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "grade": { + "name": "grade", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "class": { + "name": "class", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "grade_class_unique": { + "name": "grade_class_unique", + "nullsNotDistinct": false, + "columns": [ + "grade", + "class" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.NotificationSettings": { + "name": "NotificationSettings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "songRequestEnabled": { + "name": "songRequestEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "songVotedEnabled": { + "name": "songVotedEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "songPlayedEnabled": { + "name": "songPlayedEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "refreshInterval": { + "name": "refreshInterval", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 60 + }, + "songVotedThreshold": { + "name": "songVotedThreshold", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Notification": { + "name": "Notification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "read": { + "name": "read", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "songId": { + "name": "songId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "batch_id": { + "name": "batch_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'SYSTEM'" + }, + "sender_id": { + "name": "sender_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sender_name": { + "name": "sender_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sender_username": { + "name": "sender_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "important": { + "name": "important", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_deleted": { + "name": "user_deleted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "notification_user_important_read_created_idx": { + "name": "notification_user_important_read_created_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "important", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "read", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "createdAt", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notification_batch_id_idx": { + "name": "notification_batch_id_idx", + "columns": [ + { + "expression": "batch_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_providers": { + "name": "oauth_providers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "displayName": { + "name": "displayName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "clientId": { + "name": "clientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "clientSecret": { + "name": "clientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "authorizationEndpoint": { + "name": "authorizationEndpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokenEndpoint": { + "name": "tokenEndpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userInfoEndpoint": { + "name": "userInfoEndpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirectUri": { + "name": "redirectUri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "usernameClaim": { + "name": "usernameClaim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'preferred_username'" + }, + "nameClaim": { + "name": "nameClaim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'name'" + }, + "emailClaim": { + "name": "emailClaim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'email'" + }, + "avatarClaim": { + "name": "avatarClaim", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "sortOrder": { + "name": "sortOrder", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.passkey_challenges": { + "name": "passkey_challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "challenge": { + "name": "challenge", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "passkey_challenges_challenge_idx": { + "name": "passkey_challenges_challenge_idx", + "columns": [ + { + "expression": "challenge", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "passkey_challenges_expires_at_idx": { + "name": "passkey_challenges_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.PlayTime": { + "name": "PlayTime", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "startTime": { + "name": "startTime", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endTime": { + "name": "endTime", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.RequestTime": { + "name": "RequestTime", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp(6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "startTime": { + "name": "startTime", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "endTime": { + "name": "endTime", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expected": { + "name": "expected", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "accepted": { + "name": "accepted", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "past": { + "name": "past", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.schedule_song_pool": { + "name": "schedule_song_pool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "song_id": { + "name": "song_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "target_play_date": { + "name": "target_play_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "added_by": { + "name": "added_by", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'PENDING'" + } + }, + "indexes": { + "schedule_song_pool_song_id_idx": { + "name": "schedule_song_pool_song_id_idx", + "columns": [ + { + "expression": "song_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "schedule_song_pool_target_date_idx": { + "name": "schedule_song_pool_target_date_idx", + "columns": [ + { + "expression": "target_play_date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "schedule_song_pool_song_id_Song_id_fk": { + "name": "schedule_song_pool_song_id_Song_id_fk", + "tableFrom": "schedule_song_pool", + "tableTo": "Song", + "columnsFrom": [ + "song_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Schedule": { + "name": "Schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "songId": { + "name": "songId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "playDate": { + "name": "playDate", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "played": { + "name": "played", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "playTimeId": { + "name": "playTimeId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "isDraft": { + "name": "isDraft", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "publishedAt": { + "name": "publishedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "replay_request_id": { + "name": "replay_request_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "schedule_published_song_idx": { + "name": "schedule_published_song_idx", + "columns": [ + { + "expression": "publishedAt", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "songId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "schedule_published_date_idx": { + "name": "schedule_published_date_idx", + "columns": [ + { + "expression": "publishedAt", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "playDate", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Semester": { + "name": "Semester", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.SongBlacklist": { + "name": "SongBlacklist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "type": { + "name": "type", + "type": "BlacklistType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdBy": { + "name": "createdBy", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.song_collaborators": { + "name": "song_collaborators", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "song_id": { + "name": "song_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "collaborator_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'PENDING'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.SongComment": { + "name": "SongComment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "songId": { + "name": "songId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.song_replay_requests": { + "name": "song_replay_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "song_id": { + "name": "song_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "status": { + "name": "status", + "type": "replay_request_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'PENDING'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "song_replay_requests_song_id_user_id_unique": { + "name": "song_replay_requests_song_id_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "song_id", + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Song": { + "name": "Song", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "kg_hash": { + "name": "kg_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "singer": { + "name": "singer", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "cover_url": { + "name": "cover_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "artist": { + "name": "artist", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "requesterId": { + "name": "requesterId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "played": { + "name": "played", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "playedAt": { + "name": "playedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "semester": { + "name": "semester", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preferredPlayTimeId": { + "name": "preferredPlayTimeId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cover": { + "name": "cover", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "playUrl": { + "name": "playUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "musicPlatform": { + "name": "musicPlatform", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "musicId": { + "name": "musicId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "submissionNote": { + "name": "submissionNote", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "submissionNotePublic": { + "name": "submissionNotePublic", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "hitRequestId": { + "name": "hitRequestId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "expectedPlayDate": { + "name": "expectedPlayDate", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expectedPlaySequence": { + "name": "expectedPlaySequence", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "durationSeconds": { + "name": "durationSeconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "submissionNotePublicStatus": { + "name": "submissionNotePublicStatus", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cardCodeId": { + "name": "cardCodeId", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "song_card_code_id_idx": { + "name": "song_card_code_id_idx", + "columns": [ + { + "expression": "cardCodeId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "song_semester_created_at_idx": { + "name": "song_semester_created_at_idx", + "columns": [ + { + "expression": "semester", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "createdAt", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "song_requester_id_idx": { + "name": "song_requester_id_idx", + "columns": [ + { + "expression": "requesterId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "Song_cardCodeId_card_codes_id_fk": { + "name": "Song_cardCodeId_card_codes_id_fk", + "tableFrom": "Song", + "tableTo": "card_codes", + "columnsFrom": [ + "cardCodeId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.submission_restriction_exemptions": { + "name": "submission_restriction_exemptions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "exemption_type": { + "name": "exemption_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "submission_restriction_exemptions_user_id_idx": { + "name": "submission_restriction_exemptions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "submission_restriction_exemptions_user_id_User_id_fk": { + "name": "submission_restriction_exemptions_user_id_User_id_fk", + "tableFrom": "submission_restriction_exemptions", + "tableTo": "User", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "submission_restriction_exemptions_user_type_unique": { + "name": "submission_restriction_exemptions_user_type_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "exemption_type" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.SystemSettings": { + "name": "SystemSettings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "enablePlayTimeSelection": { + "name": "enablePlayTimeSelection", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "siteTitle": { + "name": "siteTitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "siteLogoUrl": { + "name": "siteLogoUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schoolLogoHomeUrl": { + "name": "schoolLogoHomeUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schoolLogoPrintUrl": { + "name": "schoolLogoPrintUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "siteDescription": { + "name": "siteDescription", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "siteVersion": { + "name": "siteVersion", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "submissionGuidelines": { + "name": "submissionGuidelines", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icpNumber": { + "name": "icpNumber", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gonganNumber": { + "name": "gonganNumber", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableSubmissionLimit": { + "name": "enableSubmissionLimit", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dailySubmissionLimit": { + "name": "dailySubmissionLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "weeklySubmissionLimit": { + "name": "weeklySubmissionLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "monthlySubmissionLimit": { + "name": "monthlySubmissionLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "showBlacklistKeywords": { + "name": "showBlacklistKeywords", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "hideStudentInfo": { + "name": "hideStudentInfo", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "smtpEnabled": { + "name": "smtpEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "smtpHost": { + "name": "smtpHost", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "smtpPort": { + "name": "smtpPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 587 + }, + "smtpSecure": { + "name": "smtpSecure", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "smtpUsername": { + "name": "smtpUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "smtpPassword": { + "name": "smtpPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "smtpFromEmail": { + "name": "smtpFromEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "smtpFromName": { + "name": "smtpFromName", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'校园广播站'" + }, + "enableRequestTimeLimitation": { + "name": "enableRequestTimeLimitation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "forceBlockAllRequests": { + "name": "forceBlockAllRequests", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableReplayRequests": { + "name": "enableReplayRequests", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableCollaborativeSubmission": { + "name": "enableCollaborativeSubmission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enableSubmissionRemarks": { + "name": "enableSubmissionRemarks", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionNoteRequiresApproval": { + "name": "submissionNoteRequiresApproval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "instanceId": { + "name": "instanceId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telemetryEnabled": { + "name": "telemetryEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "showBeianIcon": { + "name": "showBeianIcon", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "scheduleDaysDisplay": { + "name": "scheduleDaysDisplay", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 7 + }, + "scheduleDaysEditable": { + "name": "scheduleDaysEditable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "scheduleDaysRequestable": { + "name": "scheduleDaysRequestable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 14 + }, + "scheduleDaysBeforeEnabled": { + "name": "scheduleDaysBeforeEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "scheduleDaysBefore": { + "name": "scheduleDaysBefore", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "scheduleDaysAfterEnabled": { + "name": "scheduleDaysAfterEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "scheduleDaysAfter": { + "name": "scheduleDaysAfter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "forcePasswordChangeOnFirstLogin": { + "name": "forcePasswordChangeOnFirstLogin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableSubmissionRestriction": { + "name": "enableSubmissionRestriction", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionRestrictionScope": { + "name": "submissionRestrictionScope", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'all'" + }, + "sameSongRestrictionHours": { + "name": "sameSongRestrictionHours", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sameArtistRestrictionHours": { + "name": "sameArtistRestrictionHours", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cardCodeEnabled": { + "name": "cardCodeEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cardCodeSubmissionRequired": { + "name": "cardCodeSubmissionRequired", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cardCodeVoteEnabled": { + "name": "cardCodeVoteEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cardCodeReplayEnabled": { + "name": "cardCodeReplayEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableCardCodeRequests": { + "name": "enableCardCodeRequests", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "requireCardCodeForRequests": { + "name": "requireCardCodeForRequests", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableCardCodeLimitBypass": { + "name": "enableCardCodeLimitBypass", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionRestrictionEnabled": { + "name": "submissionRestrictionEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionRestrictionGradeEnabled": { + "name": "submissionRestrictionGradeEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionRestrictionClassEnabled": { + "name": "submissionRestrictionClassEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionRestrictionGraduateEnabled": { + "name": "submissionRestrictionGraduateEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "submissionRestrictionWithdrawnEnabled": { + "name": "submissionRestrictionWithdrawnEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "captchaProvider": { + "name": "captchaProvider", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'TURNSTILE'" + }, + "captchaEnabled": { + "name": "captchaEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "turnstileSiteKey": { + "name": "turnstileSiteKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "turnstileSecretKey": { + "name": "turnstileSecretKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowRegister": { + "name": "allowRegister", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "registerRequireEmail": { + "name": "registerRequireEmail", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "registerRequireEmailVerify": { + "name": "registerRequireEmailVerify", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "registerDefaultRole": { + "name": "registerDefaultRole", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'USER'" + }, + "registerEnabledGradeClasses": { + "name": "registerEnabledGradeClasses", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registerRequiresApproval": { + "name": "registerRequiresApproval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "oauthRegisterRequiresApproval": { + "name": "oauthRegisterRequiresApproval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "registerEmailRequired": { + "name": "registerEmailRequired", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "registerRequiresGradeClass": { + "name": "registerRequiresGradeClass", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "oauthEnabled": { + "name": "oauthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "oauthAllowRegister": { + "name": "oauthAllowRegister", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "oauthAllowLogin": { + "name": "oauthAllowLogin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "oauthAllowBind": { + "name": "oauthAllowBind", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "allowOAuthRegistration": { + "name": "allowOAuthRegistration", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "oauthRedirectUri": { + "name": "oauthRedirectUri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauthStateSecret": { + "name": "oauthStateSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauthProviders": { + "name": "oauthProviders", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "githubOAuthEnabled": { + "name": "githubOAuthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "casdoorOAuthEnabled": { + "name": "casdoorOAuthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "casdoorServerUrl": { + "name": "casdoorServerUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "casdoorClientId": { + "name": "casdoorClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "casdoorClientSecret": { + "name": "casdoorClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "casdoorOrganizationName": { + "name": "casdoorOrganizationName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "googleOAuthEnabled": { + "name": "googleOAuthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "googleClientId": { + "name": "googleClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "googleClientSecret": { + "name": "googleClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aggregateOAuthEnabled": { + "name": "aggregateOAuthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "aggregateOAuthAppId": { + "name": "aggregateOAuthAppId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aggregateOAuthAppKey": { + "name": "aggregateOAuthAppKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aggregateOAuthLoginType": { + "name": "aggregateOAuthLoginType", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'qq'" + }, + "aggregateOAuthEndpoint": { + "name": "aggregateOAuthEndpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthEnabled": { + "name": "customOAuthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "customOAuthDisplayName": { + "name": "customOAuthDisplayName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthAuthorizeUrl": { + "name": "customOAuthAuthorizeUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthTokenUrl": { + "name": "customOAuthTokenUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthUserInfoUrl": { + "name": "customOAuthUserInfoUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthScope": { + "name": "customOAuthScope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthClientId": { + "name": "customOAuthClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthClientSecret": { + "name": "customOAuthClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthUserIdField": { + "name": "customOAuthUserIdField", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthUsernameField": { + "name": "customOAuthUsernameField", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthNameField": { + "name": "customOAuthNameField", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthEmailField": { + "name": "customOAuthEmailField", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customOAuthAvatarField": { + "name": "customOAuthAvatarField", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "captchaMaxFailures": { + "name": "captchaMaxFailures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "autoBackupEnabled": { + "name": "autoBackupEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "autoBackupIntervalHours": { + "name": "autoBackupIntervalHours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 24 + }, + "autoBackupRetentionDays": { + "name": "autoBackupRetentionDays", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 30 + }, + "autoBackupConfig": { + "name": "autoBackupConfig", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "statisticsCode": { + "name": "statisticsCode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "statisticsCodeEnabled": { + "name": "statisticsCodeEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "defaultTheme": { + "name": "defaultTheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'System'" + }, + "enabledThemes": { + "name": "enabledThemes", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'[\"System\",\"ClassicDark\",\"ClassicLight\",\"ModernLight\"]'" + }, + "enabledPlatforms": { + "name": "enabledPlatforms", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "platformOrder": { + "name": "platformOrder", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.UserIdentity": { + "name": "UserIdentity", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerUserId": { + "name": "providerUserId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerUsername": { + "name": "providerUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "UserIdentity_userId_User_id_fk": { + "name": "UserIdentity_userId_User_id_fk", + "tableFrom": "UserIdentity", + "tableTo": "User", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "UserIdentity_provider_providerUserId_unique": { + "name": "UserIdentity_provider_providerUserId_unique", + "nullsNotDistinct": false, + "columns": [ + "provider", + "providerUserId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_passkeys": { + "name": "user_passkeys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_device_type": { + "name": "credential_device_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_backed_up": { + "name": "credential_backed_up", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_passkeys_user_id_idx": { + "name": "user_passkeys_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_passkeys_user_id_User_id_fk": { + "name": "user_passkeys_user_id_User_id_fk", + "tableFrom": "user_passkeys", + "tableTo": "User", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_status_logs": { + "name": "user_status_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "old_status": { + "name": "old_status", + "type": "user_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "new_status": { + "name": "new_status", + "type": "user_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "operator_id": { + "name": "operator_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.User": { + "name": "User", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "grade": { + "name": "grade", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "class": { + "name": "class", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "studentId": { + "name": "studentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'USER'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "lastLogin": { + "name": "lastLogin", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "lastLoginIp": { + "name": "lastLoginIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "passwordChangedAt": { + "name": "passwordChangedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "forcePasswordChange": { + "name": "forcePasswordChange", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meowNickname": { + "name": "meowNickname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meowBoundAt": { + "name": "meowBoundAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "user_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "statusChangedAt": { + "name": "statusChangedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "statusChangedBy": { + "name": "statusChangedBy", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "tokenVersion": { + "name": "tokenVersion", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "avatarProvider": { + "name": "avatarProvider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "avatarProviderUserId": { + "name": "avatarProviderUserId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "remark": { + "name": "remark", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "User_username_unique": { + "name": "User_username_unique", + "columns": [ + { + "expression": "username", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Vote": { + "name": "Vote", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "songId": { + "name": "songId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "vote_user_song_idx": { + "name": "vote_user_song_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "songId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "vote_song_user_unique": { + "name": "vote_song_user_unique", + "nullsNotDistinct": false, + "columns": [ + "songId", + "userId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.BlacklistType": { + "name": "BlacklistType", + "schema": "public", + "values": [ + "SONG", + "KEYWORD", + "LANGUAGE", + "GENRE" + ] + }, + "public.card_code_status": { + "name": "card_code_status", + "schema": "public", + "values": [ + "AVAILABLE", + "LOCKED", + "REDEEMED", + "INVALID" + ] + }, + "public.collaborator_status": { + "name": "collaborator_status", + "schema": "public", + "values": [ + "PENDING", + "ACCEPTED", + "REJECTED" + ] + }, + "public.replay_request_status": { + "name": "replay_request_status", + "schema": "public", + "values": [ + "PENDING", + "FULFILLED", + "REJECTED" + ] + }, + "public.user_status": { + "name": "user_status", + "schema": "public", + "values": [ + "active", + "withdrawn", + "graduate", + "pending", + "rejected" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/app/drizzle/migrations/meta/_journal.json b/app/drizzle/migrations/meta/_journal.json index fd5d1f7..654606c 100644 --- a/app/drizzle/migrations/meta/_journal.json +++ b/app/drizzle/migrations/meta/_journal.json @@ -141,6 +141,13 @@ "when": 1776518400000, "tag": "20260418112000_add_song_comments", "breakpoints": true + }, + { + "idx": 20, + "version": "7", + "when": 1788684403309, + "tag": "20260906084643_auto-migration", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/app/drizzle/schema.ts b/app/drizzle/schema.ts index f705696..eb7b324 100644 --- a/app/drizzle/schema.ts +++ b/app/drizzle/schema.ts @@ -51,9 +51,16 @@ export const authSessions = pgTable('auth_sessions', { userAgent: text('user_agent'), lastActiveAt: timestamp('last_active_at', { withTimezone: true }).defaultNow().notNull(), isRevoked: boolean('is_revoked').default(false).notNull(), + browser: text('browser'), + operatingSystem: text('operating_system'), + device: text('device'), + loginMethod: text('login_method').default('password').notNull(), + revokedAt: timestamp('revoked_at', { withTimezone: true }), + revokedReason: text('revoked_reason') }, (table) => [ - index('auth_sessions_user_id_idx').on(table.userId), + index('auth_sessions_user_active_idx').on(table.userId, table.isRevoked, table.expiresAt), index('auth_sessions_expires_at_idx').on(table.expiresAt), + index('auth_sessions_last_active_idx').on(table.lastActiveAt), uniqueIndex('auth_sessions_session_token_unique').on(table.sessionToken), ]); @@ -258,16 +265,29 @@ export const systemSettings = pgTable('SystemSettings', { enableReplayRequests: boolean('enableReplayRequests').default(false).notNull(), enableCollaborativeSubmission: boolean('enableCollaborativeSubmission').default(true).notNull(), enableSubmissionRemarks: boolean('enableSubmissionRemarks').default(false).notNull(), + submissionNoteRequiresApproval: boolean('submissionNoteRequiresApproval').default(false).notNull(), instanceId: text('instanceId'), telemetryEnabled: boolean('telemetryEnabled').default(true).notNull(), showBeianIcon: boolean('showBeianIcon').default(true).notNull(), scheduleDaysDisplay: integer('scheduleDaysDisplay').default(7).notNull(), scheduleDaysEditable: integer('scheduleDaysEditable').default(3).notNull(), scheduleDaysRequestable: integer('scheduleDaysRequestable').default(14).notNull(), + scheduleDaysBeforeEnabled: boolean('scheduleDaysBeforeEnabled').default(false).notNull(), + scheduleDaysBefore: integer('scheduleDaysBefore').default(1).notNull(), + scheduleDaysAfterEnabled: boolean('scheduleDaysAfterEnabled').default(false).notNull(), + scheduleDaysAfter: integer('scheduleDaysAfter').default(1).notNull(), + forcePasswordChangeOnFirstLogin: boolean('forcePasswordChangeOnFirstLogin').default(false).notNull(), + enableSubmissionRestriction: boolean('enableSubmissionRestriction').default(false).notNull(), + submissionRestrictionScope: text('submissionRestrictionScope').default('all').notNull(), + sameSongRestrictionHours: integer('sameSongRestrictionHours'), + sameArtistRestrictionHours: integer('sameArtistRestrictionHours'), cardCodeEnabled: boolean('cardCodeEnabled').default(false).notNull(), cardCodeSubmissionRequired: boolean('cardCodeSubmissionRequired').default(false).notNull(), cardCodeVoteEnabled: boolean('cardCodeVoteEnabled').default(false).notNull(), cardCodeReplayEnabled: boolean('cardCodeReplayEnabled').default(false).notNull(), + enableCardCodeRequests: boolean('enableCardCodeRequests').default(false).notNull(), + requireCardCodeForRequests: boolean('requireCardCodeForRequests').default(false).notNull(), + enableCardCodeLimitBypass: boolean('enableCardCodeLimitBypass').default(false).notNull(), submissionRestrictionEnabled: boolean('submissionRestrictionEnabled').default(false).notNull(), submissionRestrictionGradeEnabled: boolean('submissionRestrictionGradeEnabled').default(false).notNull(), submissionRestrictionClassEnabled: boolean('submissionRestrictionClassEnabled').default(false).notNull(), @@ -282,16 +302,56 @@ export const systemSettings = pgTable('SystemSettings', { registerRequireEmailVerify: boolean('registerRequireEmailVerify').default(false).notNull(), registerDefaultRole: text('registerDefaultRole').default('USER'), registerEnabledGradeClasses: text('registerEnabledGradeClasses'), + registerRequiresApproval: boolean('registerRequiresApproval').default(false).notNull(), + oauthRegisterRequiresApproval: boolean('oauthRegisterRequiresApproval').default(false).notNull(), + registerEmailRequired: boolean('registerEmailRequired').default(false).notNull(), + registerRequiresGradeClass: boolean('registerRequiresGradeClass').default(false).notNull(), oauthEnabled: boolean('oauthEnabled').default(false).notNull(), oauthAllowRegister: boolean('oauthAllowRegister').default(true).notNull(), oauthAllowLogin: boolean('oauthAllowLogin').default(true).notNull(), oauthAllowBind: boolean('oauthAllowBind').default(true).notNull(), + allowOAuthRegistration: boolean('allowOAuthRegistration').default(false).notNull(), + oauthRedirectUri: text('oauthRedirectUri'), + oauthStateSecret: text('oauthStateSecret'), + oauthProviders: text('oauthProviders').default('[]'), + githubOAuthEnabled: boolean('githubOAuthEnabled').default(false).notNull(), + githubClientId: text('githubClientId'), + githubClientSecret: text('githubClientSecret'), + casdoorOAuthEnabled: boolean('casdoorOAuthEnabled').default(false).notNull(), + casdoorServerUrl: text('casdoorServerUrl'), + casdoorClientId: text('casdoorClientId'), + casdoorClientSecret: text('casdoorClientSecret'), + casdoorOrganizationName: text('casdoorOrganizationName'), + googleOAuthEnabled: boolean('googleOAuthEnabled').default(false).notNull(), + googleClientId: text('googleClientId'), + googleClientSecret: text('googleClientSecret'), + aggregateOAuthEnabled: boolean('aggregateOAuthEnabled').default(false).notNull(), + aggregateOAuthAppId: text('aggregateOAuthAppId'), + aggregateOAuthAppKey: text('aggregateOAuthAppKey'), + aggregateOAuthLoginType: text('aggregateOAuthLoginType').default('qq'), + aggregateOAuthEndpoint: text('aggregateOAuthEndpoint'), + customOAuthEnabled: boolean('customOAuthEnabled').default(false).notNull(), + customOAuthDisplayName: text('customOAuthDisplayName'), + customOAuthAuthorizeUrl: text('customOAuthAuthorizeUrl'), + customOAuthTokenUrl: text('customOAuthTokenUrl'), + customOAuthUserInfoUrl: text('customOAuthUserInfoUrl'), + customOAuthScope: text('customOAuthScope'), + customOAuthClientId: text('customOAuthClientId'), + customOAuthClientSecret: text('customOAuthClientSecret'), + customOAuthUserIdField: text('customOAuthUserIdField'), + customOAuthUsernameField: text('customOAuthUsernameField'), + customOAuthNameField: text('customOAuthNameField'), + customOAuthEmailField: text('customOAuthEmailField'), + customOAuthAvatarField: text('customOAuthAvatarField'), + captchaMaxFailures: integer('captchaMaxFailures').default(3).notNull(), autoBackupEnabled: boolean('autoBackupEnabled').default(false).notNull(), autoBackupIntervalHours: integer('autoBackupIntervalHours').default(24).notNull(), autoBackupRetentionDays: integer('autoBackupRetentionDays').default(30).notNull(), + autoBackupConfig: text('autoBackupConfig'), statisticsCode: text('statisticsCode'), - defaultTheme: text('defaultTheme').default('light'), - enabledThemes: text('enabledThemes').default('light,dark'), + statisticsCodeEnabled: boolean('statisticsCodeEnabled').default(false).notNull(), + defaultTheme: text('defaultTheme').default('System').notNull(), + enabledThemes: text('enabledThemes').default('[\"System\",\"ClassicDark\",\"ClassicLight\",\"ModernLight\"]').notNull(), enabledPlatforms: text('enabledPlatforms'), platformOrder: text('platformOrder'), }); diff --git a/app/plugins/sentry.client.ts b/app/plugins/sentry.client.ts new file mode 100644 index 0000000..5217478 --- /dev/null +++ b/app/plugins/sentry.client.ts @@ -0,0 +1,29 @@ +import * as Sentry from '@sentry/vue' + +export default defineNuxtPlugin((nuxtApp) => { + const config = useRuntimeConfig() + const dsn = config.public.sentry?.dsn + + if (!dsn) return + + const app = nuxtApp.vueApp + const router = nuxtApp.$router + + Sentry.init({ + app, + dsn, + environment: config.sentry?.environment || 'production', + release: config.sentry?.release || undefined, + tracesSampleRate: config.public.sentry?.tracesSampleRate ?? 1.0, + integrations: router + ? [ + Sentry.browserTracingIntegration({ router }), + Sentry.replayIntegration() + ] + : [ + Sentry.replayIntegration() + ], + replaysSessionSampleRate: config.public.sentry?.replaySessionSampleRate ?? 0, + replaysOnErrorSampleRate: config.public.sentry?.replayOnErrorSampleRate ?? 0 + }) +}) diff --git a/app/utils/password-policy.ts b/app/utils/password-policy.ts new file mode 100644 index 0000000..f84c3d4 --- /dev/null +++ b/app/utils/password-policy.ts @@ -0,0 +1,2 @@ +export const PASSWORD_MIN_LENGTH = 6 +export const PASSWORD_MAX_LENGTH = 64 diff --git a/nuxt.config.ts b/nuxt.config.ts index a141ae2..c20d613 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -40,11 +40,51 @@ export default defineNuxtConfig({ }, modules: [ '@nuxtjs/tailwindcss', - ...(process.env.NODE_ENV === 'development' || process.env.npm_lifecycle_event?.includes('lint') + ...((process.env.NODE_ENV === 'development' || process.env.npm_lifecycle_event?.includes('lint')) ? ['@nuxt/eslint'] + : []), + ...((process.env.PWA_ENABLED || 'false') === 'true' + ? ['@vite-pwa/nuxt'] : []) ], + pwa: (process.env.PWA_ENABLED || 'false') === 'true' + ? { + registerType: 'autoUpdate', + manifest: { + name: process.env.NUXT_PUBLIC_SITE_TITLE || '校园广播站点歌系统', + short_name: process.env.NUXT_PUBLIC_SITE_TITLE || 'VoiceHub', + description: process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '校园广播站点歌系统', + display: (process.env.PWA_DISPLAY as any) || 'standalone', + background_color: process.env.PWA_BACKGROUND_COLOR || '#000000', + theme_color: process.env.PWA_THEME_COLOR || '#111111', + icons: [ + { + src: '/images/logo.png', + sizes: '192x192', + type: 'image/png' + }, + { + src: '/images/logo.png', + sizes: '512x512', + type: 'image/png' + } + ] + }, + workbox: { + navigateFallback: '/', + globPatterns: ['**/*.{js,css,html,png,jpg,jpeg,svg,ico,webp,woff2}'] + }, + client: { + installPrompt: true, + periodicSyncForUpdates: 3600 + }, + devOptions: { + enabled: process.env.NODE_ENV === 'development' + } + } + : {}, + // 引入全局CSS css: [ '~/assets/css/variables.css', @@ -150,6 +190,10 @@ export default defineNuxtConfig({ }, // 移动端优化 { name: 'theme-color', content: '#111111' }, + { + name: 'x-default-theme', + content: process.env.NUXT_PUBLIC_DEFAULT_THEME || 'System' + }, { name: 'apple-mobile-web-app-capable', content: 'yes' }, { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }, { name: 'apple-mobile-web-app-title', content: 'VoiceHub管理' }, @@ -162,22 +206,25 @@ export default defineNuxtConfig({ tagPosition: 'head', children: [ `(function(){try{`, - ` var k='voicehub:theme', d=document, r=d.documentElement, s=null;`, + ` var k='voicehub:theme', d=document, r=d.documentElement, s=null, eff=null;`, ` try{s=localStorage.getItem(k)}catch(e){s=null}`, ` if(!s){`, ` try{`, ` var meta=document.querySelector('meta[name="x-default-theme"]');`, ` if(meta && meta.content){s=meta.content}`, ` }catch(e){s=null}`, - ` if(!s){s=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}`, + ` if(!s){s='System'}`, ` }`, - ` r.setAttribute('data-theme', s);`, - ` if(s==='dark'){r.classList.add('dark'); r.style.colorScheme='dark'}`, - ` else if(s==='light'){r.classList.add('light'); r.style.colorScheme='light'}`, - ` else{r.style.colorScheme='light dark'}`, + ` if(s==='System'||s==='system'){eff=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}`, + ` else if(typeof s==='string'){eff=s.endsWith('Dark')||s==='dark'?'dark':(s.endsWith('Light')||s==='light'?'light':s)}`, + ` else{eff='dark'}`, + ` r.setAttribute('data-theme', (typeof s==='string'?s:eff));`, + ` if(eff==='dark'){r.classList.add('dark'); r.classList.remove('light'); r.style.colorScheme='dark'}`, + ` else if(eff==='light'){r.classList.add('light'); r.classList.remove('dark'); r.style.colorScheme='light'}`, + ` else{r.classList.remove('dark','light'); r.style.colorScheme='light dark'}`, ` try{`, ` var tm=d.querySelector('meta[name="theme-color"]');`, - ` if(tm){tm.content=(s==='light'?'#f8fafc':'#111111')}`, + ` if(tm){tm.content=(eff==='light'?'#f8fafc':'#111111')}`, ` }catch(e){}`, `}catch(e){}})();` ].join('') diff --git a/package-lock.json b/package-lock.json index e58e6e4..6453acf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,8 @@ "@pixi/filter-bulge-pinch": "^5.1.1", "@pixi/filter-color-matrix": "^7.4.3", "@pixi/sprite": "^7.4.3", + "@sentry/node": "^10.73.0", + "@sentry/vue": "^10.73.0", "@simplewebauthn/browser": "^13.3.0", "@simplewebauthn/server": "^13.3.3", "@types/crypto-js": "^4.2.2", @@ -35,6 +37,7 @@ "@types/pg": "^8.20.0", "@ungap/structured-clone": "^1.3.0", "@vercel/speed-insights": "^1.3.1", + "@vite-pwa/nuxt": "^1.1.1", "axios": "^1.20.0", "bcryptjs": "^2.4.3", "bezier-easing": "^2.1.0", @@ -77,6 +80,7 @@ "zod": "^4.5.4" }, "devDependencies": { + "@clack/prompts": "^1.1.0", "@nuxt/eslint": "^1.17.0", "eslint": "^9.39.5", "prettier": "^3.9.6", @@ -420,6 +424,7 @@ "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.7.tgz", "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -537,6 +542,48 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/helper-globals": { "version": "7.29.7", "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz", @@ -610,6 +657,23 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-replace-supers": { "version": "7.29.7", "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", @@ -667,6 +731,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helpers": { "version": "7.29.7", "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.7.tgz", @@ -695,6 +773,143 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.29.7", "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", @@ -715,6 +930,765 @@ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.8", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz", + "integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.8", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.8.tgz", + "integrity": "sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.8", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.8.tgz", + "integrity": "sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, @@ -744,6 +1718,177 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmmirror.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/runtime": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", @@ -805,31 +1950,24 @@ "license": "LGPL-3.0" }, "node_modules/@clack/core": { - "version": "1.4.3", - "resolved": "https://registry.npmmirror.com/@clack/core/-/core-1.4.3.tgz", - "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@clack/core/-/core-1.1.0.tgz", + "integrity": "sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==", + "dev": true, "license": "MIT", "dependencies": { - "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" } }, "node_modules/@clack/prompts": { - "version": "1.7.0", - "resolved": "https://registry.npmmirror.com/@clack/prompts/-/prompts-1.7.0.tgz", - "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@clack/prompts/-/prompts-1.1.0.tgz", + "integrity": "sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==", + "dev": true, "license": "MIT", "dependencies": { - "@clack/core": "1.4.3", - "fast-string-width": "^3.0.2", - "fast-wrap-ansi": "^0.2.0", + "@clack/core": "1.1.0", "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" } }, "node_modules/@cloudflare/kv-asset-handler": { @@ -971,6 +2109,17 @@ "integrity": "sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==", "license": "MIT" }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.91.0", "resolved": "https://registry.npmmirror.com/@es-joy/jsdoccomment/-/jsdoccomment-0.91.0.tgz", @@ -1839,7 +2988,7 @@ "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -1858,7 +3007,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1871,7 +3020,7 @@ "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1915,7 +3064,7 @@ "version": "0.21.2", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", @@ -1930,14 +3079,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1948,7 +3097,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -1961,7 +3110,7 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0" @@ -2032,7 +3181,7 @@ "version": "0.17.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -2066,7 +3215,7 @@ "version": "3.3.7", "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ajv": "^6.14.0", @@ -2090,14 +3239,14 @@ "version": "1.0.2", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.18", "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.18.tgz", "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2108,7 +3257,7 @@ "version": "14.0.0", "resolved": "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -2121,7 +3270,7 @@ "version": "3.1.5", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -2134,7 +3283,7 @@ "version": "9.39.5", "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.5.tgz", "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2147,7 +3296,7 @@ "version": "2.1.7", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2157,7 +3306,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0", @@ -2177,7 +3326,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -2187,7 +3336,7 @@ "version": "0.16.7", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -2201,7 +3350,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -2215,7 +3364,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -2686,11 +3835,40 @@ } } }, + "node_modules/@nuxt/cli/node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://registry.npmmirror.com/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@nuxt/cli/node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, "node_modules/@nuxt/cli/node_modules/citty": { "version": "0.2.2", "resolved": "https://registry.npmmirror.com/citty/-/citty-0.2.2.tgz", "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@nuxt/devalue": { "version": "2.0.2", @@ -2783,6 +3961,34 @@ "devtools-wizard": "cli.mjs" } }, + "node_modules/@nuxt/devtools-wizard/node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://registry.npmmirror.com/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@nuxt/devtools-wizard/node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, "node_modules/@nuxt/devtools/node_modules/isexe": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/isexe/-/isexe-4.0.0.tgz", @@ -2881,6 +4087,36 @@ } } }, + "node_modules/@nuxt/eslint-config/node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://registry.npmmirror.com/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@nuxt/eslint-config/node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, "node_modules/@nuxt/eslint-config/node_modules/@eslint/js": { "version": "10.0.1", "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-10.0.1.tgz", @@ -3002,6 +4238,7 @@ "resolved": "https://registry.npmmirror.com/@nuxt/kit/-/kit-4.5.2.tgz", "integrity": "sha512-l66LU9DcJYjmNwqwAj2I5UGRrUbnG2DOKGChnN70zIGtn0eq/z87gi/FRgha6eMb9/FmB1PFHgtx6PWVml1C2Q==", "license": "MIT", + "peer": true, "dependencies": { "c12": "^3.3.4", "consola": "^3.4.2", @@ -3163,6 +4400,7 @@ "resolved": "https://registry.npmmirror.com/@nuxt/schema/-/schema-4.5.2.tgz", "integrity": "sha512-h9g1kt9O2iU9nX6HDFu9gvwtpn+8oSJX0RSTWRBnEx/Pkz+WlOHtjuS0SbkTAXw5aT1+H1GysWVwNTjJfBY/0w==", "license": "MIT", + "peer": true, "dependencies": { "@vue/shared": "^3.5.40", "defu": "^6.1.7", @@ -3341,6 +4579,123 @@ "node": ">= 4" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", + "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.11.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.11.0.tgz", + "integrity": "sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/instrumentation/-/instrumentation-0.220.0.tgz", + "integrity": "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "import-in-the-middle": "^3.0.0", + "require-in-the-middle": "^8.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.11.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.11.0.tgz", + "integrity": "sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.11.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.11.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace/-/sdk-trace-2.11.0.tgz", + "integrity": "sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.11.0", + "@opentelemetry/resources": "2.11.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.11.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.11.0.tgz", + "integrity": "sha512-H19x/TX/LZdqiYOjM7fqtSxwlplC5pgelavqbQdHbhdq0q/AI/TGkM2dfGuuynTXmJPeF2HoZVoPDu+TGoW78A==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@opentelemetry/core": "2.11.0", + "@opentelemetry/resources": "2.11.0", + "@opentelemetry/sdk-trace": "2.11.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@otplib/core": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/core/-/core-12.0.1.tgz", @@ -3396,6 +4751,7 @@ "resolved": "https://registry.npmmirror.com/@oxc-project/types/-/types-0.148.0.tgz", "integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/oxc-project" } @@ -3409,41 +4765,6 @@ "@noble/hashes": "^1.1.5" } }, - "node_modules/@parcel/watcher": { - "version": "2.6.0", - "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.6.0.tgz", - "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.6.0", - "@parcel/watcher-darwin-arm64": "2.6.0", - "@parcel/watcher-darwin-x64": "2.6.0", - "@parcel/watcher-freebsd-x64": "2.6.0", - "@parcel/watcher-linux-arm-glibc": "2.6.0", - "@parcel/watcher-linux-arm-musl": "2.6.0", - "@parcel/watcher-linux-arm64-glibc": "2.6.0", - "@parcel/watcher-linux-arm64-musl": "2.6.0", - "@parcel/watcher-linux-x64-glibc": "2.6.0", - "@parcel/watcher-linux-x64-musl": "2.6.0", - "@parcel/watcher-win32-arm64": "2.6.0", - "@parcel/watcher-win32-x64": "2.6.0" - } - }, "node_modules/@parcel/watcher-android-arm64": { "version": "2.6.0", "resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", @@ -3874,6 +5195,7 @@ "resolved": "https://registry.npmjs.org/@pixi/app/-/app-7.4.3.tgz", "integrity": "sha512-opyWMuO0Ir8pf1DYUR++wAA6ZfNU+nIX2z95R2OD172HbcdhB4/HD7leLIIAny/LciEdMqlWEBhXK7N93YWbdg==", "license": "MIT", + "peer": true, "peerDependencies": { "@pixi/core": "7.4.3", "@pixi/display": "7.4.3" @@ -3905,6 +5227,7 @@ "resolved": "https://registry.npmjs.org/@pixi/core/-/core-7.4.3.tgz", "integrity": "sha512-5YDs11faWgVVTL8VZtLU05/Fl47vaP5Tnsbf+y/WRR0VSW3KhRRGTBU1J3Gdc2xEWbJhUK07KGP7eSZpvtPVgA==", "license": "MIT", + "peer": true, "dependencies": { "@pixi/color": "7.4.3", "@pixi/constants": "7.4.3", @@ -3925,6 +5248,7 @@ "resolved": "https://registry.npmjs.org/@pixi/display/-/display-7.4.3.tgz", "integrity": "sha512-b5m2dAaoNAVdxz1oDaxl3XZ059NEOcNtGkxTOZ4EYCw/jcp9sZXkgSROHRzsGn4k+NugH7+9MP4Id2Z0kkdUhw==", "license": "MIT", + "peer": true, "peerDependencies": { "@pixi/core": "7.4.3" } @@ -3940,6 +5264,7 @@ "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-7.4.3.tgz", "integrity": "sha512-ZFzS9L/whdRbs5A/EUgF3yQaBcxNarmbuwaMgrfnpQ84mRczkGByqDLGToadiufyals07ufTrXBGRle9lbtEDA==", "license": "MIT", + "peer": true, "peerDependencies": { "@pixi/core": "7.4.3" } @@ -3949,6 +5274,7 @@ "resolved": "https://registry.npmjs.org/@pixi/filter-bulge-pinch/-/filter-bulge-pinch-5.1.1.tgz", "integrity": "sha512-80I3g813td7Fnzi7IJSiR3z8gZlKblk6WN+5z6WnscQROcNEpck6lgWS/Lf/IdeHB/FtUKJCbx7RzxkUhiRTvA==", "license": "MIT", + "peer": true, "peerDependencies": { "@pixi/core": "^7.0.0-X" } @@ -3958,6 +5284,7 @@ "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-7.4.3.tgz", "integrity": "sha512-TNu0h20SrzjUWIb5v19dAp1vPpqtG0w2XF9kIHN91bMNaf3R1jzhpWG6TtaVO9eo1IolWcEJLw38jIohyC+KNw==", "license": "MIT", + "peer": true, "peerDependencies": { "@pixi/core": "7.4.3" } @@ -3990,6 +5317,7 @@ "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-7.4.3.tgz", "integrity": "sha512-iNBrpOFF9nXDT6m2jcyYy6l/sRzklLDDck1eFHprHZwvNquY2nzRfh+RGBCecxhBcijiLJ3fsZN33fP0LDXkvw==", "license": "MIT", + "peer": true, "peerDependencies": { "@pixi/core": "7.4.3", "@pixi/display": "7.4.3" @@ -4089,6 +5417,7 @@ "resolved": "https://registry.npmmirror.com/@redis/client/-/client-5.12.1.tgz", "integrity": "sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==", "license": "MIT", + "peer": true, "dependencies": { "cluster-key-slot": "1.1.2" }, @@ -4416,6 +5745,32 @@ } } }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-commonjs": { "version": "29.0.3", "resolved": "https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.3.tgz", @@ -4915,6 +6270,212 @@ "win32" ] }, + "node_modules/@sentry/browser": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/browser/-/browser-10.73.0.tgz", + "integrity": "sha512-HqTe1S5RrWLufhX2LaFP3yNoMxfNDroh120bq1zdGHZfFDBMJQ0CDXxHO+L4UJfQ5dWdCCzWbXIAiZuWGa/DFQ==", + "license": "MIT", + "dependencies": { + "@sentry/browser-utils": "10.73.0", + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0", + "@sentry/feedback": "10.73.0", + "@sentry/replay": "10.73.0", + "@sentry/replay-canvas": "10.73.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/browser-utils": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/browser-utils/-/browser-utils-10.73.0.tgz", + "integrity": "sha512-qQygxJZ+RV779+iL1+lrJ4f4sZLgbgW0/JWPNp0YlcEAE62yCsdKbqoTEjB/EugdS4mSjBMX0chZC6rblu2Ycw==", + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/conventions": { + "version": "0.16.0", + "resolved": "https://registry.npmmirror.com/@sentry/conventions/-/conventions-0.16.0.tgz", + "integrity": "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@sentry/core": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/core/-/core-10.73.0.tgz", + "integrity": "sha512-FLO1UgH19RyasVpofu612WCOgb2nEH0dZy+R72d7p65XU9i0wxlMKm3+sgfwKmiSJp1Qhilaaxs4Jg6BbiM5HA==", + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/feedback": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/feedback/-/feedback-10.73.0.tgz", + "integrity": "sha512-D6nSngX+e46Mae2/oh2bxBvxNK1z2NERbuMAhB5sx9x4xMBWIyGnYYTECehvEqV9+AqGAgxxhOZoYIG3AmRwww==", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.73.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/node/-/node-10.73.0.tgz", + "integrity": "sha512-jiMJ6GgXDw6UMGzJY+o0c8OoeA9OfHqZ/xEpHfDqy75hn+9CEkRkbNGCIdMvsc7wW/Se1Os394hHfTpU+YEskg==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/instrumentation": "^0.220.0", + "@opentelemetry/sdk-trace-base": "^2.9.0", + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0", + "@sentry/node-core": "10.73.0", + "@sentry/opentelemetry": "10.73.0", + "@sentry/server-utils": "10.73.0", + "import-in-the-middle": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node-core": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/node-core/-/node-core-10.73.0.tgz", + "integrity": "sha512-GHAGUmZPmm6FKfxfv2maVVJ/A99YAmd7oFOuKMDmITI6O/Msl6JB3vPTEpopVAHLW0LYJQBOjddL9C7o+Jt44g==", + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0", + "@sentry/opentelemetry": "10.73.0", + "import-in-the-middle": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", + "@opentelemetry/instrumentation": ">=0.57.1 <1", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@opentelemetry/core": { + "optional": true + }, + "@opentelemetry/exporter-trace-otlp-http": { + "optional": true + }, + "@opentelemetry/instrumentation": { + "optional": true + }, + "@opentelemetry/sdk-trace-base": { + "optional": true + } + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/opentelemetry/-/opentelemetry-10.73.0.tgz", + "integrity": "sha512-fQouPQKsH0CQrw6oAn1k0Z2I+tgyochCovifr5qNS69i0OzjknLa03WJyiZ/IuzXc4AVa5jAKfOeE9slABz8Qw==", + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" + } + }, + "node_modules/@sentry/replay": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/replay/-/replay-10.73.0.tgz", + "integrity": "sha512-nN2wjN/Y0J5BOJV5hqRHUEBfxwUsipp1PKjcDHh6Fpxnrtfldu3Y99E8cQInseo5heFdzEvrOHBBrqWZXOHVKQ==", + "license": "MIT", + "dependencies": { + "@sentry/browser-utils": "10.73.0", + "@sentry/core": "10.73.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/replay-canvas": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/replay-canvas/-/replay-canvas-10.73.0.tgz", + "integrity": "sha512-sxa2lKkHPfF/j5xFpW7gocthWXRqyoHz8KCPy6yGc8plT477nl57iGSKhQDYsx1Ny10TLjs7YkIuPP1GY/Ax2Q==", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.73.0", + "@sentry/replay": "10.73.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/server-utils": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/server-utils/-/server-utils-10.73.0.tgz", + "integrity": "sha512-QskripdKFbM/+gipC6mpa2crLwL7+VbkX84IpHg2z9UlYQ1kNKd3aMT+Qk9NLRSw/zu1rSIAvlbWfx4D3rgNAA==", + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/vue": { + "version": "10.73.0", + "resolved": "https://registry.npmmirror.com/@sentry/vue/-/vue-10.73.0.tgz", + "integrity": "sha512-pbUt65YO7mcLT8q0geK62K4HxlKQkya3ZNqXo+BRz99uMvC78BdNSK+ME4jvTYeHwRJdLqQfAwrcXvKgAQlweg==", + "license": "MIT", + "dependencies": { + "@sentry/browser": "10.73.0", + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.73.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@tanstack/vue-router": "^1.64.0", + "pinia": "2.x || 3.x || 4.x", + "vue": "2.x || 3.x" + }, + "peerDependenciesMeta": { + "@tanstack/vue-router": { + "optional": true + }, + "pinia": { + "optional": true + } + } + }, "node_modules/@simple-git/args-pathspec": { "version": "1.0.3", "resolved": "https://registry.npmmirror.com/@simple-git/args-pathspec/-/args-pathspec-1.0.3.tgz", @@ -5011,6 +6572,7 @@ "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/types": "^8.56.0", @@ -5235,6 +6797,7 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz", "integrity": "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.8.0" } @@ -5254,6 +6817,21 @@ "integrity": "sha512-zeSORFArxqUwfVMTRHu8AN9k9LlfSn0CKDSzLhJDITpgLoS0xpnocxsgMjQjUcVYDgO47r9zLP49HEjH/iGsFg==", "license": "Apache-2.0" }, + "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { + "version": "3.0.0-pre1", + "resolved": "https://registry.npmmirror.com/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", + "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.10", + "json5": "^2.2.3", + "magic-string": "^0.30.21", + "string.prototype.matchall": "^4.0.12" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -5341,8 +6919,9 @@ "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" + "devOptional": true, + "license": "MIT", + "peer": true }, "node_modules/@types/jsonwebtoken": { "version": "9.0.10", @@ -5413,6 +6992,7 @@ "resolved": "https://registry.npmmirror.com/@types/pg/-/pg-8.20.0.tgz", "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -5467,8 +7047,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/@types/xml2js": { "version": "0.4.14", @@ -5524,6 +7103,7 @@ "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/types": "8.69.0", @@ -6232,6 +7812,82 @@ } } }, + "node_modules/@vite-pwa/nuxt": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@vite-pwa/nuxt/-/nuxt-1.1.1.tgz", + "integrity": "sha512-8RkdxNJ3NubtwmS96bPVvDclFmysH3VADKWqlaBaUu6PLsoHM3Wq7ThdYBsAT6EpqzWS+iFC2SF6lkJ4xDhKLA==", + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^3.9.0", + "pathe": "^1.1.1", + "ufo": "^1.3.2", + "vite-plugin-pwa": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/@vite-pwa/nuxt/node_modules/@nuxt/kit": { + "version": "3.21.11", + "resolved": "https://registry.npmmirror.com/@nuxt/kit/-/kit-3.21.11.tgz", + "integrity": "sha512-0Xi3tgwN77w43Q8GCPIrvWmF1J7Peehkts44E0uKNIml9lB8WoUn8YxyUjxBv47XtVR86NWoWALAT+/IEMHJEA==", + "license": "MIT", + "dependencies": { + "c12": "^3.3.4", + "consola": "^3.4.2", + "defu": "^6.1.7", + "destr": "^2.0.5", + "errx": "^0.1.2", + "exsolve": "^1.1.1", + "ignore": "^7.0.6", + "jiti": "^2.7.0", + "klona": "^2.0.6", + "knitwork": "^1.3.0", + "mlly": "^1.8.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.1", + "rc9": "^3.0.1", + "scule": "^1.3.0", + "semver": "^7.8.5", + "tinyglobby": "^0.2.17", + "ufo": "^1.6.4", + "unctx": "^2.5.0", + "untyped": "^2.0.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@vite-pwa/nuxt/node_modules/@nuxt/kit/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/@vite-pwa/nuxt/node_modules/ignore": { + "version": "7.0.8", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-7.0.8.tgz", + "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@vite-pwa/nuxt/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-vue": { "version": "6.0.8", "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz", @@ -6373,6 +8029,7 @@ "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.42.tgz", "integrity": "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.29.8", "@vue/compiler-core": "3.5.42", @@ -6534,6 +8191,7 @@ "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.18.0.tgz", "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6554,7 +8212,7 @@ "version": "5.3.2", "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -6582,7 +8240,7 @@ "version": "6.15.0", "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -6855,9 +8513,46 @@ "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, + "devOptional": true, "license": "Python-2.0" }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -6917,6 +8612,15 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/async-sema": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/async-sema/-/async-sema-3.1.1.tgz", @@ -6974,6 +8678,21 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axios": { "version": "1.20.0", "resolved": "https://registry.npmmirror.com/axios/-/axios-1.20.0.tgz", @@ -7025,6 +8744,54 @@ } } }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", @@ -7039,6 +8806,7 @@ "resolved": "https://registry.npmmirror.com/bare-events/-/bare-events-2.9.2.tgz", "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -7247,6 +9015,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.11.20", "caniuse-lite": "^1.0.30001810", @@ -7423,6 +9192,24 @@ "node": ">= 6.0.0" } }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -7456,7 +9243,7 @@ "version": "3.1.0", "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -7632,6 +9419,12 @@ "consola": "^3.2.3" } }, + "node_modules/cjs-module-lexer": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz", + "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==", + "license": "MIT" + }, "node_modules/cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -7720,6 +9513,15 @@ "node": ">= 12.0.0" } }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmmirror.com/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/commondir/-/commondir-1.0.1.tgz", @@ -7909,7 +9711,6 @@ "version": "3.50.0", "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.50.0.tgz", "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", - "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.7" @@ -8026,6 +9827,15 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/css-line-break": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", @@ -8209,6 +10019,57 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/dayjs": { "version": "1.11.23", "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.23.tgz", @@ -8291,7 +10152,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -8331,6 +10192,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", @@ -8343,6 +10221,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/defu": { "version": "6.1.7", "resolved": "https://registry.npmmirror.com/defu/-/defu-6.1.7.tgz", @@ -8465,6 +10360,7 @@ "integrity": "sha512-aypfsr6t0uNvkqaZc6zvBfXzC6pLI0/sIulpkV6RwCVtZqG5ebBzv4weImKK0VNCj91Wl9F5j7p5WU4MNrybng==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "srvx": ">=0.11.5" }, @@ -8509,6 +10405,7 @@ "integrity": "sha512-aOuk+yNJA61yA6eJJvQJxpJLIxz090hKMqDGzd35tGsvwaodi1RPuYSFUp5EINaJp7snjVwLkO2RXVMPZBYnnA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "srvx": "bin/srvx.mjs" }, @@ -9137,6 +11034,7 @@ "resolved": "https://registry.npmmirror.com/drizzle-orm/-/drizzle-orm-0.45.2.tgz", "integrity": "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", @@ -9304,6 +11202,21 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.422", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", @@ -9352,6 +11265,92 @@ "integrity": "sha512-chfpPHmCerdo/rXr/nNvPZRkV4WwDRwzwnsJ0Uzz3tVi8Z41tDctRjduYy1138ii77AFlts1qvWtX3g/Acg91Q==", "license": "MIT" }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -9377,9 +11376,9 @@ "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -9403,12 +11402,33 @@ "node": ">= 0.4" } }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { "version": "0.27.7", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.7.tgz", "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -9463,7 +11483,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -9477,8 +11497,9 @@ "resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.39.5.tgz", "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, + "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9833,7 +11854,7 @@ "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -9867,7 +11888,7 @@ "version": "4.2.1", "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9880,14 +11901,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -9898,7 +11919,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -9915,7 +11936,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -9932,7 +11953,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -9948,7 +11969,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -9961,7 +11982,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -9977,7 +11998,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -9993,7 +12014,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10006,7 +12027,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -10019,7 +12040,7 @@ "version": "10.4.0", "resolved": "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -10037,7 +12058,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -10050,7 +12071,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -10063,7 +12084,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -10079,12 +12100,23 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/eta": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/eta/-/eta-4.6.0.tgz", + "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", @@ -10160,7 +12192,6 @@ "version": "3.1.3", "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-fifo": { @@ -10201,14 +12232,13 @@ "version": "2.1.0", "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-npm-meta": { @@ -10252,6 +12282,22 @@ "fast-string-truncated-width": "^3.0.2" } }, + "node_modules/fast-uri": { + "version": "3.1.7", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-wrap-ansi": { "version": "0.2.2", "resolved": "https://registry.npmmirror.com/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", @@ -10297,7 +12343,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -10312,6 +12358,42 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "license": "MIT" }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -10358,7 +12440,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -10372,7 +12454,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/fnv1a-64": { @@ -10401,6 +12483,21 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", @@ -10538,6 +12635,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/fuse.js": { "version": "7.5.0", "resolved": "https://registry.npmmirror.com/fuse.js/-/fuse.js-7.5.0.tgz", @@ -10629,6 +12758,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" + }, "node_modules/get-port-please": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", @@ -10660,6 +12795,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-tsconfig": { "version": "4.13.6", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", @@ -10744,6 +12896,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "16.2.4", "resolved": "https://registry.npmmirror.com/globby/-/globby-16.2.4.tgz", @@ -10836,6 +13004,18 @@ "uncrypto": "^0.1.3" } }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -10845,6 +13025,33 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -11057,6 +13264,12 @@ "node": ">=16.17.0" } }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, "node_modules/identifier-regex": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/identifier-regex/-/identifier-regex-1.1.0.tgz", @@ -11124,7 +13337,7 @@ "version": "3.3.1", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -11137,6 +13350,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/import-in-the-middle/-/import-in-the-middle-3.4.0.tgz", + "integrity": "sha512-Xfjwfarhe+LGmoaof+sexeNo3sGRysb5x56WrZLwHtmqT0OilSKtVWkv0lrCcMgSKyKP9oBogBAisHZvtJH0aw==", + "license": "Apache-2.0", + "dependencies": { + "cjs-module-lexer": "^2.2.0", + "es-module-lexer": "^2.2.0", + "module-details-from-path": "^1.0.4" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/impound": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/impound/-/impound-1.2.0.tgz", @@ -11154,7 +13381,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -11199,6 +13426,20 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/iobuffer": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", @@ -11236,6 +13477,57 @@ "url": "https://github.com/sponsors/brc-dd" } }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -11248,6 +13540,22 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-builtin-module": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/is-builtin-module/-/is-builtin-module-5.0.0.tgz", @@ -11264,6 +13572,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -11279,6 +13599,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-docker": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", @@ -11294,6 +13647,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -11303,6 +13671,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -11406,12 +13789,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "license": "MIT" }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -11421,6 +13828,31 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-inside": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-4.0.0.tgz", @@ -11460,6 +13892,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz", @@ -11472,6 +13940,97 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-wsl": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz", @@ -11520,6 +14079,23 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmmirror.com/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz", @@ -11539,7 +14115,7 @@ "version": "4.3.2", "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.2.tgz", "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -11584,7 +14160,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json-schema-to-typescript-lite": { @@ -11602,14 +14178,14 @@ "version": "0.4.1", "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json5": { @@ -11636,6 +14212,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", @@ -11730,7 +14315,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -11981,11 +14566,20 @@ "node": ">= 0.6.3" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -12009,6 +14603,7 @@ "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.33.0.tgz", "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "license": "MPL-2.0", + "peer": true, "dependencies": { "detect-libc": "^2.0.3" }, @@ -12381,6 +14976,12 @@ "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -12421,7 +15022,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/lodash.once": { @@ -12709,6 +15310,12 @@ "integrity": "sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==", "license": "MIT" }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", @@ -12825,7 +15432,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/negotiator": { @@ -13596,6 +16203,7 @@ "resolved": "https://registry.npmmirror.com/nuxt/-/nuxt-4.5.2.tgz", "integrity": "sha512-tR3fcqeHlHmmkLMpIg3V7Y+1ltr302lW8djMw/iy+myfo7QSSz+BVJDuQhg5j73b9oteSyBfOKTDYTgvMtj6TA==", "license": "MIT", + "peer": true, "dependencies": { "@dxup/nuxt": "^0.5.6", "@nuxt/cli": "^3.37.0", @@ -13734,6 +16342,7 @@ "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-1.2.3.tgz", "integrity": "sha512-Bpb0W2TbLKOZ7vJnOUnVRGq3WL2p+ISV29M6hYPL1AFCpyKZpdr5ytiXoTSSxRVhg8YW7f65+6gbG8WG6PCa/g==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } @@ -13900,6 +16509,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/obug": { "version": "2.1.4", "resolved": "https://registry.npmmirror.com/obug/-/obug-2.1.4.tgz", @@ -14019,8 +16657,9 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -14044,6 +16683,24 @@ "@otplib/preset-v11": "^12.0.1" } }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/oxc-walker": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/oxc-walker/-/oxc-walker-1.1.1.tgz", @@ -14159,7 +16816,7 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -14393,6 +17050,15 @@ "node": ">= 10.12" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.28", "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.28.tgz", @@ -14412,6 +17078,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", @@ -14957,6 +17624,7 @@ "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15007,6 +17675,7 @@ "resolved": "https://registry.npmmirror.com/postgres/-/postgres-3.4.9.tgz", "integrity": "sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==", "license": "Unlicense", + "peer": true, "engines": { "node": ">=12" }, @@ -15070,7 +17739,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -15162,7 +17831,7 @@ "version": "2.3.1", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -15448,6 +18117,46 @@ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "license": "Apache-2.0" }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmmirror.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -15469,11 +18178,53 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, "node_modules/regjsparser": { "version": "0.13.2", "resolved": "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.13.2.tgz", "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.1.0" @@ -15652,6 +18403,28 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", + "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3" + }, + "engines": { + "node": ">=9.3.0 || >=8.10.0 <9.0.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -15695,7 +18468,7 @@ "version": "4.0.0", "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -15802,6 +18575,7 @@ "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.2.7.tgz", "integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==", "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/types": "=0.148.0", "@rolldown/pluginutils": "^1.0.0" @@ -16148,6 +18922,31 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -16168,6 +18967,28 @@ ], "license": "MIT" }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", @@ -16378,6 +19199,52 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "license": "ISC" }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -16424,14 +19291,14 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -16443,13 +19310,13 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -16698,6 +19565,19 @@ "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", "license": "MIT" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -16761,6 +19641,104 @@ "node": ">=8" } }, + "node_modules/string.prototype.matchall": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz", + "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "get-intrinsic": "^1.3.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.4", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -16786,6 +19764,15 @@ "node": ">=8" } }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -16815,7 +19802,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -17073,6 +20060,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -17173,6 +20161,57 @@ "streamx": "^2.12.5" } }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/terser": { "version": "5.46.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", @@ -17399,6 +20438,7 @@ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -17435,7 +20475,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -17472,6 +20512,80 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -17482,8 +20596,9 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17504,6 +20619,24 @@ "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==", "license": "MIT" }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/uncrypto": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", @@ -17575,6 +20708,7 @@ "resolved": "https://registry.npmmirror.com/unhead/-/unhead-3.4.0.tgz", "integrity": "sha512-OlgpyYjY+NkFyQCaMihg2uTFbbvyr5lZr6TokS68VdFTXJ5jo4JwFtGR8PwKy/wRpjbQYgKF7ZYO+pbRgxtSmw==", "license": "MIT", + "peer": true, "dependencies": { "hookable": "^6.1.1", "unplugin": "^3.3.0" @@ -17591,6 +20725,46 @@ } } }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", @@ -17670,6 +20844,18 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -17778,6 +20964,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "napi-postinstall": "^0.3.4" }, @@ -17981,6 +21168,16 @@ "pkg-types": "^2.3.0" } }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, "node_modules/update-browserslist-db": { "version": "1.3.2", "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", @@ -18021,7 +21218,7 @@ "version": "4.4.1", "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -18107,6 +21304,7 @@ "resolved": "https://registry.npmmirror.com/vite/-/vite-8.2.2.tgz", "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", @@ -18403,6 +21601,48 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/vite-plugin-pwa": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", + "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.10", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/vite-plugin-pwa/node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/vite-plugin-top-level-await": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.6.0.tgz", @@ -18470,6 +21710,7 @@ "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.42.tgz", "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.42", "@vue/compiler-sfc": "3.5.42", @@ -18513,6 +21754,7 @@ "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.0", "eslint-scope": "^8.2.0 || ^9.0.0", @@ -18536,6 +21778,7 @@ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", "license": "MIT", + "peer": true, "dependencies": { "@vue/devtools-api": "^6.6.4" }, @@ -18602,12 +21845,103 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-module": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wmf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", @@ -18630,12 +21964,310 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/workbox-background-sync": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", + "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", + "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-build": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-build/-/workbox-build-7.4.1.tgz", + "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "eta": "^4.5.1", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^11.0.1", + "pretty-bytes": "^5.3.0", + "rollup": "^4.53.3", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.4.1", + "workbox-broadcast-update": "7.4.1", + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-google-analytics": "7.4.1", + "workbox-navigation-preload": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-range-requests": "7.4.1", + "workbox-recipes": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1", + "workbox-streams": "7.4.1", + "workbox-sw": "7.4.1", + "workbox-window": "7.4.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { + "version": "0.3.7", + "resolved": "https://registry.npmmirror.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.7.tgz", + "integrity": "sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==", + "license": "MIT", + "dependencies": { + "jsonpointer": "^5.0.1", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/workbox-build/node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/workbox-build/node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/workbox-build/node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/workbox-build/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.8.0.tgz", + "integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", + "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-core": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-core/-/workbox-core-7.4.1.tgz", + "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-expiration/-/workbox-expiration-7.4.1.tgz", + "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", + "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.4.1", + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", + "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-precaching": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-precaching/-/workbox-precaching-7.4.1.tgz", + "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", + "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-recipes": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-recipes/-/workbox-recipes-7.4.1.tgz", + "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-routing": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-routing/-/workbox-routing-7.4.1.tgz", + "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-strategies": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-strategies/-/workbox-strategies-7.4.1.tgz", + "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-streams": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-streams/-/workbox-streams-7.4.1.tgz", + "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1" + } + }, + "node_modules/workbox-sw": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-sw/-/workbox-sw-7.4.1.tgz", + "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/workbox-window/-/workbox-window-7.4.1.tgz", + "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.4.1" + } + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -18823,8 +22455,9 @@ "version": "2.9.0", "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, + "devOptional": true, "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 080b1d2..cf0977c 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "@pixi/filter-bulge-pinch": "^5.1.1", "@pixi/filter-color-matrix": "^7.4.3", "@pixi/sprite": "^7.4.3", + "@sentry/node": "^10.73.0", + "@sentry/vue": "^10.73.0", "@simplewebauthn/browser": "^13.3.0", "@simplewebauthn/server": "^13.3.3", "@types/crypto-js": "^4.2.2", @@ -60,6 +62,7 @@ "@types/pg": "^8.20.0", "@ungap/structured-clone": "^1.3.0", "@vercel/speed-insights": "^1.3.1", + "@vite-pwa/nuxt": "^1.1.1", "axios": "^1.20.0", "bcryptjs": "^2.4.3", "bezier-easing": "^2.1.0", @@ -105,6 +108,7 @@ "node": ">=22.11.0" }, "devDependencies": { + "@clack/prompts": "^1.1.0", "@nuxt/eslint": "^1.17.0", "eslint": "^9.39.5", "prettier": "^3.9.6", diff --git a/server/api/admin/songs/batch-reject.post.ts b/server/api/admin/songs/batch-reject.post.ts new file mode 100644 index 0000000..2f0af7a --- /dev/null +++ b/server/api/admin/songs/batch-reject.post.ts @@ -0,0 +1,135 @@ +import { db } from '~/drizzle/db' +import { schedules, songBlacklists, songs, votes, requestTimes } from '~/drizzle/schema' +import { and, eq, inArray, sql } from 'drizzle-orm' +import { cacheService } from '../../../services/cacheService' +import { createSongRejectedNotification } from '../../../services/notificationService' +import { requireSongAdmin } from '~~/server/utils/requireSongAdmin' +import { createApiError } from '~~/server/utils/apiError' +import { SERVER_ERROR_CODES } from '~~/server/config/constants' + +const MAX_BATCH_REJECT_COUNT = 1000 + +export default defineEventHandler(async (event) => { + const user = requireSongAdmin(event) + + const body = await readBody(event) + + const songIds = Array.isArray(body?.songIds) + ? [...new Set(body.songIds.filter((id: any) => Number.isInteger(id) && id > 0))] + : [] + const reason = typeof body?.reason === 'string' ? body.reason.trim() : '' + const addToBlacklist = body?.addToBlacklist === true + + if (songIds.length === 0) { + throw createApiError(400, SERVER_ERROR_CODES.SONG_BATCH_REJECT_IDS_REQUIRED, '歌曲ID列表不能为空') + } + + if (songIds.length > MAX_BATCH_REJECT_COUNT) { + throw createApiError( + 400, + SERVER_ERROR_CODES.SONG_BATCH_REJECT_LIMIT_EXCEEDED, + `单次最多驳回 ${MAX_BATCH_REJECT_COUNT} 首歌曲`, + { params: [MAX_BATCH_REJECT_COUNT] } + ) + } + + if (!reason) { + throw createApiError(400, SERVER_ERROR_CODES.SONG_BATCH_REJECT_REASON_REQUIRED, '驳回原因不能为空') + } + + try { + let rejectedSongs: any[] = [] + + await db.transaction(async (tx) => { + const existingSongs = await tx.select().from(songs).where(inArray(songs.id, songIds)) + + if (existingSongs.length === 0) { + throw createApiError(404, SERVER_ERROR_CODES.SONG_NOT_FOUND, '歌曲不存在或已被删除') + } + + const existingIds = existingSongs.map((song) => song.id) + console.log(`开始批量驳回歌曲,共 ${existingIds.length} 首`) + + if (addToBlacklist) { + const blacklistValues = [...new Set(existingSongs.map((song: any) => `${song.title} - ${song.artist}`))] + const existingBlacklist = await tx + .select({ value: songBlacklists.value }) + .from(songBlacklists) + .where(and(eq(songBlacklists.type, 'SONG'), inArray(songBlacklists.value, blacklistValues))) + const existingSet = new Set(existingBlacklist.map((item) => item.value)) + const valuesToInsert = blacklistValues.filter((value) => !existingSet.has(value)) + for (const value of valuesToInsert) { + try { + await tx.insert(songBlacklists).values({ + type: 'SONG', + value, + reason: `歌曲驳回: ${reason}`, + createdBy: user.id + }) + } catch (error: any) { + console.log(`黑名单添加失败,可能已存在: ${error.message}`) + } + } + console.log(`黑名单添加处理完成`) + } + + await tx.delete(votes).where(inArray(votes.songId, existingIds)) + console.log(`删除了投票记录`) + + await tx.delete(schedules).where(inArray(schedules.songId, existingIds)) + console.log(`删除了排期记录`) + + const hitRequestIds = [...new Set(existingSongs.map((song: any) => song.hitRequestId).filter(Boolean))] + for (const hitRequestId of hitRequestIds) { + const count = existingSongs.filter((song: any) => song.hitRequestId === hitRequestId).length + try { + await tx + .update(requestTimes) + .set({ + accepted: sql`GREATEST(0, accepted - ${count})` + }) + .where(eq(requestTimes.id, hitRequestId as any)) + } catch (error: any) { + console.error(`减少投稿时段 ${hitRequestId} 接纳数量失败: ${error.message}`) + } + } + + rejectedSongs = await tx.delete(songs).where(inArray(songs.id, existingIds)).returning() + console.log(`歌曲批量删除完成`) + }) + + const songsToNotify = rejectedSongs.filter((song) => song.requesterId) + for (const song of songsToNotify) { + createSongRejectedNotification( + song.requesterId, + { title: song.title, artist: song.artist }, + reason + ).catch((error: any) => { + console.error(`发送驳回通知失败: ${error.message}`) + }) + } + + await cacheService.clearSongsCache() + await cacheService.clearSchedulesCache() + + console.log(`批量驳回操作完成,共 ${rejectedSongs.length} 首`) + + return { + success: true, + message: '歌曲批量驳回成功', + data: { + rejected: rejectedSongs.length, + missing: songIds.length - rejectedSongs.length, + notificationSent: songsToNotify.length + } + } + } catch (error: any) { + console.error('批量驳回歌曲失败:', error) + + if (error.statusCode) { + throw error + } + + throw createApiError(500, SERVER_ERROR_CODES.SONG_OPERATION_FAILED, '批量驳回失败: ' + error.message) + } +}) diff --git a/server/api/auth/2fa/verify.post.ts b/server/api/auth/2fa/verify.post.ts index 14f191c..7f5fd7e 100644 --- a/server/api/auth/2fa/verify.post.ts +++ b/server/api/auth/2fa/verify.post.ts @@ -3,6 +3,7 @@ const { authenticator } = otplib import { db, userIdentities, eq, and, users } from '~/drizzle/db' import { twoFactorCodes } from '~~/server/utils/twoFactorStore' import { JWTEnhanced } from '~~/server/utils/jwt-enhanced' +import { createAuthSession } from '~~/server/utils/create-auth-session' import { getClientIP } from '~~/server/utils/ip-utils' import { getBeijingTime } from '~/utils/timeUtils' @@ -100,7 +101,12 @@ export default defineEventHandler(async (event) => { .catch((err) => console.error('Error updating user login info:', err)) // 生成Token - const authToken = JWTEnhanced.generateToken(user.id, user.role) + const { token: authToken, jti } = JWTEnhanced.generateTokenWithJti(user.id, user.role) + await createAuthSession(event, { + userId: user.id, + jti, + loginMethod: type === 'totp' ? 'totp_2fa' : 'email_2fa' + }) const isSecure = getRequestURL(event).protocol === 'https:' || diff --git a/server/api/auth/[provider]/callback.get.ts b/server/api/auth/[provider]/callback.get.ts index fe196ca..dc24044 100644 --- a/server/api/auth/[provider]/callback.get.ts +++ b/server/api/auth/[provider]/callback.get.ts @@ -2,6 +2,7 @@ import { parseState, getRedirectUri } from '~~/server/utils/oauth' import { generateBindingToken } from '~~/server/utils/oauth-token' import { db, eq, userIdentities } from '~/drizzle/db' import { JWTEnhanced } from '~~/server/utils/jwt-enhanced' +import { createAuthSession } from '~~/server/utils/create-auth-session' import { getOAuthStrategy } from '~~/server/utils/oauth-strategies' import { isUserBlocked, getUserBlockRemainingTime } from '~~/server/services/securityService' @@ -142,7 +143,13 @@ async function handleUserLoginOrBind( } // 登录 - const token = JWTEnhanced.generateToken(existingIdentity.user.id, existingIdentity.user.role) + const { token, jti } = JWTEnhanced.generateTokenWithJti(existingIdentity.user.id, existingIdentity.user.role) + await createAuthSession(event, { + userId: existingIdentity.user.id, + jti, + loginMethod: 'oauth', + oauthProvider: provider + }) setCookie(event, 'auth-token', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', diff --git a/server/api/auth/bind.post.ts b/server/api/auth/bind.post.ts index 1e31b27..43025d1 100644 --- a/server/api/auth/bind.post.ts +++ b/server/api/auth/bind.post.ts @@ -1,6 +1,7 @@ import bcrypt from 'bcryptjs' import { db, eq, users, userIdentities } from '~/drizzle/db' import { JWTEnhanced } from '~~/server/utils/jwt-enhanced' +import { createAuthSession } from '~~/server/utils/create-auth-session' import { verifyBindingToken } from '~~/server/utils/oauth-token' import { isAccountLocked, @@ -86,7 +87,13 @@ export default defineEventHandler(async (event) => { recordLoginSuccess(username, clientIp) // 登录 - const token = JWTEnhanced.generateToken(user.id, user.role) + const { token, jti } = JWTEnhanced.generateTokenWithJti(user.id, user.role) + await createAuthSession(event, { + userId: user.id, + jti, + loginMethod: 'oauth', + oauthProvider: payload.provider + }) setCookie(event, 'auth-token', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', diff --git a/server/api/auth/login.post.ts b/server/api/auth/login.post.ts index 5d3f3f9..2113caf 100644 --- a/server/api/auth/login.post.ts +++ b/server/api/auth/login.post.ts @@ -1,6 +1,7 @@ import bcrypt from 'bcryptjs' import { db, eq, users, userIdentities, and } from '~/drizzle/db' import { JWTEnhanced } from '~~/server/utils/jwt-enhanced' +import { createAuthSession } from '~~/server/utils/create-auth-session' import { getAccountLockRemainingTime, getIPBlockRemainingTime, @@ -187,7 +188,8 @@ export default defineEventHandler(async (event) => { .catch((err) => console.error('Error updating user login info:', err)) // 生成JWT - const token = JWTEnhanced.generateToken(user.id, user.role) + const { token, jti } = JWTEnhanced.generateTokenWithJti(user.id, user.role) + await createAuthSession(event, { userId: user.id, jti, loginMethod: 'password' }) // 自动判断是否需要secure const isSecure = diff --git a/server/api/auth/register.post.ts b/server/api/auth/register.post.ts index 5e6ef73..7369928 100644 --- a/server/api/auth/register.post.ts +++ b/server/api/auth/register.post.ts @@ -1,6 +1,7 @@ import bcrypt from 'bcryptjs' import { db, eq, users } from '~/drizzle/db' import { JWTEnhanced } from '~~/server/utils/jwt-enhanced' +import { createAuthSession } from '~~/server/utils/create-auth-session' import { emailVerificationCodes } from '~~/server/api/user/email/send-code.post' export default defineEventHandler(async (event) => { @@ -109,7 +110,8 @@ export default defineEventHandler(async (event) => { } // 签发 JWT Token - const token = JWTEnhanced.generateToken(newUser.id, newUser.role) + const { token, jti } = JWTEnhanced.generateTokenWithJti(newUser.id, newUser.role) + await createAuthSession(event, { userId: newUser.id, jti, loginMethod: 'password' }) const isSecure = getRequestURL(event).protocol === 'https:' || diff --git a/server/api/auth/verify.get.ts b/server/api/auth/verify.get.ts index d44065b..db98f63 100644 --- a/server/api/auth/verify.get.ts +++ b/server/api/auth/verify.get.ts @@ -3,6 +3,7 @@ import { db } from '~/drizzle/db' import { users } from '~/drizzle/schema' import { executeRedisCommand, isRedisReady } from '../../utils/redis' import { eq } from 'drizzle-orm' +import { isSessionRevokedByJti, touchAuthSession } from '~~/server/utils/create-auth-session' // 用户认证缓存(永久缓存,登出或权限变更时主动失效) @@ -19,9 +20,17 @@ export default defineEventHandler(async (event) => { } // 验证JWT令牌 - const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: number } + const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: number; jti?: string } const userId = decoded.userId + if (await isSessionRevokedByJti(decoded.jti)) { + throw createError({ + statusCode: 401, + statusMessage: '会话已撤销,请重新登录' + }) + } + touchAuthSession(decoded.jti).catch(() => undefined) + // 优先从Redis缓存获取用户认证状态 if (isRedisReady()) { const cachedUser = await executeRedisCommand(async () => { diff --git a/server/api/auth/webauthn/login/verify.post.ts b/server/api/auth/webauthn/login/verify.post.ts index 1367427..a05d8d4 100644 --- a/server/api/auth/webauthn/login/verify.post.ts +++ b/server/api/auth/webauthn/login/verify.post.ts @@ -4,6 +4,7 @@ import { getWebAuthnConfig } from '~~/server/utils/webauthn-config' import { db, eq, and, userIdentities } from '~/drizzle/db' import { createError, defineEventHandler, setCookie } from 'h3' import { JWTEnhanced } from '~~/server/utils/jwt-enhanced' +import { createAuthSession } from '~~/server/utils/create-auth-session' export default defineEventHandler(async (event) => { const body = await readBody(event) @@ -84,7 +85,8 @@ export default defineEventHandler(async (event) => { .where(eq(userIdentities.id, identity.id)) // 签发登录 Token - const token = JWTEnhanced.generateToken(identity.user.id, identity.user.role) + const { token, jti } = JWTEnhanced.generateTokenWithJti(identity.user.id, identity.user.role) + await createAuthSession(event, { userId: identity.user.id, jti, loginMethod: 'webauthn' }) setCookie(event, 'auth-token', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', diff --git a/server/api/open/schedules.get.ts b/server/api/open/schedules.get.ts index 4139815..9744bd4 100644 --- a/server/api/open/schedules.get.ts +++ b/server/api/open/schedules.get.ts @@ -1,12 +1,17 @@ import { createError, defineEventHandler, getQuery } from 'h3' import { db } from '~/drizzle/db' -import { playTimes, schedules, songCollaborators, songs, users } from '~/drizzle/schema' +import { playTimes, schedules, songCollaborators, songs, systemSettings, users } from '~/drizzle/schema' import { and, asc, desc, eq, gte, inArray, like, lt, or, sql } from 'drizzle-orm' import { formatDateTime } from '~/utils/timeUtils' import { openApiCache } from '~~/server/utils/open-api-cache' import { CACHE_CONSTANTS } from '~~/server/config/constants' import { cacheService } from '~~/server/services/cacheService' import { executeRedisCommand, isRedisReady } from '~~/server/utils/redis' +import { + resolveScheduleVisibilityRange, + isPlayDateInRange, + type VisibilitySettingsLike +} from '~~/server/utils/schedule-visibility' export default defineEventHandler(async (event) => { try { @@ -36,6 +41,27 @@ export default defineEventHandler(async (event) => { const sortBy = (query.sortBy as string) || 'playDate' const sortOrder = (query.sortOrder as string) || 'asc' + // 读取系统设置:排期可见范围 + let visibilityRange = { startAt: null as Date | null, endAt: null as Date | null } + try { + const systemSettingsDataResult = await db.select().from(systemSettings).limit(1) + const systemSettingsData = systemSettingsDataResult[0] || null + const visibilitySettings: VisibilitySettingsLike = { + scheduleDaysBeforeEnabled: systemSettingsData?.scheduleDaysBeforeEnabled, + scheduleDaysBefore: systemSettingsData?.scheduleDaysBefore, + scheduleDaysAfterEnabled: systemSettingsData?.scheduleDaysAfterEnabled, + scheduleDaysAfter: systemSettingsData?.scheduleDaysAfter + } + visibilityRange = resolveScheduleVisibilityRange(visibilitySettings) + } catch (err) { + console.warn('[Schedules API] 读取排期可见范围设置失败,将展示全部:', err) + } + + const applyVisibilityFilter = (items: any[]): any[] => { + if (!visibilityRange.startAt && !visibilityRange.endAt) return items + return items.filter((s) => isPlayDateInRange(s.playDate, visibilityRange)) + } + // 优先从普通API缓存获取数据 // 尝试从CacheService获取排期数据 @@ -49,6 +75,7 @@ export default defineEventHandler(async (event) => { if (semester) { filteredSchedules = cachedSchedules.filter((s) => s.song?.semester === semester) } + filteredSchedules = applyVisibilityFilter(filteredSchedules) // 转换为开放API格式 const result = { @@ -105,11 +132,12 @@ export default defineEventHandler(async (event) => { }) if (redisData) { + const filteredRedisData = applyVisibilityFilter(redisData) // 转换为开放API格式 const result = { success: true, data: { - schedules: redisData.map((schedule: any) => ({ + schedules: filteredRedisData.map((schedule: any) => ({ id: schedule.id, playDate: schedule.playDate, sequence: schedule.sequence, @@ -133,7 +161,7 @@ export default defineEventHandler(async (event) => { } : null })), - total: redisData.length, + total: filteredRedisData.length, semester: semester || null } } @@ -175,6 +203,13 @@ export default defineEventHandler(async (event) => { conditions.push(or(like(songs.title, `%${search}%`)!, like(songs.artist, `%${search}%`)!)!) } + if (visibilityRange.startAt) { + conditions.push(gte(schedules.playDate, visibilityRange.startAt)!) + } + if (visibilityRange.endAt) { + conditions.push(lt(schedules.playDate, visibilityRange.endAt)!) + } + const whereCondition = conditions.length > 0 ? and(...conditions) : undefined // 计算偏移量 diff --git a/server/api/site-config.get.ts b/server/api/site-config.get.ts index 8ead517..2e0c55c 100644 --- a/server/api/site-config.get.ts +++ b/server/api/site-config.get.ts @@ -26,7 +26,13 @@ const publicFields = [ 'enableSubmissionRemarks', 'enableRequestTimeLimitation', 'forceBlockAllRequests', - 'smtpEnabled' + 'smtpEnabled', + 'defaultTheme', + 'enabledThemes', + 'scheduleDaysBeforeEnabled', + 'scheduleDaysBefore', + 'scheduleDaysAfterEnabled', + 'scheduleDaysAfter' ] const filterPublicSettings = (data: any) => { @@ -81,7 +87,13 @@ export default defineEventHandler(async (event) => { enableRequestTimeLimitation: false, forceBlockAllRequests: false, enableReplayRequests: false, - smtpEnabled: false + smtpEnabled: false, + defaultTheme: 'System', + enabledThemes: '["System","ClassicDark","ClassicLight","ModernLight"]', + scheduleDaysBeforeEnabled: false, + scheduleDaysBefore: 30, + scheduleDaysAfterEnabled: false, + scheduleDaysAfter: 14 }) .returning() diff --git a/server/api/songs/[id]/update.put.ts b/server/api/songs/[id]/update.put.ts index abe3c9c..3d5b70d 100644 --- a/server/api/songs/[id]/update.put.ts +++ b/server/api/songs/[id]/update.put.ts @@ -1,8 +1,16 @@ import { db } from '~/drizzle/db' -import { songs, users, songCollaborators, collaborationLogs } from '~/drizzle/schema' -import { eq, or } from 'drizzle-orm' +import { + songs, + users, + songCollaborators, + collaborationLogs, + systemSettings, + songBlacklists +} from '~/drizzle/schema' +import { and, eq, inArray, or } from 'drizzle-orm' import { cacheService } from '~~/server/services/cacheService' import { createSubmissionNoteClearedNotification } from '~~/server/services/notificationService' +import { moderateSubmissionNote } from '~~/server/utils/submissionNoteAutoModeration' export default defineEventHandler(async (event) => { try { @@ -122,6 +130,38 @@ export default defineEventHandler(async (event) => { ? body.submissionNote.trim() : null } + if ('submissionNotePublic' in body) { + const wantPublic = updateData.submissionNote ? body.submissionNotePublic !== false : false + updateData.submissionNotePublic = wantPublic + + // 自动审查(若 systemSettings 打开 submissionNoteRequiresApproval) + try { + const sysSetRes = await db.select().from(systemSettings).limit(1) + const sysSet = sysSetRes[0] + if (sysSet?.submissionNoteRequiresApproval && wantPublic && updateData.submissionNote) { + const bl = await db + .select() + .from(songBlacklists) + .where(inArray(songBlacklists.type, ['KEYWORD', 'LANGUAGE', 'GENRE'])) + const mod = moderateSubmissionNote( + updateData.submissionNote, + wantPublic, + true, + { + title: updateData.title || existingSong.title, + artist: updateData.artist || existingSong.artist + }, + bl + ) + updateData.submissionNotePublic = mod.notePublic + updateData.submissionNotePublicStatus = mod.publicStatus + } else { + updateData.submissionNotePublicStatus = null + } + } catch (err) { + console.warn('[Update API] 投稿留言自动审查失败,保持用户设置:', err) + } + } const currentRequesterId = updateData.requesterId || existingSong.requesterId diff --git a/server/api/songs/public.get.ts b/server/api/songs/public.get.ts index 6cd730c..d342e44 100644 --- a/server/api/songs/public.get.ts +++ b/server/api/songs/public.get.ts @@ -11,7 +11,12 @@ import { users, votes } from '~/drizzle/schema' -import { and, count, desc, eq, inArray } from 'drizzle-orm' +import { and, count, desc, eq, gte, inArray, lt, like, or } from 'drizzle-orm' +import { + resolveScheduleVisibilityRange, + isPlayDateInRange, + type VisibilitySettingsLike +} from '~~/server/utils/schedule-visibility' import { cacheService } from '~~/server/services/cacheService' import { executeRedisCommand, isRedisReady } from '../../utils/redis' import { formatDateTime } from '~/utils/timeUtils' @@ -38,6 +43,13 @@ export default defineEventHandler(async (event) => { .limit(1) const systemSettingsData = systemSettingsDataResult[0] || null const shouldHideStudentInfo = systemSettingsData?.hideStudentInfo ?? true + const visibilitySettings: VisibilitySettingsLike = { + scheduleDaysBeforeEnabled: systemSettingsData?.scheduleDaysBeforeEnabled, + scheduleDaysBefore: systemSettingsData?.scheduleDaysBefore, + scheduleDaysAfterEnabled: systemSettingsData?.scheduleDaysAfterEnabled, + scheduleDaysAfter: systemSettingsData?.scheduleDaysAfter + } + const visibilityRange = resolveScheduleVisibilityRange(visibilitySettings) // 初始化缓存服务 @@ -73,7 +85,14 @@ export default defineEventHandler(async (event) => { }) if (cachedData) { - return cachedData + const filtered = visibilityRange.startAt || visibilityRange.endAt + ? cachedData.filter((s) => isPlayDateInRange(s.playDate, visibilityRange)) + : cachedData + const resultData = JSON.parse(JSON.stringify(filtered)) as PublicScheduleItem[] + if (shouldHideStudentInfo && !isAdmin) { + maskPublicScheduleData(resultData) + } + return resultData } } @@ -91,6 +110,12 @@ export default defineEventHandler(async (event) => { filteredSchedules = cachedSchedules.filter((s) => s.song?.semester === semester) console.log(`[Cache] 过滤学期 ${semester} 后的数量: ${filteredSchedules.length}`) } + // 应用排期可见范围过滤 + if (visibilityRange.startAt || visibilityRange.endAt) { + filteredSchedules = filteredSchedules.filter((s) => + isPlayDateInRange(s.playDate, visibilityRange) + ) + } // 将过滤后的数据缓存到Redis(缓存完整数据,不进行模糊化) if (isRedisReady()) { @@ -116,6 +141,13 @@ export default defineEventHandler(async (event) => { } // 获取排期的歌曲,包含播放时段信息(查询所有学期的数据) + const scheduleWhere: any[] = [eq(schedules.isDraft, false)] + if (visibilityRange.startAt) { + scheduleWhere.push(gte(schedules.playDate, visibilityRange.startAt)!) + } + if (visibilityRange.endAt) { + scheduleWhere.push(lt(schedules.playDate, visibilityRange.endAt)!) + } const schedulesData = await db .select({ id: schedules.id, @@ -153,10 +185,9 @@ export default defineEventHandler(async (event) => { .leftJoin(songs, eq(schedules.songId, songs.id)) .leftJoin(users, eq(songs.requesterId, users.id)) .leftJoin(playTimes, eq(schedules.playTimeId, playTimes.id)) - .where(eq(schedules.isDraft, false)) // 只查询已发布的排期 + .where(and(...scheduleWhere)) // 只查询已发布的排期(+可见范围) .orderBy(schedules.playDate) - // 获取每首歌的投票数 const voteCountsQuery = await db .select({ songId: votes.songId, diff --git a/server/api/songs/request.post.ts b/server/api/songs/request.post.ts index 632859a..abf422f 100644 --- a/server/api/songs/request.post.ts +++ b/server/api/songs/request.post.ts @@ -4,14 +4,16 @@ import { playTimes, requestTimes, semesters, + songBlacklists, songCollaborators, songs, systemSettings } from '~/drizzle/db' -import { and, eq, gt, gte, lt, lte, sql } from 'drizzle-orm' +import { and, eq, gt, gte, inArray, lt, lte, sql } from 'drizzle-orm' import { createCollaborationInvitationNotification } from '~~/server/services/notificationService' import { isLimitReached } from '~~/server/utils/submissionLimit' import { getBeijingTimeISOString } from '~/utils/timeUtils' +import { moderateSubmissionNote } from '~~/server/utils/submissionNoteAutoModeration' export default defineEventHandler(async (event) => { // 检查用户认证 @@ -132,6 +134,18 @@ export default defineEventHandler(async (event) => { const systemSettingsData = systemSettingsResult[0] const isAdmin = user.role === 'SUPER_ADMIN' || user.role === 'ADMIN' + // 加载自动审查需要的黑名单(KEYWORD / LANGUAGE / GENRE) + let moderationBlacklists: any[] = [] + try { + moderationBlacklists = await db + .select() + .from(songBlacklists) + .where(inArray(songBlacklists.type, ['KEYWORD', 'LANGUAGE', 'GENRE'])) + } catch (err) { + console.warn('[Request API] 加载自动审查黑名单失败,将跳过自动审查:', err) + moderationBlacklists = [] + } + // 1. 检查强制关闭 if (systemSettingsData?.forceBlockAllRequests && !isAdmin) { throw createError({ @@ -243,8 +257,34 @@ export default defineEventHandler(async (event) => { } const submissionNote = systemSettingsData?.enableSubmissionRemarks && rawSubmissionNote ? rawSubmissionNote : null - const submissionNotePublic = - submissionNote !== null ? body.submissionNotePublic !== false : false + const rawSubmissionNotePublic = submissionNote !== null ? body.submissionNotePublic !== false : false + const requiresApproval = Boolean(systemSettingsData?.submissionNoteRequiresApproval) + + let finalSubmissionNotePublic = rawSubmissionNotePublic + let submissionNotePublicStatus: string | null = null + + if (submissionNote && rawSubmissionNotePublic && requiresApproval) { + const mod = moderateSubmissionNote( + submissionNote, + rawSubmissionNotePublic, + requiresApproval, + { title: body.title, artist: body.artist, genre: body.genre || null }, + moderationBlacklists + ) + finalSubmissionNotePublic = mod.notePublic + submissionNotePublicStatus = mod.publicStatus + if (mod.rejectedReasons.length > 0) { + console.log( + `[Request API] 投稿留言自动审查未通过,歌曲=${body.title} - ${body.artist},原因:`, + mod.rejectedReasons + ) + } + } else if (submissionNote) { + // 没开自动审查,也记录一下状态 + submissionNotePublicStatus = null + } + + const submissionNotePublic = finalSubmissionNotePublic // 准备发送通知的列表 const notificationsToSend: { userId: number; songId: number; songTitle: string }[] = [] @@ -367,6 +407,7 @@ export default defineEventHandler(async (event) => { playUrl: body.playUrl || null, submissionNote, submissionNotePublic, + submissionNotePublicStatus, hitRequestId: hitRequestTime?.id || null, expectedPlayDate: body.expectedPlayDate || null, expectedPlaySequence: body.expectedPlaySequence !== undefined ? Number(body.expectedPlaySequence) : null diff --git a/server/config/constants.ts b/server/config/constants.ts index daa4c29..f708722 100644 --- a/server/config/constants.ts +++ b/server/config/constants.ts @@ -180,3 +180,13 @@ export const RISK_CONTROL_CONSTANTS = { SONG_IP_DOMINANCE_PERCENT: 0.6, SONG_IP_MIN_SAMPLE: 8 } as const + +export const SERVER_ERROR_CODES = { + AUTH_UNAUTHORIZED: 'AUTH_UNAUTHORIZED', + AUTH_FORBIDDEN: 'AUTH_FORBIDDEN', + SONG_NOT_FOUND: 'SONG_NOT_FOUND', + SONG_OPERATION_FAILED: 'SONG_OPERATION_FAILED', + SONG_BATCH_REJECT_IDS_REQUIRED: 'SONG_BATCH_REJECT_IDS_REQUIRED', + SONG_BATCH_REJECT_LIMIT_EXCEEDED: 'SONG_BATCH_REJECT_LIMIT_EXCEEDED', + SONG_BATCH_REJECT_REASON_REQUIRED: 'SONG_BATCH_REJECT_REASON_REQUIRED' +} as const diff --git a/server/plugins/sentry.ts b/server/plugins/sentry.ts new file mode 100644 index 0000000..daec8c9 --- /dev/null +++ b/server/plugins/sentry.ts @@ -0,0 +1,24 @@ +import * as Sentry from '@sentry/node' + +export default defineNitroPlugin((nitroApp) => { + const config = useRuntimeConfig() + const dsn = config.sentry?.serverDsn || config.sentry?.dsn + + if (!dsn) return + + Sentry.init({ + dsn, + environment: config.sentry?.environment || process.env.NODE_ENV || 'production', + release: config.sentry?.release || undefined, + tracesSampleRate: config.sentry?.errorSampleRate ?? 1.0, + sampleRate: config.sentry?.errorSampleRate ?? 1.0 + }) + + nitroApp.hooks.hook('error', (error) => { + Sentry.captureException(error) + }) + + nitroApp.hooks.hook('request', (event) => { + event.context.sentry = Sentry + }) +}) diff --git a/server/services/cardCodeDeleteService.ts b/server/services/cardCodeDeleteService.ts new file mode 100644 index 0000000..eecbfaf --- /dev/null +++ b/server/services/cardCodeDeleteService.ts @@ -0,0 +1,20 @@ +import { inArray } from 'drizzle-orm' +import { db } from '~/drizzle/db' +import { cardCodes, cardCodeRedemptions, songs } from '~/drizzle/schema' + +export async function deleteCardCodesByIds(ids: number[]) { + return await db.transaction(async (tx) => { + await tx.update(songs) + .set({ cardCodeId: null }) + .where(inArray(songs.cardCodeId, ids)) + + await tx.delete(cardCodeRedemptions) + .where(inArray(cardCodeRedemptions.cardCodeId, ids)) + + const deleted = await tx.delete(cardCodes) + .where(inArray(cardCodes.id, ids)) + .returning() + + return deleted + }) +} diff --git a/server/utils/admin-password-policy.ts b/server/utils/admin-password-policy.ts new file mode 100644 index 0000000..9755036 --- /dev/null +++ b/server/utils/admin-password-policy.ts @@ -0,0 +1,35 @@ +import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH } from '~/utils/password-policy' + +interface AdminPasswordViolation { + code: string + message: string +} + +export function getAdminPasswordViolation(password: unknown): AdminPasswordViolation | null { + if (typeof password !== 'string' || !password) { + return { code: 'AUTH_NEW_PASSWORD_REQUIRED', message: '新密码不能为空' } + } + + if (password.length < PASSWORD_MIN_LENGTH) { + return { + code: 'AUTH_PASSWORD_TOO_SHORT', + message: `密码长度不能少于${PASSWORD_MIN_LENGTH}个字符` + } + } + + if (password.length > PASSWORD_MAX_LENGTH) { + return { + code: 'AUTH_PASSWORD_TOO_LONG', + message: `密码长度不能超过${PASSWORD_MAX_LENGTH}位` + } + } + + if (new TextEncoder().encode(password).length > 72) { + return { + code: 'AUTH_PASSWORD_TOO_MANY_BYTES', + message: '密码有效长度不能超过72字节' + } + } + + return null +} diff --git a/server/utils/apiError.ts b/server/utils/apiError.ts new file mode 100644 index 0000000..cea7d95 --- /dev/null +++ b/server/utils/apiError.ts @@ -0,0 +1,15 @@ +import { createError } from 'h3' + +export function createApiError( + statusCode: number, + code: string, + message: string, + data?: Record +) { + return createError({ + statusCode, + statusMessage: code, + message, + data: { code, ...(data || {}) } + }) +} diff --git a/server/utils/auth-route-policy.ts b/server/utils/auth-route-policy.ts new file mode 100644 index 0000000..b0ef35b --- /dev/null +++ b/server/utils/auth-route-policy.ts @@ -0,0 +1,99 @@ +type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' + +interface RoutePolicy { + path: string + methods: readonly HttpMethod[] +} + +const GET_METHODS = ['GET', 'HEAD'] as const +const WRITE_METHODS = ['POST', 'PUT', 'PATCH', 'DELETE'] as const + +export const PASSWORD_CHANGE_ALLOWED_ROUTES: readonly RoutePolicy[] = [ + { path: '/api/auth/verify', methods: GET_METHODS }, + { path: '/api/auth/logout', methods: ['POST'] }, + { path: '/api/auth/change-password', methods: ['POST'] }, + { path: '/api/auth/set-initial-password', methods: ['POST'] }, + { path: '/api/auth/2fa/verify', methods: ['POST'] }, + { path: '/api/auth/2fa/send-email', methods: ['POST'] }, + { path: '/api/site-config', methods: GET_METHODS } +] + +export const PUBLIC_API_EXACT_ROUTES: readonly RoutePolicy[] = [ + { path: '/api/auth/login', methods: ['POST'] }, + { path: '/api/auth/register', methods: ['POST'] }, + { path: '/api/auth/email-code', methods: ['POST'] }, + { path: '/api/auth/grade-class-options', methods: GET_METHODS }, + { path: '/api/auth/oauth-register-options', methods: GET_METHODS }, + { path: '/api/auth/bind', methods: ['POST'] }, + { path: '/api/auth/oauth-register', methods: ['POST'] }, + { path: '/api/auth/2fa/verify', methods: ['POST'] }, + { path: '/api/auth/2fa/send-email', methods: ['POST'] }, + { path: '/api/auth/forgot-password', methods: ['POST'] }, + { path: '/api/auth/reset-password', methods: ['POST'] }, + { path: '/api/auth/captcha', methods: GET_METHODS }, + { path: '/api/semesters/current', methods: GET_METHODS }, + { path: '/api/play-times', methods: GET_METHODS }, + { path: '/api/schedules/public', methods: GET_METHODS }, + { path: '/api/songs/count', methods: GET_METHODS }, + { path: '/api/songs/public', methods: GET_METHODS }, + { path: '/api/site-config', methods: GET_METHODS }, + { path: '/api/system/location', methods: GET_METHODS }, + { path: '/api/auth/webauthn/login', methods: ['POST'] }, + { path: '/api/music/resolve-url', methods: ['POST'] }, + { path: '/api/music/state', methods: ['POST'] }, + { path: '/api/music/websocket', methods: GET_METHODS }, + { path: '/api/sys/time', methods: GET_METHODS } +] + +export const PUBLIC_API_PREFIX_ROUTES: readonly RoutePolicy[] = [ + { path: '/api/proxy/', methods: GET_METHODS }, + { path: '/api/api-enhanced/', methods: [...GET_METHODS, ...WRITE_METHODS] }, + { path: '/api/native-api/', methods: [...GET_METHODS, 'POST'] }, + { path: '/api/open/', methods: [...GET_METHODS, ...WRITE_METHODS] }, + { path: '/api/auth/webauthn/login/', methods: ['POST'] } +] + +function matchesMethod(policy: RoutePolicy, method: string): boolean { + return policy.methods.includes(method.toUpperCase() as HttpMethod) +} + +export function isPublicApiPath(pathname: string, method: string): boolean { + return ( + PUBLIC_API_EXACT_ROUTES.some( + (policy) => pathname === policy.path && matchesMethod(policy, method) + ) || + PUBLIC_API_PREFIX_ROUTES.some( + (policy) => pathname.startsWith(policy.path) && matchesMethod(policy, method) + ) + ) +} + +export function isAllowedDuringPasswordChange(pathname: string, method: string): boolean { + return PASSWORD_CHANGE_ALLOWED_ROUTES.some( + (policy) => pathname === policy.path && matchesMethod(policy, method) + ) +} + +export function shouldBlockDuringPasswordChange( + pathname: string, + method: string, + requirePasswordChange: boolean +): boolean { + return ( + requirePasswordChange && + !isPublicApiPath(pathname, method) && + !isAllowedDuringPasswordChange(pathname, method) + ) +} + +export function shouldBypassPublicApiAuthentication( + pathname: string, + method: string, + hasToken: boolean +): boolean { + return isPublicApiPath(pathname, method) && !hasToken +} + +export function canBindOAuthIdentity(requirePasswordChange: boolean): boolean { + return !requirePasswordChange +} diff --git a/server/utils/card-code-delete-handler.ts b/server/utils/card-code-delete-handler.ts new file mode 100644 index 0000000..682954d --- /dev/null +++ b/server/utils/card-code-delete-handler.ts @@ -0,0 +1,68 @@ +import { createError, getQuery, readBody } from 'h3' +import { z } from 'zod' +import { deleteCardCodesByIds } from '~~/server/services/cardCodeDeleteService' + +const MAX_DELETE_COUNT = 500 +const idSchema = z.preprocess( + (value) => (typeof value === 'number' || typeof value === 'string' ? value : undefined), + z.coerce.number().int().positive() +) + +const deleteCardCodesSchema = z.object({ + id: idSchema.optional(), + ids: z.preprocess( + (value) => { + if (typeof value === 'string') { + return value.split(',').map((item) => item.trim()).filter(Boolean) + } + return value + }, + z.array(idSchema).max(MAX_DELETE_COUNT, `单次最多删除 ${MAX_DELETE_COUNT} 个点歌券`).optional() + ) +}) + +export const handleOpenCardCodeDelete = async (event: any) => { + const apiKey = event.context.apiKey + if (!apiKey) { + throw createError({ statusCode: 401, message: 'API认证失败' }) + } + + try { + const query = getQuery(event) + const body = await readBody(event).catch(() => ({})) ?? {} + const validatedData = deleteCardCodesSchema.parse({ ...query, ...body }) + const rawIds = [ + ...(validatedData.id !== undefined ? [validatedData.id] : []), + ...(validatedData.ids || []) + ] + const ids = Array.from(new Set(rawIds)) + + if (!ids.length) { + throw createError({ statusCode: 400, message: '缺少有效点歌券ID' }) + } + if (ids.length > MAX_DELETE_COUNT) { + throw createError({ statusCode: 400, message: `单次最多删除 ${MAX_DELETE_COUNT} 个点歌券` }) + } + + const deletedRows = await deleteCardCodesByIds(ids) + return { + success: true, + message: '点歌券删除成功', + data: { + cardCodes: deletedRows, + deleted: deletedRows.length, + requested: ids.length + } + } + } catch (err: any) { + if (err.statusCode) throw err + if (err.name === 'ZodError') { + throw createError({ + statusCode: 400, + message: `请求参数验证失败:${(err.issues || err.errors).map((issue: any) => issue.message).join(', ')}` + }) + } + console.error('开放API删除点歌券失败', err) + throw createError({ statusCode: 500, message: '删除点歌券失败' }) + } +} diff --git a/server/utils/create-auth-session.ts b/server/utils/create-auth-session.ts new file mode 100644 index 0000000..bd45df1 --- /dev/null +++ b/server/utils/create-auth-session.ts @@ -0,0 +1,83 @@ +import { getHeader } from 'h3' +import { db, eq, and } from '~/drizzle/db' +import { authSessions } from '~/drizzle/schema' +import { parseUserAgent, type LoginMethod } from './user-agent-info' +import { getClientIP } from './ip-utils' +import { randomUUID } from 'node:crypto' + +export interface CreateAuthSessionOptions { + userId: number + jti: string + loginMethod: LoginMethod + expiresAt?: Date + oauthProvider?: string +} + +const DEFAULT_SESSION_TTL_MS = 7 * 24 * 60 * 60 * 1000 + +export async function createAuthSession( + event: any, + options: CreateAuthSessionOptions +): Promise { + const { userId, jti, loginMethod, oauthProvider } = options + const ua = getHeader(event, 'user-agent') + const { browser, operatingSystem, device } = parseUserAgent(ua) + const ip = getClientIP(event) + const now = new Date() + const expiresAt = options.expiresAt ?? new Date(now.getTime() + DEFAULT_SESSION_TTL_MS) + + try { + let method = loginMethod + if (oauthProvider && method === 'oauth') { + method = `oauth:${oauthProvider}` as any + } + + await db.insert(authSessions).values({ + id: randomUUID(), + userId, + sessionToken: jti, + browser, + operatingSystem, + device, + loginMethod: method, + ipAddress: ip, + userAgent: ua ?? null, + createdAt: now, + lastActiveAt: now, + expiresAt, + isRevoked: false + }) + } catch (error) { + console.warn('[AuthSession] 创建会话失败,继续无会话登录:', error) + } + + return jti +} + +export async function isSessionRevokedByJti(jti: string | undefined): Promise { + if (!jti) return false + try { + const row = await db.query.authSessions.findFirst({ + where: and(eq(authSessions.sessionToken, jti)), + columns: { isRevoked: true, expiresAt: true } + }) + if (!row) return false + if (row.expiresAt && row.expiresAt.getTime() < Date.now()) return true + return Boolean(row.isRevoked) + } catch (error) { + console.warn('[AuthSession] 会话状态校验失败,默认放行:', error) + return false + } +} + +export async function touchAuthSession(jti: string | undefined): Promise { + if (!jti) return + try { + await db + .update(authSessions) + .set({ lastActiveAt: new Date() }) + .where(eq(authSessions.sessionToken, jti)) + } catch (_error) { + // ignore + } +} diff --git a/server/utils/email-verification.ts b/server/utils/email-verification.ts new file mode 100644 index 0000000..d649217 --- /dev/null +++ b/server/utils/email-verification.ts @@ -0,0 +1,171 @@ +import { randomInt, timingSafeEqual } from 'node:crypto' +import { getServerTimestamp } from '~~/server/utils/serverTime' +import { getRedisClient, buildRedisKey } from '~~/server/utils/redis' + +const EMAIL_CODE_TTL_MS = 5 * 60 * 1000 +const EMAIL_CODE_COOLDOWN_MS = 60 * 1000 +const EMAIL_CODE_MAX_ATTEMPTS = 5 +const EMAIL_CODE_DAILY_LIMIT = 5 +const EMAIL_CODE_DAILY_WINDOW_MS = 24 * 60 * 60 * 1000 + +type EmailCodeEntry = { + code: string + expiresAt: number + createdAt: number + attempts: number +} + +const emailCodes = new Map() +const dailySendCounts = new Map() + +const normalizeEmail = (email: string) => email.trim().toLowerCase() + +const getDayKey = () => { + const now = new Date(getServerTimestamp()) + return `${now.getUTCFullYear()}-${now.getUTCMonth() + 1}-${now.getUTCDate()}` +} + +const codeRedisKey = (email: string) => buildRedisKey('email-code', 'code', normalizeEmail(email)) +const attemptsRedisKey = (email: string) => buildRedisKey('email-code', 'attempts', normalizeEmail(email)) +const cooldownRedisKey = (email: string) => buildRedisKey('email-code', 'cooldown', normalizeEmail(email)) +const dailyRedisKey = (email: string) => buildRedisKey('email-code', 'daily', normalizeEmail(email), getDayKey()) + +const VERIFY_EMAIL_CODE_SCRIPT = ` +local stored = redis.call('GET', KEYS[1]) +if not stored then + return { 0, 0 } +end +local attempts = redis.call('INCR', KEYS[2]) +if attempts == 1 then + redis.call('EXPIRE', KEYS[2], 300) +end +if ARGV[1] == stored then + redis.call('DEL', KEYS[1], KEYS[2]) + return { 1, attempts } +end +if attempts >= tonumber(ARGV[2]) then + redis.call('DEL', KEYS[1], KEYS[2]) + return { 2, attempts } +end +return { 0, attempts } +` + +const safeCodeEqual = (a: string, b: string): boolean => { + if (a.length !== b.length) return false + return timingSafeEqual(Buffer.from(a), Buffer.from(b)) +} + +export function generateEmailCode(): string { + return String(randomInt(100000, 1000000)) +} + +export async function storeEmailCode(email: string, code: string): Promise { + const normalized = normalizeEmail(email) + const now = getServerTimestamp() + emailCodes.set(normalized, { + code, + expiresAt: now + EMAIL_CODE_TTL_MS, + createdAt: now, + attempts: 0 + }) + + const dayKey = getDayKey() + const record = dailySendCounts.get(normalized) + if (!record || record.dayKey !== dayKey) { + dailySendCounts.set(normalized, { count: 1, dayKey }) + } else { + record.count++ + } + + let client: Awaited> | null = null + try { + client = getRedisClient() + if (!client) return + const ttlSeconds = Math.ceil(EMAIL_CODE_TTL_MS / 1000) + await client.set(codeRedisKey(email), code, { EX: ttlSeconds }) + await client.set(cooldownRedisKey(email), '1', { + EX: Math.ceil(EMAIL_CODE_COOLDOWN_MS / 1000) + }) + const dailyKey = dailyRedisKey(email) + const dailyCount = await client.incr(dailyKey) + if (dailyCount === 1) { + await client.expire(dailyKey, Math.ceil(EMAIL_CODE_DAILY_WINDOW_MS / 1000)) + } + } catch (error) { + console.error('[EmailCode] Redis 写入失败,已回退内存存储:', error) + } +} + +export async function isEmailCodeCooldownActive(email: string): Promise { + let client: Awaited> | null = null + try { + client = getRedisClient() + if (client) { + return Boolean(await client.exists(cooldownRedisKey(email))) + } + } catch (error) { + console.error('[EmailCode] Redis 读取失败,已回退内存判断:', error) + } + const entry = emailCodes.get(normalizeEmail(email)) + return Boolean(entry && getServerTimestamp() - entry.createdAt < EMAIL_CODE_COOLDOWN_MS) +} + +export async function isEmailCodeDailyLimitReached(email: string): Promise { + let client: Awaited> | null = null + try { + client = getRedisClient() + if (client) { + const count = await client.get(dailyRedisKey(email)) + return Number(count || 0) >= EMAIL_CODE_DAILY_LIMIT + } + } catch (error) { + console.error('[EmailCode] Redis 读取失败,已回退内存判断:', error) + } + const normalized = normalizeEmail(email) + const dayKey = getDayKey() + const record = dailySendCounts.get(normalized) + return Boolean(record && record.dayKey === dayKey && record.count >= EMAIL_CODE_DAILY_LIMIT) +} + +export async function verifyEmailCode(email: string, code: string): Promise { + const trimmedCode = code.trim() + let client + try { + client = getRedisClient() + if (client) { + const result = await client.eval(VERIFY_EMAIL_CODE_SCRIPT, { + keys: [codeRedisKey(email), attemptsRedisKey(email)], + arguments: [trimmedCode, String(EMAIL_CODE_MAX_ATTEMPTS)] + }) + if (Array.isArray(result)) { + return Number(result[0]) === 1 + } + } + } catch (error) { + console.error('[EmailCode] Redis 校验失败,已回退内存校验:', error) + } + + const normalized = normalizeEmail(email) + const entry = emailCodes.get(normalized) + if (!entry) return false + if (getServerTimestamp() > entry.expiresAt) { + emailCodes.delete(normalized) + return false + } + if (safeCodeEqual(entry.code, trimmedCode)) { + emailCodes.delete(normalized) + return true + } + entry.attempts++ + if (entry.attempts >= EMAIL_CODE_MAX_ATTEMPTS) { + emailCodes.delete(normalized) + } + return false +} + +export function cleanupExpiredEmailCodes(): void { + const now = getServerTimestamp() + for (const [email, entry] of emailCodes) { + if (now > entry.expiresAt) emailCodes.delete(email) + } +} diff --git a/server/utils/grade-class-core.ts b/server/utils/grade-class-core.ts new file mode 100644 index 0000000..39234a5 --- /dev/null +++ b/server/utils/grade-class-core.ts @@ -0,0 +1,36 @@ +export const smartSort = (a: string, b: string) => { + const gradeOrder: Record = { + '初一': 1, '初二': 2, '初三': 3, + '高一': 4, '高二': 5, '高三': 6, + '大一': 7, '大二': 8, '大三': 9, '大四': 10, + '教师': 99, '教职工': 99 + } + + const weightA = gradeOrder[a] + const weightB = gradeOrder[b] + + if (weightA !== undefined && weightB !== undefined) return weightA - weightB + if (weightA !== undefined) return -1 + if (weightB !== undefined) return 1 + + return a.localeCompare(b, 'zh-CN', { numeric: true }) +} + +export interface GradeClassOption { + grade: string + class: string +} + +export const resolveGradeClassOptions = ( + configItems: GradeClassOption[], + fallbackItems: GradeClassOption[] +): GradeClassOption[] => { + const source = configItems.length > 0 ? configItems : fallbackItems + + return source + .filter((item): item is GradeClassOption => Boolean(item.grade?.trim()) && Boolean(item.class?.trim())) + .sort((a, b) => { + const gradeResult = smartSort(a.grade, b.grade) + return gradeResult || smartSort(a.class, b.class) + }) +} diff --git a/server/utils/grade-class-options.ts b/server/utils/grade-class-options.ts new file mode 100644 index 0000000..b7fc19b --- /dev/null +++ b/server/utils/grade-class-options.ts @@ -0,0 +1,45 @@ +import { and, isNotNull, eq, ne, sql } from 'drizzle-orm' +import { db } from '~/drizzle/db' +import { users, gradeClasses } from '~/drizzle/schema' +import { resolveGradeClassOptions, type GradeClassOption } from './grade-class-core' + +export async function fetchGradeClassOptions(): Promise { + const [configRows, userRows] = await Promise.all([ + db.select({ + grade: gradeClasses.grade, + class: gradeClasses.class + }).from(gradeClasses), + db + .selectDistinct({ + grade: users.grade, + class: users.class + }) + .from(users) + .where(and(eq(users.status, 'active'), isNotNull(users.grade), isNotNull(users.class))) + ]) + + return resolveGradeClassOptions(configRows, userRows) +} + +export async function isGradeClassValid(grade: string, studentClass: string): Promise { + const configHit = await db.query.gradeClasses.findFirst({ + where: (t, { eq: eq_, and: and_ }) => and_(eq_(t.grade, grade), eq_(t.class, studentClass)), + columns: { id: true } + }) + + if (configHit) return true + + const configCount = await db + .select({ count: () => sql`count(*)::int` }) + .from(gradeClasses) + .where(and(ne(gradeClasses.grade, ''), ne(gradeClasses.class, ''))) + if ((configCount[0]?.count || 0) > 0) return false + + const userHit = await db.query.users.findFirst({ + where: (t, { eq: eq_, and: and_ }) => + and_(eq_(t.status, 'active'), eq_(t.grade, grade), eq_(t.class, studentClass)), + columns: { id: true } + }) + + return Boolean(userHit) +} diff --git a/server/utils/important-notification-policy.ts b/server/utils/important-notification-policy.ts new file mode 100644 index 0000000..2c8c273 --- /dev/null +++ b/server/utils/important-notification-policy.ts @@ -0,0 +1,72 @@ +export const NOTIFICATION_TITLE_MAX_LENGTH = 200 +export const NOTIFICATION_CONTENT_MAX_LENGTH = 20000 +export const NOTIFICATION_SOURCES = { + SYSTEM: 'SYSTEM', + ADMIN_MANUAL: 'ADMIN_MANUAL' +} as const + +export type NotificationSenderInput = { + id: number + name?: string | null + username?: string | null +} + +export type NotificationSenderSnapshot = { + senderId: number | null + senderName: string | null + senderUsername: string | null +} + +export const resolveNotificationSource = (sender: NotificationSenderInput | null) => + sender ? NOTIFICATION_SOURCES.ADMIN_MANUAL : NOTIFICATION_SOURCES.SYSTEM + +export const createNotificationSenderSnapshot = ( + sender: NotificationSenderInput | null = null +): NotificationSenderSnapshot => ({ + senderId: sender?.id ?? null, + senderName: sender?.name?.trim() || null, + senderUsername: sender?.username?.trim() || null +}) + +export const serializeNotificationSender = (snapshot: NotificationSenderSnapshot) => + snapshot.senderId + ? { + id: snapshot.senderId, + name: snapshot.senderName, + username: snapshot.senderUsername + } + : null + +export const shouldCheckImportantNotification = ( + authenticated: boolean, + userId?: number | null, + requirePasswordChange = false +): boolean => + authenticated && Number.isInteger(userId) && Number(userId) > 0 && !requirePasswordChange + +export const canSendSystemNotification = (role?: string): boolean => + role === 'ADMIN' || role === 'SUPER_ADMIN' + +export const resolveImportantFlag = (value: unknown): boolean | null => { + if (value === undefined) return false + return typeof value === 'boolean' ? value : null +} + +export const shouldDeliverSystemNotification = ( + important: boolean, + notificationsEnabled?: boolean +): boolean => important || notificationsEnabled !== false + +export const shouldRetainNotificationHistory = (type: string, source: string): boolean => + type === 'SYSTEM_NOTICE' && source === NOTIFICATION_SOURCES.ADMIN_MANUAL + +export const createNotificationReadUpdate = (updatedAt = new Date()) => ({ + read: true as const, + updatedAt +}) + +export const createNotificationUserDeleteUpdate = (updatedAt = new Date()) => ({ + userDeleted: true as const, + read: true as const, + updatedAt +}) diff --git a/server/utils/initial-password-policy.ts b/server/utils/initial-password-policy.ts new file mode 100644 index 0000000..c1e379d --- /dev/null +++ b/server/utils/initial-password-policy.ts @@ -0,0 +1,33 @@ +interface InitialPasswordUserState { + requirePasswordChange?: boolean | null +} + +interface StoredPasswordState { + password?: string | null + passwordChangedAt?: Date | string | null +} + +export interface PasswordSetupState { + hasSetPassword: boolean + needsInitialPasswordSetup: boolean +} + +export function getPasswordSetupState( + storedPassword: StoredPasswordState, + requirePasswordChange: boolean +): PasswordSetupState { + const hasSetPassword = !!storedPassword.password + return { + hasSetPassword, + needsInitialPasswordSetup: + !storedPassword.passwordChangedAt && (requirePasswordChange || !hasSetPassword) + } +} + +export function canSetInitialPassword( + user: InitialPasswordUserState, + storedPassword: StoredPasswordState +): boolean { + return getPasswordSetupState(storedPassword, !!user.requirePasswordChange) + .needsInitialPasswordSetup +} diff --git a/server/utils/instance-id.ts b/server/utils/instance-id.ts new file mode 100644 index 0000000..2d7ef39 --- /dev/null +++ b/server/utils/instance-id.ts @@ -0,0 +1,112 @@ +import { randomUUID } from 'node:crypto' +import { asc, eq, sql } from 'drizzle-orm' +import { db } from '~/drizzle/db' +import { systemSettings } from '~/drizzle/schema' +import { SYSTEM_SETTINGS_DEFAULTS } from './system-settings-defaults' +import { getServerTimestamp } from './serverTime' + +export interface InstanceIdInfo { + instanceId: string + persisted: boolean +} + +let cachedInstanceIdInfo: InstanceIdInfo | null = null +let cachedInstanceIdExpiresAt = 0 +let pendingInstanceIdPromise: Promise | null = null +let pendingInstanceIdInfoPromise: Promise | null = null + +const TEMPORARY_INSTANCE_ID_CACHE_TTL_MS = 5 * 60 * 1000 + +const loadOrCreateInstanceId = async (): Promise => { + const settingsResult = await db + .select({ id: systemSettings.id, instanceId: systemSettings.instanceId }) + .from(systemSettings) + .orderBy(asc(systemSettings.id)) + .limit(1) + + const settings = settingsResult[0] + + if (settings?.instanceId) { + return settings.instanceId + } + + const instanceId = randomUUID() + + if (!settings) { + await db + .insert(systemSettings) + .values({ id: 1, ...SYSTEM_SETTINGS_DEFAULTS, instanceId }) + .onConflictDoUpdate({ + target: systemSettings.id, + set: { instanceId, updatedAt: new Date() } + }) + + await db.execute(sql` + SELECT setval(pg_get_serial_sequence('"SystemSettings"', 'id'), (SELECT MAX(id) FROM "SystemSettings")) + `) + } else { + await db + .update(systemSettings) + .set({ instanceId, updatedAt: new Date() }) + .where(eq(systemSettings.id, settings.id)) + } + + return instanceId +} + +const getCachedInstanceIdInfo = (): InstanceIdInfo | null => { + if (!cachedInstanceIdInfo) { + return null + } + + if (cachedInstanceIdInfo.persisted || cachedInstanceIdExpiresAt > getServerTimestamp()) { + return cachedInstanceIdInfo + } + + return null +} + +export const getInstanceIdInfo = async (): Promise => { + const cached = getCachedInstanceIdInfo() + if (cached) { + return cached + } + + if (!pendingInstanceIdInfoPromise) { + pendingInstanceIdInfoPromise = loadOrCreateInstanceId() + .then((instanceId) => { + const info = { instanceId, persisted: true } + cachedInstanceIdInfo = info + cachedInstanceIdExpiresAt = Number.POSITIVE_INFINITY + return info + }) + .catch((error) => { + const fallbackInstanceId = cachedInstanceIdInfo?.persisted === false + ? cachedInstanceIdInfo.instanceId + : randomUUID() + + const info = { instanceId: fallbackInstanceId, persisted: false } + cachedInstanceIdInfo = info + cachedInstanceIdExpiresAt = getServerTimestamp() + TEMPORARY_INSTANCE_ID_CACHE_TTL_MS + console.warn('[Instance ID] Failed to persist instance ID, using temporary fallback value:', error) + return info + }) + .finally(() => { + pendingInstanceIdInfoPromise = null + }) + } + + return pendingInstanceIdInfoPromise +} + +export const getInstanceId = async (): Promise => { + if (!pendingInstanceIdPromise) { + pendingInstanceIdPromise = getInstanceIdInfo() + .then(({ instanceId }) => instanceId) + .finally(() => { + pendingInstanceIdPromise = null + }) + } + + return pendingInstanceIdPromise +} diff --git a/server/utils/jwt-enhanced.ts b/server/utils/jwt-enhanced.ts index b57e83a..53aaa08 100644 --- a/server/utils/jwt-enhanced.ts +++ b/server/utils/jwt-enhanced.ts @@ -38,30 +38,34 @@ export class JWTEnhanced { } /** - * 生成JWT token + * 生成JWT token(返回 token 字符串,兼容旧调用) */ static generateToken(userId: number, role: string): string { + return this.generateTokenWithJti(userId, role).token + } + + /** + * 生成JWT token 并返回 jti(会话表关联需要) + */ + static generateTokenWithJti(userId: number, role: string): { token: string; jti: string } { if (!this.JWT_SECRET) { throw new Error('JWT_SECRET environment variable is not set') } - // 生成唯一的JWT ID const jti = `${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` - // JWT载荷 const payload: Omit = { userId, role, jti } - // 生成token const token = jwt.sign(payload, this.JWT_SECRET, { expiresIn: this.TOKEN_EXPIRES }) console.log(`Generated JWT token for user ${userId}`) - return token + return { token, jti } } /** diff --git a/server/utils/notification-history-policy.ts b/server/utils/notification-history-policy.ts new file mode 100644 index 0000000..9457fe1 --- /dev/null +++ b/server/utils/notification-history-policy.ts @@ -0,0 +1,108 @@ +export const NOTIFICATION_HISTORY_STATUSES = ['ALL', 'READ', 'UNREAD'] as const + +export type NotificationHistoryStatus = (typeof NOTIFICATION_HISTORY_STATUSES)[number] + +export const NOTIFICATION_HISTORY_TYPES = ['ALL', 'IMPORTANT', 'NORMAL'] as const +export const NOTIFICATION_HISTORY_SORT_ORDERS = ['DESC', 'ASC'] as const +export const NOTIFICATION_HISTORY_KEYWORD_MAX_LENGTH = 100 + +export type NotificationHistoryType = (typeof NOTIFICATION_HISTORY_TYPES)[number] +export type NotificationHistorySortOrder = (typeof NOTIFICATION_HISTORY_SORT_ORDERS)[number] + +export const resolveNotificationHistoryFilters = (values: { + keyword?: unknown + type?: unknown + sender?: unknown + sortOrder?: unknown +}): { + keyword: string + type: NotificationHistoryType + senderId: number | null + sortOrder: NotificationHistorySortOrder +} | null => { + if (values.keyword !== undefined && typeof values.keyword !== 'string') return null + + const keyword = typeof values.keyword === 'string' ? values.keyword.trim() : '' + if (keyword.length > NOTIFICATION_HISTORY_KEYWORD_MAX_LENGTH) return null + + if (values.type !== undefined && typeof values.type !== 'string') return null + const type = typeof values.type === 'string' && values.type.trim() + ? values.type.trim().toUpperCase() + : 'ALL' + if (!NOTIFICATION_HISTORY_TYPES.includes(type as NotificationHistoryType)) return null + + let senderId: number | null = null + if (values.sender !== undefined && values.sender !== null && values.sender !== '') { + if (typeof values.sender !== 'string') return null + const parsedSenderId = Number(values.sender.trim()) + if (!Number.isInteger(parsedSenderId) || parsedSenderId <= 0) return null + senderId = parsedSenderId + } + + if (values.sortOrder !== undefined && typeof values.sortOrder !== 'string') return null + const sortOrder = typeof values.sortOrder === 'string' && values.sortOrder.trim() + ? values.sortOrder.trim().toUpperCase() + : 'DESC' + if (!NOTIFICATION_HISTORY_SORT_ORDERS.includes(sortOrder as NotificationHistorySortOrder)) { + return null + } + + return { + keyword, + type: type as NotificationHistoryType, + senderId, + sortOrder: sortOrder as NotificationHistorySortOrder + } +} + +export const resolveNotificationHistoryStatus = ( + value: unknown +): NotificationHistoryStatus | null => { + if (value === undefined || value === null || value === '') return 'ALL' + if (typeof value !== 'string') return null + + const normalized = value.trim().toUpperCase() + return NOTIFICATION_HISTORY_STATUSES.includes(normalized as NotificationHistoryStatus) + ? (normalized as NotificationHistoryStatus) + : null +} + +export const resolveNotificationHistoryPagination = ( + pageValue: unknown, + limitValue: unknown +) => { + const parsedPage = Number(pageValue) + const parsedLimit = Number(limitValue) + const page = Number.isInteger(parsedPage) && parsedPage > 0 ? parsedPage : 1 + const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 100) : 20 + + return { + page, + limit, + offset: (page - 1) * limit + } +} + +const UUID_PATTERN = + /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i +const LEGACY_BATCH_PATTERN = /^legacy-([1-9]\d*)$/ + +export const resolveNotificationBatchReference = (value: unknown) => { + if (typeof value !== 'string') return null + + const normalized = value.trim() + const legacyMatch = normalized.match(LEGACY_BATCH_PATTERN) + if (legacyMatch) { + return { + batchId: null, + notificationId: Number(legacyMatch[1]) + } + } + + if (!UUID_PATTERN.test(normalized)) return null + + return { + batchId: normalized.toLowerCase(), + notificationId: null + } +} diff --git a/server/utils/oauth-identity.ts b/server/utils/oauth-identity.ts new file mode 100644 index 0000000..1486f74 --- /dev/null +++ b/server/utils/oauth-identity.ts @@ -0,0 +1,85 @@ +import { db, eq, userIdentities, users } from '~/drizzle/db' +import { getBeijingTime } from '~/utils/timeUtils' +import { resolveAvatarSource } from '~~/server/utils/user-avatar' + +type DbTransaction = Parameters[0]>[0] + +export interface OAuthIdentityPayload { + provider: string + providerUserId: string + providerUsername?: string | null + avatar?: string | null +} + +export interface ExistingOAuthIdentity { + id: number + avatar: string | null +} + +export async function syncOAuthIdentityAvatar( + tx: DbTransaction, + user: { id: number; avatarProvider?: string | null; avatarProviderUserId?: string | null }, + existing: ExistingOAuthIdentity | null | undefined, + payload: OAuthIdentityPayload +): Promise<{ created: boolean; avatarSourceSet: boolean }> { + const currentIdentities = await tx.query.userIdentities.findMany({ + where: (t, { eq: eqUserId }) => eqUserId(t.userId, user.id), + columns: { + id: true, + provider: true, + providerUserId: true, + providerUsername: true, + avatar: true, + createdAt: true + } + }) + const currentAvatarSource = resolveAvatarSource(user, currentIdentities) + + let created = false + if (existing) { + if (payload.avatar && existing.avatar !== payload.avatar) { + await tx + .update(userIdentities) + .set({ avatar: payload.avatar }) + .where(eq(userIdentities.id, existing.id)) + } + } else { + await tx.insert(userIdentities).values({ + userId: user.id, + provider: payload.provider, + providerUserId: payload.providerUserId, + providerUsername: payload.providerUsername, + avatar: payload.avatar || null, + createdAt: getBeijingTime() + }) + created = true + } + + let avatarSourceSet = false + if (!currentAvatarSource) { + const updatedIdentities = await tx.query.userIdentities.findMany({ + where: (t, { eq: eqUserId }) => eqUserId(t.userId, user.id), + columns: { + id: true, + provider: true, + providerUserId: true, + providerUsername: true, + avatar: true, + createdAt: true + } + }) + const nextAvatarSource = resolveAvatarSource(user, updatedIdentities) + if (nextAvatarSource) { + await tx + .update(users) + .set({ + avatarProvider: nextAvatarSource.provider, + avatarProviderUserId: nextAvatarSource.providerUserId + }) + .where(eq(users.id, user.id)) + avatarSourceSet = true + } + } + + return { created, avatarSourceSet } +} diff --git a/server/utils/oauth-providers.ts b/server/utils/oauth-providers.ts new file mode 100644 index 0000000..594754c --- /dev/null +++ b/server/utils/oauth-providers.ts @@ -0,0 +1,126 @@ +export type OAuthProvider = 'github' | 'casdoor' | 'google' | 'oauth2' | 'aggregate' + +export const AGGREGATE_OAUTH_LOGIN_TYPES = [ + 'qq', + 'wx', + 'alipay', + 'sina', + 'baidu', + 'douyin', + 'huawei', + 'xiaomi', + 'gitee', + 'gitea', + 'bilibili', + 'kuaishou' +] as const + +export type AggregateOAuthLoginType = (typeof AGGREGATE_OAUTH_LOGIN_TYPES)[number] + +const isPrivateIPv4 = (hostname: string): boolean => { + const parts = hostname.split('.').map(Number) + if ( + parts.length !== 4 || + parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255) + ) { + return false + } + + const [first, second] = parts + return ( + first === 10 || + first === 127 || + (first === 100 && second >= 64 && second <= 127) || + (first === 169 && second === 254) || + (first === 172 && second >= 16 && second <= 31) || + (first === 192 && second === 168) + ) +} + +const isPrivateIPv6 = (hostname: string): boolean => { + const normalized = hostname.replace(/^\[|\]$/g, '').toLowerCase() + if (!normalized.includes(':')) return false + if (normalized.startsWith('::ffff:')) { + return isPrivateIPv4(normalized.slice('::ffff:'.length)) + } + return ( + normalized === '::1' || + normalized.startsWith('fc') || + normalized.startsWith('fd') || + /^fe[89ab]/.test(normalized) + ) +} + +const isInternalHostname = (hostname: string): boolean => { + const normalized = hostname.toLowerCase() + if (normalized.includes(':')) return isPrivateIPv6(normalized) + if (isPrivateIPv4(normalized)) return true + return ( + normalized === 'localhost' || + !normalized.includes('.') || + normalized.endsWith('.localhost') || + normalized.endsWith('.local') || + normalized.endsWith('.lan') || + normalized.endsWith('.internal') || + normalized.endsWith('.home.arpa') + ) +} + +export const isSafeAggregateOAuthUrl = (value: string): boolean => { + try { + const url = new URL(value) + if (url.username || url.password) return false + if (url.protocol === 'https:') return true + if (url.protocol !== 'http:') return false + return isInternalHostname(url.hostname) + } catch { + return false + } +} + +export const normalizeAggregateOAuthLoginTypes = (value: unknown): AggregateOAuthLoginType[] => { + let values: unknown[] = [] + + if (Array.isArray(value)) { + values = value + } else if (typeof value === 'string' && value.trim()) { + const normalized = value.trim() + try { + const parsed = JSON.parse(normalized) + values = Array.isArray(parsed) ? parsed : [parsed] + } catch { + values = normalized.split(',') + } + } + + return [ + ...new Set( + values + .filter((item): item is string => typeof item === 'string') + .map((item) => item.trim().toLowerCase()) + .filter((item): item is AggregateOAuthLoginType => + AGGREGATE_OAUTH_LOGIN_TYPES.includes(item as AggregateOAuthLoginType) + ) + ) + ] +} + +export const getAggregateOAuthLoginTypesOrDefault = (value: unknown): AggregateOAuthLoginType[] => { + const normalized = normalizeAggregateOAuthLoginTypes(value) + const hasConfiguredValue = + (Array.isArray(value) && value.length > 0) || + (typeof value === 'string' && value.trim().length > 0) + return normalized.length > 0 || hasConfiguredValue ? normalized : ['qq'] +} + +export const SUPPORTED_OAUTH_PROVIDERS: OAuthProvider[] = [ + 'github', + 'casdoor', + 'google', + 'oauth2', + 'aggregate' +] + +export const isSupportedOAuthProvider = (provider: string): provider is OAuthProvider => { + return SUPPORTED_OAUTH_PROVIDERS.includes(provider as OAuthProvider) +} diff --git a/server/utils/oauth-strategies.ts b/server/utils/oauth-strategies.ts index d317281..333c421 100644 --- a/server/utils/oauth-strategies.ts +++ b/server/utils/oauth-strategies.ts @@ -1,4 +1,12 @@ import { createError } from 'h3' +import { createHmac, randomUUID } from 'node:crypto' +import { db } from '~/drizzle/db' +import { systemSettings } from '~/drizzle/schema' +import { asc } from 'drizzle-orm' +import { + isSafeAggregateOAuthUrl, + getAggregateOAuthLoginTypesOrDefault +} from './oauth-providers' export interface OAuthUserInfo { id: string @@ -250,6 +258,139 @@ const strategies: Record = { google: googleStrategy } +async function loadAggregateSettings() { + const row = await db + .select({ + aggregateOAuthEnabled: systemSettings.aggregateOAuthEnabled, + aggregateOAuthAppId: systemSettings.aggregateOAuthAppId, + aggregateOAuthAppKey: systemSettings.aggregateOAuthAppKey, + aggregateOAuthLoginType: systemSettings.aggregateOAuthLoginType, + aggregateOAuthEndpoint: systemSettings.aggregateOAuthEndpoint + }) + .from(systemSettings) + .orderBy(asc(systemSettings.id)) + .limit(1) + return row[0] ?? null +} + +function normalizeEndpoint(endpoint: string): string { + return endpoint.replace(/\/+$/, '') +} + +function aggregateSign(params: Record, appKey: string): string { + const sorted = Object.keys(params) + .filter((k) => params[k] !== undefined && params[k] !== null && params[k] !== '') + .sort() + .map((k) => `${k}=${params[k]}`) + .join('&') + return createHmac('sha256', appKey).update(sorted).digest('hex') +} + +const aggregateStrategy: OAuthStrategy = { + async getAuthorizeUrl(redirectUri: string, state: string) { + const settings = await loadAggregateSettings() + if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) { + throw createError({ statusCode: 500, message: '聚合登录未配置' }) + } + if (!isSafeAggregateOAuthUrl(settings.aggregateOAuthEndpoint)) { + throw createError({ statusCode: 500, message: '聚合登录端点不安全或格式错误' }) + } + + const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType) + const loginType = loginTypes[0] || 'qq' + const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint) + const timestamp = String(Math.floor(Date.now() / 1000)) + const nonce = randomUUID().replace(/-/g, '') + const baseParams: Record = { + app_id: settings.aggregateOAuthAppId, + response_type: 'code', + redirect_uri: redirectUri, + state, + login_type: loginType, + timestamp, + nonce + } + const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey) + const query = new URLSearchParams({ ...baseParams, sign }).toString() + return `${endpoint}/oauth/authorize?${query}` + }, + + async exchangeToken(code: string, redirectUri: string) { + const settings = await loadAggregateSettings() + if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) { + throw createError({ statusCode: 500, message: '聚合登录未配置' }) + } + const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint) + const timestamp = String(Math.floor(Date.now() / 1000)) + const nonce = randomUUID().replace(/-/g, '') + const baseParams: Record = { + app_id: settings.aggregateOAuthAppId, + grant_type: 'authorization_code', + code, + redirect_uri: redirectUri, + timestamp, + nonce + } + const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey) + + try { + const tokenResponse = await $fetch(`${endpoint}/oauth/token`, { + method: 'POST', + body: { ...baseParams, sign }, + headers: { Accept: 'application/json' } + }) + if (tokenResponse.error) { + throw new Error(tokenResponse.error_description || tokenResponse.error || '令牌请求失败') + } + const accessToken = tokenResponse.access_token || tokenResponse.accessToken + if (!accessToken) { + throw new Error('未能获取访问令牌') + } + return accessToken + } catch (e: any) { + console.error('Aggregate OAuth token exchange failed', e) + throw new Error(e.message || '令牌请求失败') + } + }, + + async getUserInfo(accessToken: string) { + const settings = await loadAggregateSettings() + if (!settings?.aggregateOAuthAppId || !settings?.aggregateOAuthAppKey || !settings?.aggregateOAuthEndpoint) { + throw createError({ statusCode: 500, message: '聚合登录未配置' }) + } + const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint) + const timestamp = String(Math.floor(Date.now() / 1000)) + const nonce = randomUUID().replace(/-/g, '') + const baseParams: Record = { + app_id: settings.aggregateOAuthAppId, + access_token: accessToken, + timestamp, + nonce + } + const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey) + + try { + const userInfo = await $fetch(`${endpoint}/oauth/userinfo`, { + method: 'POST', + body: { ...baseParams, sign }, + headers: { Accept: 'application/json' } + }) + return { + id: String(userInfo.id || userInfo.openid || userInfo.sub || userInfo.userId || ''), + username: userInfo.username || userInfo.nickname || userInfo.name || String(userInfo.id || 'user'), + name: userInfo.name || userInfo.nickname || undefined, + email: userInfo.email || undefined, + avatar: userInfo.avatar || userInfo.avatar_url || userInfo.headimgurl || undefined + } + } catch (e: any) { + console.error('Aggregate OAuth user info failed', e) + throw new Error('获取用户信息失败') + } + } +} + +strategies.aggregate = aggregateStrategy + export const getOAuthStrategy = (provider: string): OAuthStrategy => { const strategy = strategies[provider] if (!strategy) { diff --git a/server/utils/redis.ts b/server/utils/redis.ts index c8bb351..f7f6ce7 100644 --- a/server/utils/redis.ts +++ b/server/utils/redis.ts @@ -261,6 +261,12 @@ export const disconnectRedis = () => redisPool.disconnect() export const getRedisClient = () => redisPool.getClient() export const isRedisReady = () => redisPool.isReady() export const getRedisStats = () => redisPool.getStats() + +export const REDIS_KEY_PREFIX = 'voicehub' + +export function buildRedisKey(...segments: string[]): string { + return [REDIS_KEY_PREFIX, ...segments].filter(Boolean).join(':') +} export const executeRedisCommand = (command: () => Promise, fallback?: () => Promise) => redisPool.executeCommand(command, fallback) diff --git a/server/utils/requireSongAdmin.ts b/server/utils/requireSongAdmin.ts new file mode 100644 index 0000000..1a9eeba --- /dev/null +++ b/server/utils/requireSongAdmin.ts @@ -0,0 +1,15 @@ +import { createApiError } from './apiError' +import { SERVER_ERROR_CODES } from '../config/constants' + +const SONG_ADMIN_ROLES = ['SONG_ADMIN', 'ADMIN', 'SUPER_ADMIN'] + +export function requireSongAdmin(event: any) { + const user = event.context?.user + if (!user) { + throw createApiError(401, SERVER_ERROR_CODES.AUTH_UNAUTHORIZED, '请先登录') + } + if (!SONG_ADMIN_ROLES.includes(user.role)) { + throw createApiError(403, SERVER_ERROR_CODES.AUTH_FORBIDDEN, '没有权限执行此操作') + } + return user +} diff --git a/server/utils/schedule-visibility.ts b/server/utils/schedule-visibility.ts new file mode 100644 index 0000000..3412f33 --- /dev/null +++ b/server/utils/schedule-visibility.ts @@ -0,0 +1,52 @@ +export interface ScheduleVisibilityRange { + startAt: Date | null + endAt: Date | null +} + +export interface VisibilitySettingsLike { + scheduleDaysBeforeEnabled?: boolean | null + scheduleDaysBefore?: number | null + scheduleDaysAfterEnabled?: boolean | null + scheduleDaysAfter?: number | null +} + +export function resolveScheduleVisibilityRange( + settings: VisibilitySettingsLike | null | undefined, + referenceDate = new Date() +): ScheduleVisibilityRange { + const today = new Date( + referenceDate.getFullYear(), + referenceDate.getMonth(), + referenceDate.getDate() + ) + + let startAt: Date | null = null + let endAt: Date | null = null + + if (settings?.scheduleDaysBeforeEnabled) { + const days = Math.max(0, Number(settings.scheduleDaysBefore) || 0) + const d = new Date(today) + d.setDate(d.getDate() - days) + startAt = d + } + + if (settings?.scheduleDaysAfterEnabled) { + const days = Math.max(0, Number(settings.scheduleDaysAfter) || 0) + const d = new Date(today) + d.setDate(d.getDate() + days + 1) + endAt = d + } + + return { startAt, endAt } +} + +export function isPlayDateInRange( + playDate: Date | string | null | undefined, + range: ScheduleVisibilityRange +): boolean { + if (!playDate) return true + const d = new Date(playDate) + if (range.startAt && d.getTime() < range.startAt.getTime()) return false + if (range.endAt && d.getTime() >= range.endAt.getTime()) return false + return true +} diff --git a/server/utils/serverTime.ts b/server/utils/serverTime.ts new file mode 100644 index 0000000..d8ac330 --- /dev/null +++ b/server/utils/serverTime.ts @@ -0,0 +1,3 @@ +export function getServerTimestamp(): number { + return Date.now() +} diff --git a/server/utils/submissionNoteAutoModeration.ts b/server/utils/submissionNoteAutoModeration.ts new file mode 100644 index 0000000..ca3e29c --- /dev/null +++ b/server/utils/submissionNoteAutoModeration.ts @@ -0,0 +1,150 @@ +import type { SongBlacklist } from '~/drizzle/schema' + +export type BlacklistType = 'KEYWORD' | 'LANGUAGE' | 'GENRE' | 'SONG' + +export interface ModerationContext { + title?: string | null + artist?: string | null + genre?: string | null +} + +export interface ModerationResult { + notePublic: boolean + publicStatus: 'approved' | 'rejected' | null + rejectedReasons: string[] + matchedRules: { type: BlacklistType; value: string }[] +} + +function escapeRegex(s: string): string { + return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} + +function isCJK(text: string): boolean { + return /[\u4e00-\u9fa5]/.test(text) +} + +function isLatin(text: string): boolean { + return /[A-Za-z]/.test(text) +} + +function isKana(text: string): boolean { + return /[\u3040-\u30ff]/.test(text) +} + +function isHangul(text: string): boolean { + return /[\uac00-\ud7af]/.test(text) +} + +function isCyrillic(text: string): boolean { + return /[\u0400-\u04ff]/.test(text) +} + +function isArabic(text: string): boolean { + return /[\u0600-\u06ff]/.test(text) +} + +function detectLanguages(text: string): string[] { + const result: string[] = [] + if (!text) return result + const normalized = text.toLowerCase() + if (isCJK(text)) result.push('zh', '中文', 'chinese', 'cjk') + if (isLatin(text)) result.push('en', '英文', 'english', 'latin') + if (isKana(text)) result.push('ja', '日文', 'japanese') + if (isHangul(text)) result.push('ko', '韩文', 'korean') + if (isCyrillic(text)) result.push('ru', '俄文', 'russian', 'cyrillic') + if (isArabic(text)) result.push('ar', '阿拉伯文', 'arabic') + return result +} + +export function moderateSubmissionNote( + note: string | null, + wantPublic: boolean, + requiresApproval: boolean, + song: ModerationContext, + blacklistRows: SongBlacklist[] +): ModerationResult { + if (!note || !wantPublic) { + return { + notePublic: wantPublic && !!note, + publicStatus: null, + rejectedReasons: [], + matchedRules: [] + } + } + + const noteLower = note.toLowerCase() + const noteForKeyword = note.toLowerCase() + const title = (song.title || '').toLowerCase() + const artist = (song.artist || '').toLowerCase() + const genre = (song.genre || '').toLowerCase() + + const rejectedReasons: string[] = [] + const matchedRules: { type: BlacklistType; value: string }[] = [] + + const noteLanguages = detectLanguages(note) + const textLanguages = new Set([ + ...noteLanguages, + ...detectLanguages(song.title || ''), + ...detectLanguages(song.artist || ''), + ...detectLanguages(song.genre || '') + ]) + + for (const row of blacklistRows) { + const t = row.type as BlacklistType + const rawValue = row.value + if (!rawValue) continue + const value = rawValue.trim() + if (!value) continue + const valueLower = value.toLowerCase() + + if (t === 'KEYWORD') { + // 命中 note / title / artist / genre 的其中一个都算 + const haystacks = [noteForKeyword, title, artist, genre].filter(Boolean) as string[] + const exact = haystacks.some((h) => h.includes(valueLower)) + const asRegex = (() => { + try { + const re = new RegExp(escapeRegex(value), 'i') + return haystacks.some((h) => re.test(h)) + } catch (_) { + return false + } + })() + if (exact || asRegex) { + matchedRules.push({ type: t, value }) + rejectedReasons.push(`命中敏感词:${value}`) + } + } else if (t === 'LANGUAGE') { + const v = valueLower + const checkList = [ + v, + ...v.split(/[,,\/|\s]+/).map((s) => s.trim()).filter(Boolean) + ] + const hit = checkList.some((lang) => textLanguages.has(lang)) + if (hit) { + matchedRules.push({ type: t, value }) + rejectedReasons.push(`命中语言限制:${value}`) + } + } else if (t === 'GENRE') { + // 匹配流派:genre 字段或 note/title/artist 中的流派关键词 + const combinedForGenre = `${genre} ${noteForKeyword} ${title} ${artist}`.trim() + if (!combinedForGenre) continue + const tokens = valueLower.split(/[,,\/|\s]+/).map((s) => s.trim()).filter(Boolean) + const hit = tokens.some((tok) => combinedForGenre.includes(tok)) + if (hit) { + matchedRules.push({ type: t, value }) + rejectedReasons.push(`命中流派限制:${value}`) + } + } else { + // SONG 不参与 note 审查 + continue + } + } + + const rejected = matchedRules.length > 0 + return { + notePublic: rejected ? false : (requiresApproval ? false : wantPublic), + publicStatus: requiresApproval || matchedRules.length > 0 ? (rejected ? 'rejected' : 'approved') : null, + rejectedReasons, + matchedRules + } +} diff --git a/server/utils/system-settings-defaults.ts b/server/utils/system-settings-defaults.ts new file mode 100644 index 0000000..7946b9e --- /dev/null +++ b/server/utils/system-settings-defaults.ts @@ -0,0 +1,70 @@ +export const SYSTEM_SETTINGS_DEFAULTS = { + siteTitle: '校园广播站点歌系统', + siteVersion: '1.7.1.0', + enableSubmissionLimit: false, + showBlacklistKeywords: false, + hideStudentInfo: true, + smtpEnabled: false, + smtpPort: 587, + smtpSecure: false, + smtpFromName: '校园广播站', + enableRequestTimeLimitation: false, + forceBlockAllRequests: false, + enableReplayRequests: false, + enableCollaborativeSubmission: true, + enableSubmissionRemarks: false, + submissionNoteRequiresApproval: false, + telemetryEnabled: true, + showBeianIcon: true, + scheduleDaysDisplay: 7, + scheduleDaysEditable: 3, + scheduleDaysRequestable: 14, + scheduleDaysBeforeEnabled: false, + scheduleDaysBefore: 1, + scheduleDaysAfterEnabled: false, + scheduleDaysAfter: 1, + forcePasswordChangeOnFirstLogin: false, + enableSubmissionRestriction: false, + submissionRestrictionScope: 'all', + cardCodeEnabled: false, + cardCodeSubmissionRequired: false, + cardCodeVoteEnabled: false, + cardCodeReplayEnabled: false, + enableCardCodeRequests: false, + requireCardCodeForRequests: false, + enableCardCodeLimitBypass: false, + submissionRestrictionEnabled: false, + submissionRestrictionGradeEnabled: false, + submissionRestrictionClassEnabled: false, + submissionRestrictionGraduateEnabled: false, + submissionRestrictionWithdrawnEnabled: false, + captchaProvider: 'TURNSTILE', + captchaEnabled: false, + allowRegister: true, + registerRequireEmail: false, + registerRequireEmailVerify: false, + registerDefaultRole: 'USER', + registerRequiresApproval: false, + oauthRegisterRequiresApproval: false, + registerEmailRequired: false, + registerRequiresGradeClass: false, + oauthEnabled: false, + oauthAllowRegister: true, + oauthAllowLogin: true, + oauthAllowBind: true, + allowOAuthRegistration: false, + oauthProviders: '[]', + githubOAuthEnabled: false, + casdoorOAuthEnabled: false, + googleOAuthEnabled: false, + aggregateOAuthEnabled: false, + aggregateOAuthLoginType: 'qq', + customOAuthEnabled: false, + captchaMaxFailures: 3, + autoBackupEnabled: false, + autoBackupIntervalHours: 24, + autoBackupRetentionDays: 30, + statisticsCodeEnabled: false, + defaultTheme: 'System', + enabledThemes: '["System","ClassicDark","ClassicLight","ModernLight"]' +} as const diff --git a/server/utils/user-agent-info.ts b/server/utils/user-agent-info.ts new file mode 100644 index 0000000..e33f3e9 --- /dev/null +++ b/server/utils/user-agent-info.ts @@ -0,0 +1,71 @@ +export interface UserAgentInfo { + browser: string | null + operatingSystem: string | null + device: string | null +} + +const BROWSER_PATTERNS: Array<[RegExp, string]> = [ + [/Edg\//i, 'Microsoft Edge'], + [/OPR\//i, 'Opera'], + [/Chrome\//i, 'Chrome'], + [/Safari\//i, 'Safari'], + [/Firefox\//i, 'Firefox'], + [/MSIE |Trident\//i, 'Internet Explorer'] +] + +const OS_PATTERNS: Array<[RegExp, string]> = [ + [/Windows NT 10\.0/i, 'Windows 10/11'], + [/Windows NT 6\.3/i, 'Windows 8.1'], + [/Windows NT 6\.2/i, 'Windows 8'], + [/Windows NT 6\.1/i, 'Windows 7'], + [/Windows/i, 'Windows'], + [/Mac OS X ([\d_.]+)/i, 'macOS'], + [/iPhone OS ([\d_]+)/i, 'iOS'], + [/iPad.*CPU OS ([\d_]+)/i, 'iPadOS'], + [/Android ([\d.]+)/i, 'Android'], + [/Linux/i, 'Linux'] +] + +const DEVICE_PATTERNS: Array<[RegExp, string]> = [ + [/iPhone/i, 'iPhone'], + [/iPad/i, 'iPad'], + [/Android.*Mobile/i, 'Android Phone'], + [/Android/i, 'Android Tablet'], + [/Windows Phone/i, 'Windows Phone'], + [/Macintosh/i, 'Mac'], + [/Windows/i, 'Windows PC'], + [/Linux/i, 'Linux PC'] +] + +export function parseUserAgent(userAgent: string | null | undefined): UserAgentInfo { + const ua = (userAgent ?? '').trim() + if (!ua) return { browser: null, operatingSystem: null, device: null } + + let browser: string | null = null + for (const [regex, name] of BROWSER_PATTERNS) { + if (regex.test(ua)) { + browser = name + break + } + } + + let operatingSystem: string | null = null + for (const [regex, name] of OS_PATTERNS) { + if (regex.test(ua)) { + operatingSystem = name + break + } + } + + let device: string | null = null + for (const [regex, name] of DEVICE_PATTERNS) { + if (regex.test(ua)) { + device = name + break + } + } + + return { browser, operatingSystem, device } +} + +export type LoginMethod = 'password' | 'oauth' | 'webauthn' | 'totp_2fa' | 'email_2fa' diff --git a/server/utils/user-avatar.ts b/server/utils/user-avatar.ts new file mode 100644 index 0000000..de76771 --- /dev/null +++ b/server/utils/user-avatar.ts @@ -0,0 +1,45 @@ +interface AvatarUserState { + avatarProvider?: string | null + avatarProviderUserId?: string | null +} + +interface IdentityRow { + provider: string + providerUserId: string + avatar?: string | null + createdAt: Date | string +} + +export interface AvatarSource { + provider: string | null + providerUserId: string | null +} + +export function resolveAvatarSource( + user: AvatarUserState, + identities: IdentityRow[] +): AvatarSource | null { + if (user.avatarProvider) { + return { + provider: user.avatarProvider, + providerUserId: user.avatarProviderUserId ?? null + } + } + + const sorted = [...identities].sort((a, b) => { + const at = new Date(a.createdAt).getTime() + const bt = new Date(b.createdAt).getTime() + return at - bt + }) + + for (const identity of sorted) { + if (identity.avatar) { + return { + provider: identity.provider, + providerUserId: identity.providerUserId + } + } + } + + return null +}