diff --git a/.env.example b/.env.example index ecd00c857..13cf0ae81 100644 --- a/.env.example +++ b/.env.example @@ -14,6 +14,7 @@ BOT_TOKEN= # For production, change localhost:3300 to your domain. DASHBOARD_URL=https://localhost:3300 API_URL=https://localhost:3300/api +PORTAL_URL=https://localhost:3400 # Comma-separated list of user IDs who should have access to the bot's global commands STAFF= @@ -32,9 +33,16 @@ DEFAULT_ALLOWED_SERVERS= # NOTE: You only need to fill in these values for running the development environment # ========================== +# Host to bind the various exposed devenv ports on +# The default value of "127.0.0.1" only allows access from the local machine +DEVELOPMENT_BIND_HOST=127.0.0.1 + +# Legacy dashboard port DEVELOPMENT_WEB_PORT=3300 +# Modern portal port +DEVELOPMENT_PORTAL_PORT=3400 -# The MySQL database running in the container is exposed to the host on this port, +# The MySQL database running in the container is exposed on this port, # allowing access with database tools such as DBeaver DEVELOPMENT_MYSQL_PORT=3356 # Password for the Zeppelin database user @@ -43,10 +51,14 @@ DEVELOPMENT_MYSQL_PASSWORD=password DEVELOPMENT_MYSQL_ROOT_PASSWORD=password # The development environment container has an SSH server that you can connect to. -# This is the port that server is exposed to the host on. +# This is the port that server is exposed on. DEVELOPMENT_SSH_PORT=3022 DEVELOPMENT_SSH_PASSWORD=password +# If you're accessing the Vite devserver for the portal using a domain rather than IP, add it here. +# Multiple domains supported when separated by commas. +DEVELOPMENT_VITE_ALLOWED_HOSTS= + # If using the cftunnel docker compose profile, set your Cloudflare Tunnel token here #CF_TUNNEL_TOKEN= diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 33fcf9575..79ccd6a19 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -1,5 +1,5 @@ { "$schema": "./node_modules/oxfmt/configuration_schema.json", - "ignorePatterns": ["dist/**", "*.min.js", "*.yml", "*.yaml", "*.json", "LICENSE.md"], + "ignorePatterns": ["**/dist/**", "**/*.min.js", "**/*.yml", "**/*.yaml", "**/*.json", "**/LICENSE.md", "**/.adonisjs/**", "public/assets/**", "**/*.md"], "printWidth": 120 } diff --git a/.oxlintrc.json b/.oxlintrc.json index fc705770e..33b8b5b02 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,6 +1,6 @@ { "$schema": "./node_modules/oxlint/configuration_schema.json", - "ignorePatterns": ["dist/**", "*.min.js", "dashboard/src/**"], + "ignorePatterns": ["**/dist/**", "*.min.js", "dashboard/src/**", "**/.adonisjs/**", "public/assets/**"], "plugins": [ "typescript", "unicorn", @@ -13,4 +13,4 @@ "env": { "builtin": true } -} \ No newline at end of file +} diff --git a/Dockerfile b/Dockerfile index c61e2d3a7..b685fc1dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,10 +21,12 @@ COPY --from=prod-deps /zeppelin/node_modules /zeppelin/node_modules COPY --from=prod-deps /zeppelin/backend/node_modules /zeppelin/backend/node_modules #COPY --from=prod-deps /zeppelin/shared/node_modules /zeppelin/shared/node_modules # No prod deps in shared COPY --from=prod-deps /zeppelin/dashboard/node_modules /zeppelin/dashboard/node_modules +COPY --from=prod-deps /zeppelin/portal/node_modules /zeppelin/portal/node_modules COPY --from=build /zeppelin/backend/dist /zeppelin/backend/dist COPY --from=build /zeppelin/shared/dist /zeppelin/shared/dist COPY --from=build /zeppelin/dashboard/dist /zeppelin/dashboard/dist +COPY --from=build /zeppelin/portal/build /zeppelin/portal/build # Add version info RUN echo "${COMMIT_HASH}" > /zeppelin/.commit-hash diff --git a/assets/squiggle2.afdesign b/assets/squiggle2.afdesign new file mode 100644 index 000000000..e8e1f16ec Binary files /dev/null and b/assets/squiggle2.afdesign differ diff --git a/backend/package.json b/backend/package.json index ccbb1f101..c3ab5b713 100644 --- a/backend/package.json +++ b/backend/package.json @@ -22,6 +22,7 @@ "migrate-rollback-dev": "pnpm run build && pnpm run migrate-rollback", "validate-active-configs": "node --enable-source-maps dist/validateActiveConfigs.js > ../config-errors.txt", "export-config-json-schema": "node --enable-source-maps dist/exportSchemas.js ../config-checker/public/config-schema.json", + "export-docs-data": "node --enable-source-maps dist/exportDocsData.js ../shared/src/docsData.json", "test": "pnpm run build && pnpm run run-tests", "run-tests": "ava" }, @@ -85,6 +86,12 @@ "ts-toolbelt": "^9.6.0", "typescript": "catalog:ts7" }, + "exports": { + "./*.js": { + "types": "./dist/*.d.ts", + "default": "./dist/*.js" + } + }, "ava": { "files": [ "dist/**/*.test.js" diff --git a/backend/src/exportDocsData.ts b/backend/src/exportDocsData.ts new file mode 100644 index 000000000..770d1a74a --- /dev/null +++ b/backend/src/exportDocsData.ts @@ -0,0 +1,37 @@ +import z from "zod"; +import { availableGlobalPlugins, availableGuildPlugins } from "./plugins/availablePlugins.js"; +import { ZeppelinPluginDocs } from "./types.js"; +import { writeFileSync } from "node:fs"; +import { GlobalPluginBlueprint, GuildPluginBlueprint } from "vety"; + +import type { ZeppelinPluginDocsData, ZeppelinDocsData } from "@zeppelinbot/shared/docsDataTypes.js"; + +const outputPath = process.argv[2]; +if (!outputPath) { + console.error("Output dir required"); + process.exit(1); +} + +function pluginToDocsData( + plugin: GuildPluginBlueprint | GlobalPluginBlueprint, + docs: ZeppelinPluginDocs, +): ZeppelinPluginDocsData { + return { + name: plugin.name, + prettyName: docs.prettyName ?? plugin.name, + type: docs.type, + description: docs.description, + usageGuide: docs.usageGuide, + configurationGuide: docs.configurationGuide, + configJsonSchema: z.toJSONSchema(docs.configSchema, { io: "input", cycles: "ref" }), + }; +} + +const docsData: ZeppelinDocsData = { + guildPlugins: availableGuildPlugins.map(({ plugin, docs }) => pluginToDocsData(plugin, docs)), + globalPlugins: availableGlobalPlugins.map(({ plugin, docs }) => pluginToDocsData(plugin, docs)), +}; + +writeFileSync(outputPath, JSON.stringify(docsData), { encoding: "utf8" }); + +process.exit(0); diff --git a/backend/src/exportSchemas.ts b/backend/src/exportSchemas.ts index dbe50eb46..7311cde9c 100644 --- a/backend/src/exportSchemas.ts +++ b/backend/src/exportSchemas.ts @@ -3,25 +3,7 @@ import { z } from "zod"; import { availableGuildPlugins } from "./plugins/availablePlugins.js"; import { zZeppelinGuildConfig } from "./types.js"; import { JSONSchema } from "zod/v4/core"; - -function makeJsonSchemaDeepPartial(schema: Record) { - if (schema.type === "object") { - delete schema.required; - } - for (const value of Object.values(schema)) { - if (value && typeof value === "object") { - if (Array.isArray(value)) { - for (const item of value) { - if (item && typeof item === "object") { - makeJsonSchemaDeepPartial(item); - } - } - } else { - makeJsonSchemaDeepPartial(value); - } - } - } -} +import { makeJsonSchemaDeepPartial } from "./utils/makeJsonSchemaDeepPartial.js"; const basePluginOverrideCriteriaSchema = z.strictObject({ channel: z diff --git a/backend/src/migrations/1792935256055-CreatePortalUsersTable.ts b/backend/src/migrations/1792935256055-CreatePortalUsersTable.ts new file mode 100644 index 000000000..defcc1364 --- /dev/null +++ b/backend/src/migrations/1792935256055-CreatePortalUsersTable.ts @@ -0,0 +1,54 @@ +import { MigrationInterface, QueryRunner, Table } from "typeorm"; + +export class CreatePortalUsersTable1792935256055 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: "portal_users", + columns: [ + { + name: "id", + type: "int", + isPrimary: true, + isGenerated: true, + generationStrategy: "increment", + }, + { + name: "discord_user_id", + type: "bigint", + }, + { + name: "discord_username", + type: "varchar", + length: "255", + }, + { + name: "discord_avatar_url", + type: "varchar", + length: "255", + isNullable: true, + }, + { + name: "last_login_at", + type: "datetime", + }, + { + name: "created_at", + type: "datetime", + default: "CURRENT_TIMESTAMP", + }, + ], + indices: [ + { + columnNames: ["discord_user_id"], + isUnique: true, + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("portal_users"); + } +} diff --git a/backend/src/plugins/AutoDelete/AutoDeletePlugin.ts b/backend/src/plugins/AutoDelete/AutoDeletePlugin.ts index 7c24a91b5..43f4e3e09 100644 --- a/backend/src/plugins/AutoDelete/AutoDeletePlugin.ts +++ b/backend/src/plugins/AutoDelete/AutoDeletePlugin.ts @@ -7,11 +7,12 @@ import { AutoDeletePluginType, zAutoDeleteConfig } from "./types.js"; import { onMessageCreate } from "./util/onMessageCreate.js"; import { onMessageDelete } from "./util/onMessageDelete.js"; import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const AutoDeletePlugin = guildPlugin()({ name: "auto_delete", - dependencies: () => [TimeAndDatePlugin, LogsPlugin], + dependencies: () => [TimeAndDatePlugin, LogsPlugin, MessageSaverPlugin], configSchema: zAutoDeleteConfig, beforeLoad(pluginData) { diff --git a/backend/src/plugins/AutoReactions/AutoReactionsPlugin.ts b/backend/src/plugins/AutoReactions/AutoReactionsPlugin.ts index 226e5b3ec..f4172f18c 100644 --- a/backend/src/plugins/AutoReactions/AutoReactionsPlugin.ts +++ b/backend/src/plugins/AutoReactions/AutoReactionsPlugin.ts @@ -7,6 +7,7 @@ import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd.js"; import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd.js"; import { AddReactionsEvt } from "./events/AddReactionsEvt.js"; import { AutoReactionsPluginType, zAutoReactionsConfig } from "./types.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; const defaultOverrides: Array> = [ { @@ -23,6 +24,7 @@ export const AutoReactionsPlugin = guildPlugin()({ // prettier-ignore dependencies: () => [ LogsPlugin, + MessageSaverPlugin, ], configSchema: zAutoReactionsConfig, diff --git a/backend/src/plugins/Automod/AutomodPlugin.ts b/backend/src/plugins/Automod/AutomodPlugin.ts index ca8bc3ec2..75350cd2f 100644 --- a/backend/src/plugins/Automod/AutomodPlugin.ts +++ b/backend/src/plugins/Automod/AutomodPlugin.ts @@ -34,6 +34,7 @@ import { clearOldRecentActions } from "./functions/clearOldRecentActions.js"; import { clearOldRecentSpam } from "./functions/clearOldRecentSpam.js"; import { AutomodPluginType, zAutomodConfig } from "./types.js"; import { DebugAutomodCmd } from "./commands/DebugAutomodCmd.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const AutomodPlugin = guildPlugin()({ name: "automod", @@ -47,6 +48,7 @@ export const AutomodPlugin = guildPlugin()({ PhishermanPlugin, InternalPosterPlugin, RoleManagerPlugin, + MessageSaverPlugin, ], configSchema: zAutomodConfig, diff --git a/backend/src/plugins/Censor/CensorPlugin.ts b/backend/src/plugins/Censor/CensorPlugin.ts index 114032a39..7dc213a88 100644 --- a/backend/src/plugins/Censor/CensorPlugin.ts +++ b/backend/src/plugins/Censor/CensorPlugin.ts @@ -6,6 +6,7 @@ import { LogsPlugin } from "../Logs/LogsPlugin.js"; import { CensorPluginType, zCensorConfig } from "./types.js"; import { onMessageCreate } from "./util/onMessageCreate.js"; import { onMessageUpdate } from "./util/onMessageUpdate.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; const defaultOverrides: Array> = [ { @@ -24,7 +25,7 @@ const defaultOverrides: Array> = [ export const CensorPlugin = guildPlugin()({ name: "censor", - dependencies: () => [LogsPlugin], + dependencies: () => [LogsPlugin, MessageSaverPlugin], configSchema: zCensorConfig, defaultOverrides, diff --git a/backend/src/plugins/Logs/LogsPlugin.ts b/backend/src/plugins/Logs/LogsPlugin.ts index 573d6926f..49e5641f2 100644 --- a/backend/src/plugins/Logs/LogsPlugin.ts +++ b/backend/src/plugins/Logs/LogsPlugin.ts @@ -108,6 +108,7 @@ import { logVoiceChannelForceMove } from "./logFunctions/logVoiceChannelForceMov import { logVoiceChannelJoin } from "./logFunctions/logVoiceChannelJoin.js"; import { logVoiceChannelLeave } from "./logFunctions/logVoiceChannelLeave.js"; import { logVoiceChannelMove } from "./logFunctions/logVoiceChannelMove.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; // The `any` cast here is to prevent TypeScript from locking up from the circular dependency function getCasesPlugin(): Promise { @@ -117,7 +118,12 @@ function getCasesPlugin(): Promise { export const LogsPlugin = guildPlugin()({ name: "logs", - dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin], + dependencies: async () => [ + TimeAndDatePlugin, + InternalPosterPlugin, + (await getCasesPlugin()).CasesPlugin, + MessageSaverPlugin, + ], configSchema: zLogsConfig, defaultOverrides: [ { diff --git a/backend/src/plugins/Post/PostPlugin.ts b/backend/src/plugins/Post/PostPlugin.ts index 8b2c7e4cb..27c509c2c 100644 --- a/backend/src/plugins/Post/PostPlugin.ts +++ b/backend/src/plugins/Post/PostPlugin.ts @@ -15,11 +15,12 @@ import { ScheduledPostsListCmd } from "./commands/ScheduledPostsListCmd.js"; import { ScheduledPostsShowCmd } from "./commands/ScheduledPostsShowCmd.js"; import { PostPluginType, zPostConfig } from "./types.js"; import { postScheduledPost } from "./util/postScheduledPost.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const PostPlugin = guildPlugin()({ name: "post", - dependencies: () => [TimeAndDatePlugin, LogsPlugin], + dependencies: () => [TimeAndDatePlugin, LogsPlugin, MessageSaverPlugin], configSchema: zPostConfig, defaultOverrides: [ { diff --git a/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts b/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts index 006ca85f9..9fd08af87 100644 --- a/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts +++ b/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts @@ -10,11 +10,12 @@ import { RefreshReactionRolesCmd } from "./commands/RefreshReactionRolesCmd.js"; import { AddReactionRoleEvt } from "./events/AddReactionRoleEvt.js"; import { MessageDeletedEvt } from "./events/MessageDeletedEvt.js"; import { ReactionRolesPluginType, zReactionRolesConfig } from "./types.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const ReactionRolesPlugin = guildPlugin()({ name: "reaction_roles", - dependencies: () => [LogsPlugin], + dependencies: () => [LogsPlugin, MessageSaverPlugin], configSchema: zReactionRolesConfig, defaultOverrides: [ { diff --git a/backend/src/plugins/Slowmode/SlowmodePlugin.ts b/backend/src/plugins/Slowmode/SlowmodePlugin.ts index 8965efc23..4636ab73a 100644 --- a/backend/src/plugins/Slowmode/SlowmodePlugin.ts +++ b/backend/src/plugins/Slowmode/SlowmodePlugin.ts @@ -13,6 +13,7 @@ import { SlowmodeSetCmd } from "./commands/SlowmodeSetCmd.js"; import { SlowmodePluginType, zSlowmodeConfig } from "./types.js"; import { clearExpiredSlowmodes } from "./util/clearExpiredSlowmodes.js"; import { onMessageCreate } from "./util/onMessageCreate.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; const BOT_SLOWMODE_CLEAR_INTERVAL = 60 * SECONDS; @@ -22,6 +23,7 @@ export const SlowmodePlugin = guildPlugin()({ // prettier-ignore dependencies: () => [ LogsPlugin, + MessageSaverPlugin, ], configSchema: zSlowmodeConfig, diff --git a/backend/src/plugins/Spam/SpamPlugin.ts b/backend/src/plugins/Spam/SpamPlugin.ts index e067a5ec1..129334b96 100644 --- a/backend/src/plugins/Spam/SpamPlugin.ts +++ b/backend/src/plugins/Spam/SpamPlugin.ts @@ -8,11 +8,12 @@ import { SpamVoiceStateUpdateEvt } from "./events/SpamVoiceEvt.js"; import { SpamPluginType, zSpamConfig } from "./types.js"; import { clearOldRecentActions } from "./util/clearOldRecentActions.js"; import { onMessageCreate } from "./util/onMessageCreate.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const SpamPlugin = guildPlugin()({ name: "spam", - dependencies: () => [LogsPlugin], + dependencies: () => [LogsPlugin, MessageSaverPlugin], configSchema: zSpamConfig, defaultOverrides: [ { diff --git a/backend/src/plugins/Starboard/StarboardPlugin.ts b/backend/src/plugins/Starboard/StarboardPlugin.ts index 12302f4df..e0c56fba8 100644 --- a/backend/src/plugins/Starboard/StarboardPlugin.ts +++ b/backend/src/plugins/Starboard/StarboardPlugin.ts @@ -8,10 +8,13 @@ import { StarboardReactionAddEvt } from "./events/StarboardReactionAddEvt.js"; import { StarboardReactionRemoveAllEvt, StarboardReactionRemoveEvt } from "./events/StarboardReactionRemoveEvts.js"; import { StarboardPluginType, zStarboardConfig } from "./types.js"; import { onMessageDelete } from "./util/onMessageDelete.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const StarboardPlugin = guildPlugin()({ name: "starboard", + dependencies: () => [MessageSaverPlugin], + configSchema: zStarboardConfig, defaultOverrides: [ { diff --git a/backend/src/plugins/Tags/TagsPlugin.ts b/backend/src/plugins/Tags/TagsPlugin.ts index 23552fcda..b6a2ffae8 100644 --- a/backend/src/plugins/Tags/TagsPlugin.ts +++ b/backend/src/plugins/Tags/TagsPlugin.ts @@ -21,11 +21,12 @@ import { findTagByName } from "./util/findTagByName.js"; import { onMessageCreate } from "./util/onMessageCreate.js"; import { onMessageDelete } from "./util/onMessageDelete.js"; import { renderTagBody } from "./util/renderTagBody.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const TagsPlugin = guildPlugin()({ name: "tags", - dependencies: () => [LogsPlugin], + dependencies: () => [LogsPlugin, MessageSaverPlugin], configSchema: zTagsConfig, defaultOverrides: [ { diff --git a/backend/src/plugins/Utility/UtilityPlugin.ts b/backend/src/plugins/Utility/UtilityPlugin.ts index fb260979a..e1d8702d1 100644 --- a/backend/src/plugins/Utility/UtilityPlugin.ts +++ b/backend/src/plugins/Utility/UtilityPlugin.ts @@ -45,11 +45,12 @@ import { hasPermission } from "./functions/hasPermission.js"; import { activeReloads } from "./guildReloads.js"; import { refreshMembersIfNeeded } from "./refreshMembers.js"; import { UtilityPluginType, zUtilityConfig } from "./types.js"; +import { MessageSaverPlugin } from "../MessageSaver/MessageSaverPlugin.js"; export const UtilityPlugin = guildPlugin()({ name: "utility", - dependencies: () => [TimeAndDatePlugin, ModActionsPlugin, LogsPlugin], + dependencies: () => [TimeAndDatePlugin, ModActionsPlugin, LogsPlugin, MessageSaverPlugin], configSchema: zUtilityConfig, defaultOverrides: [ diff --git a/backend/src/plugins/availablePlugins.ts b/backend/src/plugins/availablePlugins.ts index d326fd394..53d67c444 100644 --- a/backend/src/plugins/availablePlugins.ts +++ b/backend/src/plugins/availablePlugins.ts @@ -148,7 +148,6 @@ export const availableGuildPlugins: ZeppelinGuildPluginInfo[] = [ { plugin: MessageSaverPlugin, docs: messageSaverPluginDocs, - autoload: true, }, { plugin: ModActionsPlugin, diff --git a/backend/src/utils/makeJsonSchemaDeepPartial.ts b/backend/src/utils/makeJsonSchemaDeepPartial.ts new file mode 100644 index 000000000..b59413961 --- /dev/null +++ b/backend/src/utils/makeJsonSchemaDeepPartial.ts @@ -0,0 +1,18 @@ +export function makeJsonSchemaDeepPartial(schema: Record) { + if (schema.type === "object") { + delete schema.required; + } + for (const value of Object.values(schema)) { + if (value && typeof value === "object") { + if (Array.isArray(value)) { + for (const item of value) { + if (item && typeof item === "object") { + makeJsonSchemaDeepPartial(item); + } + } + } else { + makeJsonSchemaDeepPartial(value); + } + } + } +} diff --git a/dashboard/public/env.js b/dashboard/public/env.js index cf4a9404e..ff5264268 100644 --- a/dashboard/public/env.js +++ b/dashboard/public/env.js @@ -1,2 +1,9 @@ // Don't edit this directly, it uses env vars in prod via serve.js +// These are dev values window.API_URL = "/api"; +(() => { + const url = new URL("/", window.location.href); + url.port = 3400; + window.PORTAL_URL = url.href.replace(/\/$/, ""); +})(); +window.USE_PORTAL_PRIVACY_POLICY = true; diff --git a/dashboard/serve.js b/dashboard/serve.js index 0fbf58ab4..fdcbaaf8a 100644 --- a/dashboard/serve.js +++ b/dashboard/serve.js @@ -10,7 +10,14 @@ const fastify = Fastify({ fastify.addHook("preHandler", (req, reply, done) => { if (req.url === "/env.js") { reply.header("Content-Type", "application/javascript; charset=utf8"); - reply.send(`window.API_URL = ${JSON.stringify(process.env.API_URL)};`); + const vars = [ + `window.API_URL = ${JSON.stringify(process.env.API_URL)};`, + ]; + if (process.env.PORTAL_URL) { + vars.push(`window.PORTAL_URL = ${JSON.stringify(process.env.PORTAL_URL)};`); + vars.push(`window.USE_PORTAL_PRIVACY_POLICY = ${process.env.USE_PORTAL_PRIVACY_POLICY === "1" ? "true" : "false"};`); + } + reply.send(vars.join("\n")); } done(); }); diff --git a/dashboard/src/routes.ts b/dashboard/src/routes.ts index 96f8d5243..ad29993f7 100644 --- a/dashboard/src/routes.ts +++ b/dashboard/src/routes.ts @@ -14,6 +14,12 @@ export const router = createRouter({ { path: "/privacy-policy", component: () => import("./components/PrivacyPolicy.vue"), + beforeEnter: () => { + if (window.USE_PORTAL_PRIVACY_POLICY) { + window.location.replace(`${window.PORTAL_URL}/privacy-policy`); + return false; + } + }, }, // Docs diff --git a/dashboard/src/vite-env.d.ts b/dashboard/src/vite-env.d.ts index c8504cdfa..4c6cca3a1 100644 --- a/dashboard/src/vite-env.d.ts +++ b/dashboard/src/vite-env.d.ts @@ -7,4 +7,6 @@ declare module "*.html" { interface Window { API_URL: string; + PORTAL_URL: string; + USE_PORTAL_PRIVACY_POLICY?: boolean; } diff --git a/docker-compose.development.yml b/docker-compose.development.yml index fb1c9dec8..78b09b00d 100644 --- a/docker-compose.development.yml +++ b/docker-compose.development.yml @@ -5,31 +5,44 @@ volumes: untrusted-home: {} mysql-data: {} redis-data: {} + caddy-data: {} services: - nginx: - build: - context: ./docker/development/nginx - args: - DEVELOPMENT_WEB_PORT: ${DEVELOPMENT_WEB_PORT:?Missing DEVELOPMENT_WEB_PORT} + caddy: + image: caddy:2 + pull_policy: daily ports: - - "${DEVELOPMENT_WEB_PORT:?Missing DEVELOPMENT_WEB_PORT}:443" + - "${DEVELOPMENT_BIND_HOST:-127.0.0.1}:${DEVELOPMENT_WEB_PORT:?Missing DEVELOPMENT_WEB_PORT}:443" + - "${DEVELOPMENT_BIND_HOST:-127.0.0.1}:${DEVELOPMENT_PORTAL_PORT:?Missing DEVELOPMENT_PORTAL_PORT}:444" + volumes: + - ./docker/development/caddy/config:/etc/caddy + - caddy-data:/data + # Mount host tailscale dir for tailscale cert support + # Creates an empty dir on host if it doesn't already exist + # Probably doesn't work on Windows but who cares + - type: bind + source: /var/run/tailscale + target: /var/run/tailscale + read_only: true + bind: + create_host_path: true mysql: - image: mysql:8.0 + image: mysql:8 + pull_policy: daily environment: MYSQL_ROOT_PASSWORD: ${DEVELOPMENT_MYSQL_ROOT_PASSWORD?:Missing DEVELOPMENT_MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: zeppelin MYSQL_USER: zeppelin MYSQL_PASSWORD: ${DEVELOPMENT_MYSQL_PASSWORD?:Missing DEVELOPMENT_MYSQL_PASSWORD} ports: - - "127.0.0.1:${DEVELOPMENT_MYSQL_PORT:?Missing DEVELOPMENT_MYSQL_PORT}:3306" + - "${DEVELOPMENT_BIND_HOST:-127.0.0.1}:${DEVELOPMENT_MYSQL_PORT:?Missing DEVELOPMENT_MYSQL_PORT}:3306" volumes: - mysql-data:/var/lib/mysql - command: --authentication-policy=mysql_native_password redis: - image: redis:8.2.3 + image: redis:8 + pull_policy: daily volumes: - redis-data:/data @@ -40,7 +53,7 @@ services: environment: DEVELOPMENT_SSH_PASSWORD: ${DEVELOPMENT_SSH_PASSWORD:?Missing DEVELOPMENT_SSH_PASSWORD} ports: - - "127.0.0.1:${DEVELOPMENT_SSH_PORT:?Missing DEVELOPMENT_SSH_PORT}:22" + - "${DEVELOPMENT_BIND_HOST:-127.0.0.1}:${DEVELOPMENT_SSH_PORT:?Missing DEVELOPMENT_SSH_PORT}:22" volumes: - home:/home/dev - ./:/workspace/zeppelin diff --git a/docker/development/caddy/config/Caddyfile b/docker/development/caddy/config/Caddyfile new file mode 100644 index 000000000..f94316677 --- /dev/null +++ b/docker/development/caddy/config/Caddyfile @@ -0,0 +1,30 @@ +# Dashboard + API +https://:443 { + tls internal { + on_demand + } + + @api path /api /api/* + handle @api { + reverse_proxy devenv:3001 + } + + handle { + reverse_proxy devenv:3002 + } +} + +# Portal +https://:444 { + tls internal { + on_demand + } + + @vite_hmr { + path / + header Upgrade websocket + } + + reverse_proxy @vite_hmr devenv:3004 + reverse_proxy devenv:3003 +} diff --git a/docker/development/devenv/Dockerfile b/docker/development/devenv/Dockerfile index 4976c78ef..1bfda0eec 100644 --- a/docker/development/devenv/Dockerfile +++ b/docker/development/devenv/Dockerfile @@ -14,7 +14,7 @@ RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - RUN apt-get install -y nodejs gcc g++ make python3 # Install pnpm -RUN npm install -g pnpm@11.19.0 +RUN npm install -g --min-release-age=7 pnpm # Delete default sudo user and create unprivileged user RUN userdel -r ubuntu diff --git a/docker/development/nginx/Dockerfile b/docker/development/nginx/Dockerfile deleted file mode 100644 index 602a70773..000000000 --- a/docker/development/nginx/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM nginx - -RUN apt-get update && apt-get install -y openssl -RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/localhost-cert.key -out /etc/ssl/certs/localhost-cert.pem -days 3650 -subj '/CN=localhost' -nodes - -COPY ./default.conf /etc/nginx/conf.d/default.conf diff --git a/docker/development/nginx/default.conf b/docker/development/nginx/default.conf deleted file mode 100644 index 2b2070dde..000000000 --- a/docker/development/nginx/default.conf +++ /dev/null @@ -1,39 +0,0 @@ -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name localhost; - - # Using a variable here stops nginx from crashing if the dev container is restarted or becomes otherwise unavailable - set $backend_upstream "http://devenv:3001"; - set $dashboard_upstream "http://devenv:3002"; - - location / { - # Using a variable in proxy_pass also requires resolver to be set. - # This is the address of the internal docker compose DNS server. - resolver 127.0.0.11; - proxy_pass $dashboard_upstream$uri$is_args$args; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $host; - proxy_http_version 1.1; - proxy_cache_bypass $http_upgrade; - } - - location /api { - resolver 127.0.0.11; - proxy_pass $backend_upstream$uri$is_args$args; - proxy_redirect off; - - client_max_body_size 200M; - } - - ssl_certificate /etc/ssl/certs/localhost-cert.pem; - ssl_certificate_key /etc/ssl/private/localhost-cert.key; - - ssl_session_timeout 1d; - ssl_session_cache shared:MozSSL:10m; - ssl_session_tickets off; - - ssl_protocols TLSv1.3; - ssl_prefer_server_ciphers off; -} diff --git a/entrypoint.sh b/entrypoint.sh index 8d1b6e310..1e8e80ad5 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -7,6 +7,7 @@ case "$1" in bot) exec pnpm run --silent run:bot;; api) exec pnpm run --silent run:api;; dashboard) exec pnpm run --silent run:dashboard;; + portal) exec pnpm run --silent run:portal;; *) echo "Unknown command: $1" exit 1 diff --git a/package.json b/package.json index c208f2024..b13bf2215 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "run:migrate": "cd backend && pnpm run migrate", "run:bot": "cd backend && pnpm run start-bot-prod", "run:api": "cd backend && pnpm run start-api-prod", - "run:dashboard": "cd dashboard && node serve.js" + "run:dashboard": "cd dashboard && node serve.js", + "run:portal": "cd portal/build && NODE_ENV=production node bin/server.js" }, "devDependencies": { "@types/node": "^24.13.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b40cca622..576abef93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,7 +72,7 @@ importers: version: 1.0.5 express: specifier: ^4.20.0 - version: 4.22.2 + version: 4.22.2(supports-color@10.2.2) fp-ts: specifier: ^2.0.1 version: 2.16.11 @@ -132,7 +132,7 @@ importers: version: 1.0.0 threads: specifier: ^1.7.0 - version: 1.7.0 + version: 1.7.0(supports-color@10.2.2) tlds: specifier: ^1.221.1 version: 1.261.0 @@ -147,7 +147,7 @@ importers: version: 12.1.6 typeorm: specifier: ^0.3.27 - version: 0.3.31(mysql2@3.23.0(@types/node@24.13.3))(redis@5.12.1) + version: 0.3.31(mysql2@3.23.0(@types/node@24.13.3))(redis@5.12.1)(supports-color@10.2.2) utf-8-validate: specifier: ^5.0.5 version: 5.0.10 @@ -199,7 +199,7 @@ importers: version: 9.0.8 ava: specifier: ^5.3.1 - version: 5.3.1 + version: 5.3.1(supports-color@10.2.2) source-map-support: specifier: ^0.5.16 version: 0.5.21 @@ -302,17 +302,600 @@ importers: specifier: ^4.1.0 version: 4.1.0(vue@3.5.40(typescript@6.0.3)) + portal: + dependencies: + '@adonisjs/ally': + specifier: ^6.3.2 + version: 6.3.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/inertia@5.0.1(3f17abe654a593f174d8c7d5a3b95857))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982)) + '@adonisjs/auth': + specifier: ^10.1.0 + version: 10.1.0(c16d739126567016c4d2c00b96bddf22) + '@adonisjs/core': + specifier: ^7.5.2 + version: 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@adonisjs/cors': + specifier: ^3.0.0 + version: 3.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1)) + '@adonisjs/inertia': + specifier: ^5.0.1 + version: 5.0.1(3f17abe654a593f174d8c7d5a3b95857) + '@adonisjs/limiter': + specifier: ^3.0.1 + version: 3.0.1(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2))(@adonisjs/redis@11.0.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2)) + '@adonisjs/lucid': + specifier: ^22.4.2 + version: 22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + '@adonisjs/redis': + specifier: ^11.0.0 + version: 11.0.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2) + '@adonisjs/session': + specifier: ^8.1.0 + version: 8.1.0(770cc5139ed8289213226f432e14c982) + '@adonisjs/shield': + specifier: ^9.0.0 + version: 9.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0))(edge.js@6.5.1) + '@adonisjs/static': + specifier: ^2.0.1 + version: 2.0.1(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2) + '@adonisjs/vite': + specifier: ^6.0.2 + version: 6.0.3(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/shield@9.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0))(edge.js@6.5.1))(edge.js@6.5.1)(vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0)) + '@fontsource-variable/playpen-sans': + specifier: ^5.3.0 + version: 5.3.0 + '@fontsource-variable/recursive': + specifier: ^5.3.0 + version: 5.3.0 + '@inertiajs/core': + specifier: ^3.7.1 + version: 3.9.1 + '@inertiajs/vue3': + specifier: ^3.7.1 + version: 3.9.1(vue@3.5.43(typescript@6.0.3)) + '@tuyau/core': + specifier: ^1.2.2 + version: 1.2.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1)) + '@vinejs/vine': + specifier: ^4.4.0 + version: 4.4.0 + '@vue/server-renderer': + specifier: ^3.5.43 + version: 3.5.43 + '@zeppelinbot/shared': + specifier: workspace:* + version: link:../shared + csv-stringify: + specifier: ^6.9.0 + version: 6.9.0 + edge.js: + specifier: ^6.5.1 + version: 6.5.1 + jszip: + specifier: ^3.10.2 + version: 3.10.2 + lucide-vue-next: + specifier: ^1.0.0 + version: 1.0.0(vue@3.5.43(typescript@6.0.3)) + luxon: + specifier: ^3.7.2 + version: 3.7.2 + markdown-it: + specifier: ^15.0.2 + version: 15.0.2 + mysql2: + specifier: ^3.23.0 + version: 3.23.0(@types/node@26.6.5) + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + reka-ui: + specifier: ^2.11.0 + version: 2.11.0(vue@3.5.43(typescript@6.0.3)) + vue: + specifier: ^3.5.43 + version: 3.5.43(typescript@6.0.3) + vue-sonner: + specifier: ^2.0.9 + version: 2.0.9 + zod: + specifier: ^4.4.3 + version: 4.4.3 + devDependencies: + '@adonisjs/assembler': + specifier: ^8.5.2 + version: 8.5.2(typescript@6.0.3) + '@adonisjs/prettier-config': + specifier: ^1.5.0 + version: 1.5.0(prettier@3.9.6) + '@adonisjs/tsconfig': + specifier: ^2.0.0 + version: 2.0.0 + '@japa/assert': + specifier: ^4.2.0 + version: 4.2.0(@japa/runner@5.3.0) + '@japa/browser-client': + specifier: ^2.3.0 + version: 2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0) + '@japa/plugin-adonisjs': + specifier: ^5.2.0 + version: 5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0) + '@japa/runner': + specifier: ^5.3.0 + version: 5.3.0 + '@poppinss/ts-exec': + specifier: ^1.4.4 + version: 1.5.0(@swc/helpers@0.5.23) + '@types/luxon': + specifier: ^3.7.5 + version: 3.7.6 + '@types/node': + specifier: ~26.6.2 + version: 26.6.5 + '@vitejs/plugin-vue': + specifier: ^6.0.9 + version: 6.0.10(vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.43(typescript@6.0.3)) + hot-hook: + specifier: ^1.0.0 + version: 1.0.0 + pino-pretty: + specifier: ^13.1.3 + version: 13.2.0 + typescript: + specifier: catalog:ts6 + version: 6.0.3 + vite: + specifier: ^8.3.0 + version: 8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0) + vue-tsc: + specifier: ^3.3.11 + version: 3.3.13(typescript@6.0.3) + youch: + specifier: ^4.1.1 + version: 4.1.1 + shared: devDependencies: ava: specifier: ^5.3.1 - version: 5.3.1 + version: 5.3.1(supports-color@10.2.2) typescript: specifier: catalog:ts7 version: 7.0.2 packages: + '@adonisjs/ace@14.1.1': + resolution: {integrity: sha512-6MP2eZicAP8hd1US1PR2b6hEzWVaNlEbbAxanwDAyTOMW8PysefQam7b59ipbxw4+ADTJsgIyQWVt815W9f6WQ==} + engines: {node: '>=24.0.0'} + peerDependencies: + youch: ^4.1.0-beta.11 || ^4.1.0 + + '@adonisjs/ally@6.3.2': + resolution: {integrity: sha512-MCQoXmBrbdyVfQL8hEDuJnjnSr1R4rLBApc5ekKHzZCOnUhCMmqHjxkM3gdiSXe5eQ/SqH9RMDkv162EOGAJHA==} + engines: {node: '>=20.6.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0 + '@adonisjs/core': ^7.0.0-next.8 || ^7.0.0 + '@adonisjs/i18n': ^3.0.0 + '@adonisjs/inertia': ^4.2.0 || ^5.0.0 + '@adonisjs/session': ^8.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/i18n': + optional: true + '@adonisjs/inertia': + optional: true + '@adonisjs/session': + optional: true + + '@adonisjs/application@9.1.0': + resolution: {integrity: sha512-KWsTfkITDozW4csD4YofDEbbWuORKI056VgEr9WBwjIdrzIC7hqPxLtnszFVmyv14THPi0SRBTN/fIYQ6/SQ4Q==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.23 || ^8.0.0 + '@adonisjs/config': ^6.1.0-next.0 || ^6.0.0 + '@adonisjs/fold': ^11.0.0-next.3 || ^11.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + + '@adonisjs/assembler@8.5.2': + resolution: {integrity: sha512-CipLZEl/2zBa6ejoMogXsXAg4+8hIf0CAhRaHjf9KXfeUininRc9Wg3zFv+To1xgHLjnuPiQfqKBhP6I44KVlA==} + engines: {node: '>=24.0.0'} + peerDependencies: + typescript: ^5.0.0 || ^6.0.0 + + '@adonisjs/auth@10.1.0': + resolution: {integrity: sha512-H92C4HLWBpvxtQrgnsdWdWfoGu2bM/j+nyk/tHmpxH9ETkNOH0z3dRfEebLJI63vtTDpRp5cwiI0bzn32gUQiA==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.26 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.16 || ^7.0.0 + '@adonisjs/i18n': ^3.0.0-next.2 || ^3.0.0 + '@adonisjs/lucid': ^22.0.0-next.1 || ^22.0.0 + '@adonisjs/session': ^8.0.0-next.1 || ^8.0.0 + '@japa/api-client': ^3.1.1 + '@japa/browser-client': ^2.2.0 + '@japa/plugin-adonisjs': ^5.1.0-next.0 || ^5.1.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/i18n': + optional: true + '@adonisjs/lucid': + optional: true + '@adonisjs/session': + optional: true + '@japa/api-client': + optional: true + '@japa/browser-client': + optional: true + '@japa/plugin-adonisjs': + optional: true + + '@adonisjs/bodyparser@11.0.4': + resolution: {integrity: sha512-amqMPVFbzxkOoCMbkFs5sC+rTu7cER2rSv+1v8dsGKszolk5lnGuyNjkha1Lqksvw1qykIIbC1fXr37B9WJTdg==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/http-server': ^8.0.0-next.17 || ^8.0.0 || ^9.0.0 + + '@adonisjs/config@6.1.0': + resolution: {integrity: sha512-YVDRL8xHCtM6iMnAefOBaz6iXVpojwBPDQWPKxnVSucycYeNGrGitJiLy+cGaeAU7Gjm8al9SJRJt3rRPr5PKg==} + engines: {node: '>=24.0.0'} + + '@adonisjs/core@7.6.0': + resolution: {integrity: sha512-DGDkpoNrExwLhhmuzZBaOKe6wk67HI/0+3GLWsJXB+Ze4NjXuKKOT5169R2CqpSO6yvL1Xw39HwSJ9YJ1oTvLg==} + engines: {node: '>=24.0.0'} + hasBin: true + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.23 || ^8.0.0 + '@vinejs/vine': ^4.0.0 + argon2: ^0.44.0 || ^0.45.1 + bcrypt: ^6.0.0 + edge.js: ^6.2.0 + pino-pretty: ^13.1.3 + youch: ^4.1.0-beta.13 || ^4.1.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@vinejs/vine': + optional: true + argon2: + optional: true + bcrypt: + optional: true + edge.js: + optional: true + pino-pretty: + optional: true + youch: + optional: true + + '@adonisjs/cors@3.0.0': + resolution: {integrity: sha512-S3LS+zZ2SziwVvilnkKg4DjmU+df1xqdZRDSQjUKJr5hYEOVAlnci0kHTiz2szxB+QiseQXr/XfN/D5ooMMlYQ==} + engines: {node: '>=18.16.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.7 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.0 || ^7.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + + '@adonisjs/env@7.1.0': + resolution: {integrity: sha512-DXKCDIDoHzjxx9O7HvFYYBGQENmF5ANTUXBGE65ygOcJTtXyrLBISUkjrIQGVAKUmcLPF9WInkXQfxMnfO2VJw==} + engines: {node: '>=24.0.0'} + + '@adonisjs/events@10.2.0': + resolution: {integrity: sha512-SzwzbmTLsybSZd47zZMZ3df7puwhY7D8vZ5Uy79SiHjLKbr2eVzUuKjjoYB6/0pZu6IwK9Qx06dI43sl+tLoDw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/application': ^9.0.0-next.14 || ^9.0.0 + '@adonisjs/fold': ^11.0.0-next.4 || ^11.0.0 + + '@adonisjs/fold@11.1.0': + resolution: {integrity: sha512-M3/AUZ6w8s/3uLJ4RBPwkzpOaXAdYh1EezRA11j+S9/WfUyxx4aiIm9FpjitSJC1Hrc5ap6AqlYu2m6dfzHVRA==} + engines: {node: '>=24.0.0'} + + '@adonisjs/hash@10.1.1': + resolution: {integrity: sha512-i12srCoJ2uomD8fTMPEp16lcRTsB9pI8AlGFrtkrq7xcoLPBVi67lovXkdS6BNHdvdciH9HLcRe73KB2kUvgfw==} + engines: {node: '>=20.6.0'} + peerDependencies: + argon2: ^0.31.2 || ^0.41.0 || ^0.43.0 || ^0.44.0 || ^0.45.1 + bcrypt: ^5.1.1 || ^6.0.0 + peerDependenciesMeta: + argon2: + optional: true + bcrypt: + optional: true + + '@adonisjs/health@3.1.0': + resolution: {integrity: sha512-m3doBnSwi/l9v1DO79xmjAoSPl9b2XCp+crGwF8QUlhe5CgWgtfnL0SeFNEiZGliD3c4gYdihKz4Pnydctva8A==} + engines: {node: '>=24.0.0'} + + '@adonisjs/http-server@9.3.1': + resolution: {integrity: sha512-SX3JATI2PtSNYYia/I0rfJvUR4IHJ9GSluORTIwLfwpqi01nVkkXdokxea9XVh4Wn1z4OOIXy/5gfa8OlFrBxQ==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/application': ^9.0.0-next.14 || ^9.0.0 + '@adonisjs/events': ^10.1.0-next.4 || ^10.1.0 + '@adonisjs/fold': ^11.0.0-next.4 || ^11.0.0 + '@adonisjs/logger': ^7.1.0-next.3 || ^7.1.0 + '@boringnode/encryption': ^0.2.0 || ^1.0.0 + youch: ^4.1.0-beta.13 || ^4.1.0 + peerDependenciesMeta: + youch: + optional: true + + '@adonisjs/http-transformers@2.3.1': + resolution: {integrity: sha512-N3gBcKyoPHDeVvVIedTzc+ARSUURwNGTPid/e3iLdM4v/myoSnXd76FL/GGzMmjfqqxegpjI2IEMibG7ylrKSQ==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/fold': ^11.0.0-next.2 + + '@adonisjs/inertia@5.0.1': + resolution: {integrity: sha512-UuENysVrnTTuaupY+ltzFDsa9lBS0NDa9PV27KxpyxgQcwCP9S88ZQYe9MJosEzz8NVoDLd0CjkNMilXxknXCA==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.29 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.23 || ^7.0.0 + '@adonisjs/session': ^8.0.0-next.2 || ^8.0.0 + '@adonisjs/vite': ^6.0.0-next.0 || ^6.0.0 + '@inertiajs/core': ^3.4.0 + '@inertiajs/react': ^3.4.0 + '@inertiajs/vue3': ^3.4.0 + '@japa/api-client': ^3.1.1 + '@japa/plugin-adonisjs': ^5.1.0-next.1 || ^5.1.0 + '@tuyau/core': ^1.0.0-beta.10 || ^1.0.0 + edge.js: ^6.4.0 + react: ^19.2.3 + vue: ^3.5.17 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@inertiajs/core': + optional: true + '@inertiajs/react': + optional: true + '@inertiajs/vue3': + optional: true + '@japa/api-client': + optional: true + '@japa/plugin-adonisjs': + optional: true + '@tuyau/core': + optional: true + react: + optional: true + vue: + optional: true + + '@adonisjs/limiter@3.0.1': + resolution: {integrity: sha512-U7drt/FPlB5PV84dnxQQSFGk75fDxgEHSkfT/eGwx/+Z4re7XlkVU4oros/VGefD72JTgXp7Kz97tS1XW7eEXA==} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.9 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.1 || ^7.0.0 + '@adonisjs/i18n': ^3.0.0-next.0 || ^3.0.0 + '@adonisjs/lucid': ^22.0.0-next.0 || ^22.0.0 + '@adonisjs/redis': ^10.0.0-next.1 || ^10.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/i18n': + optional: true + '@adonisjs/lucid': + optional: true + '@adonisjs/redis': + optional: true + + '@adonisjs/logger@7.1.1': + resolution: {integrity: sha512-MmUlp8xBMT6zZy0+vnQcQjHIlNfU4pUJARlINr7Bqha9BvhIn03QZgJL5QJ+kJe1tl6ZpNAryoRTJUiOk/wINQ==} + engines: {node: '>=24.0.0'} + peerDependencies: + pino-pretty: ^13.1.1 + peerDependenciesMeta: + pino-pretty: + optional: true + + '@adonisjs/lucid@22.4.2': + resolution: {integrity: sha512-3ztENqBQIFSGAWREHKCGbL1g4ehtsxxsuFX72Uf5bq+oSc0D6UcumjzYpU8TPyBxhmgS6HuRSfz2rG42iuz7AA==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.29 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.21 || ^7.0.0 + '@vinejs/vine': ^3.0.0 || ^4.0.0 + luxon: ^3.4.4 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@vinejs/vine': + optional: true + luxon: + optional: true + + '@adonisjs/presets@3.0.0': + resolution: {integrity: sha512-+gVIvyEiM7jiN5Gb93200TAC8ed3vZIPfxFFo0pIVgX8k40BleuYhWxFhI6TPocVXXIIpw2JuMFV2Pqjk36W2A==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.9 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.1 || ^7.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + + '@adonisjs/prettier-config@1.5.0': + resolution: {integrity: sha512-im5V503HAaWSqmDWXV3k40KMCXvgurGNExkjGjvEkl2N7Wp+RcBN3pC6PAWUA1j4iukp4azzuuuR2tPFgnIkbA==} + + '@adonisjs/redis@11.0.0': + resolution: {integrity: sha512-NXPzn8fC7fjRRbuRC9nVIvEQyuZrf45OFH2sp2EU0MUuMO/Y7CSORHeFfe9TxJQOutmeOwwGoyXgWIh6owfi4w==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/core': ^7.0.0-next.0 || ^7.0.0 + + '@adonisjs/repl@5.0.0': + resolution: {integrity: sha512-cPp0w5svYUA3M1gdxQBO2Mx5g+SZfPweqKCAxk7C1Os/Qu67JKgWqXqNnl1q0Tzv/l0L19Ms1C7ivzQxeBNajg==} + engines: {node: '>=24.0.0'} + + '@adonisjs/session@8.1.0': + resolution: {integrity: sha512-hTd5m49Ro8XhxVQN0yyCeDOihDhj+mFIVltzeWPXkCxK19JHAtA++TAygxSUEhvcm56IVS43XWNE1lNIOPjMJA==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.26 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.16 || ^7.0.0 + '@adonisjs/lucid': ^22.0.0-next.0 || ^22.0.0 + '@adonisjs/redis': ^10.0.0-next.2 || ^10.0.0 + '@aws-sdk/client-dynamodb': ^3.955.0 + '@aws-sdk/util-dynamodb': ^3.955.0 + '@japa/api-client': ^3.1.0 + '@japa/browser-client': ^2.0.3 + '@japa/plugin-adonisjs': ^5.1.0-next.0 || ^5.1.0 + edge.js: ^6.4.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/lucid': + optional: true + '@adonisjs/redis': + optional: true + '@aws-sdk/client-dynamodb': + optional: true + '@aws-sdk/util-dynamodb': + optional: true + '@japa/api-client': + optional: true + '@japa/browser-client': + optional: true + '@japa/plugin-adonisjs': + optional: true + edge.js: + optional: true + + '@adonisjs/shield@9.0.0': + resolution: {integrity: sha512-RmupWRspYGyzS/fAC0QspL7+Uhp6IaidvxE4CYbuqO43PBPCxhC47VjXML720B8hcps7ClK9RWjdMiJkUrn7fA==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.26 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.16 || ^7.0.0 + '@adonisjs/i18n': ^3.0.0-next.2 || ^3.0.0 + '@adonisjs/session': ^8.0.0-next.1 || ^8.0.0 + '@japa/api-client': ^3.1.1 + '@japa/plugin-adonisjs': ^5.1.0-next.0 || ^5.1.0 + edge.js: ^6.4.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/i18n': + optional: true + '@japa/api-client': + optional: true + '@japa/plugin-adonisjs': + optional: true + edge.js: + optional: true + + '@adonisjs/static@2.0.1': + resolution: {integrity: sha512-pXSyQgha1yfyQDXPp0ywv7hJqk4JgCCkzWLkku2PW3Y6i/9GUTyzzNTCpz29loZzSF0b/EpiHXQE/sqBhW+p7w==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.7 || ^8.0.0 + '@adonisjs/core': ^7.0.0-next.0 || ^7.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + + '@adonisjs/tsconfig@2.0.0': + resolution: {integrity: sha512-Uz8qvB6KR9otCh9zei2VEj7tPwdsrT7R+voYoN4tUfEijWRdTNgJ8d1CtyLKHaggCCOwZIwZLVklV/h2FDHgNw==} + + '@adonisjs/vite@6.0.3': + resolution: {integrity: sha512-LmY5Zqj1hPZTaqFrLzTSDyCe+15j+9zz4o3Bh+gCnmZAHJyIhDmyyDnBsNzcQ4qgXMAQDhLLKmteXTpFjFloOg==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.10 || ^8.0.0 + '@adonisjs/core': ^7.5.0 + '@adonisjs/shield': ^9.0.0-next.0 || ^9.0.0 + edge.js: ^6.0.1 + vite: ^8.0.0 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/shield': + optional: true + edge.js: + optional: true + + '@antfu/install-pkg@2.1.0': + resolution: {integrity: sha512-sdg9NxU3zR4Mnawfbc/x6GB5Wf17WYud5qOuEuxXjaKpYpMkISSJEjItGebXJ2bQ4DIcly4NYH23mtkGJjvKUw==} + + '@arr/every@1.0.1': + resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==} + engines: {node: '>=4'} + + '@ast-grep/napi-darwin-arm64@0.45.3': + resolution: {integrity: sha512-rMZJ6frSpR/xSbeV4hiA9WR5hHqk3rVYX8lOqEoUCaUnjEuFXvHdGN4WawJ8pVDq/IqM1UnTtsDSYgUdVmO5DA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@ast-grep/napi-darwin-x64@0.45.3': + resolution: {integrity: sha512-tIclZ5pM+YSgk8NNTBoTkaclbS39cU5lbVfSrFWX4LUnxXfUPG+F+ppxyFjKwJTBELsGHEO4LdX3/Lc+FDwPNA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@ast-grep/napi-linux-arm64-gnu@0.45.3': + resolution: {integrity: sha512-Bm8F7/oRHQkDXbjH+gBi9oB5huJ0q12r/AIOMIypf5PWlAVvh206Tsw468phw4Oh6kd4Ad1Z+gflNW1MutgK2g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@ast-grep/napi-linux-arm64-musl@0.45.3': + resolution: {integrity: sha512-yr5xcRerV41GeRxmZ8SKbfGeyZRhQePoNNCgTAb4OrWMelWwbMI80aY7/IlF2bo1sN40BSW4hZdGIO/akTd1RQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@ast-grep/napi-linux-x64-gnu@0.45.3': + resolution: {integrity: sha512-lluRK3hxfHMQdFuVID6seAKVx4FH0kEwF6rCh5/I40Sf3EtNR2UCBXAqd6RBA6hqlSckktvBxCfw+h4aescDmg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@ast-grep/napi-linux-x64-musl@0.45.3': + resolution: {integrity: sha512-09wJQKq86LqILqQtw0+X09SzhcPwUnMVFKyia7S3XLbLqSeQpAMF55Y+zll53JRQ1dCzFEZJyvTT/7j9vwfE3w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@ast-grep/napi-win32-arm64-msvc@0.45.3': + resolution: {integrity: sha512-/HiVgw2cdtzXLDLoG4eBBcauekNXewfagy7qiVbjkVu/KcCH8dJ9lpj8DzeWwuBNtZxuD8jpiwP0M1pz3Bc3uw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@ast-grep/napi-win32-ia32-msvc@0.45.3': + resolution: {integrity: sha512-/gwJrJQUw65uNtAFcG2rtSTr117Gqqy3bfjaljCPKsa65dTeRcMMnjKLlZ6V9/g8z+4Xf78kdhp5ECbir4yfSw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@ast-grep/napi-win32-x64-msvc@0.45.3': + resolution: {integrity: sha512-CEZAMAsaDoQoVE3MT2c/ry3/ydfyaqlTjxv8DK5PG355SrdAYPgevGC2Me6tz4dhphJin89Y20VsnrS5UrYV5Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@ast-grep/napi@0.45.3': + resolution: {integrity: sha512-bjJsUt0g3UCwbn9bjv7MnoR15rszSm79yPCXn4DWWK0NuYUUqBU/srtNMR4WnpfR7TnfBRdYFoqSNx0pGCNWJg==} + engines: {node: '>= 10'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} @@ -326,10 +909,34 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/types@7.29.7': resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@boringnode/encryption@1.0.1': + resolution: {integrity: sha512-+UL9erFUngnxNEDdXSKCnGQA8D62C/x2vxLF5vc9zaX7T2JolV/bGjpZAvFLzlY2gIffHyw+KsqsEWod5+zV0w==} + engines: {node: '>=20.6'} + + '@boringnode/route-matcher@0.1.1': + resolution: {integrity: sha512-Iim6TZdwX3BuQ+m4wg5wIEviIoi0Xy6j6cpw4B2o1wppByUxafbLMgMIFJ6yS/l1XKXifEGcds9M1Gw7Fk8DUg==} + engines: {node: '>=20.6'} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@csstools/selector-resolve-nested@3.1.0': resolution: {integrity: sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==} engines: {node: '>=18'} @@ -379,6 +986,10 @@ packages: '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@faker-js/faker@10.6.0': + resolution: {integrity: sha512-3RQHgEtvL1Frl/d1cSreo7qhJ3Gk1OdNUai/CtZ8G+wYeRQnJih3s9xJ9/kgYekPQRdwgh0HXRPqMlzWGwivIQ==} + engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + '@fastify/accept-negotiator@1.1.0': resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==} engines: {node: '>=14'} @@ -401,10 +1012,107 @@ packages: '@fastify/static@7.0.4': resolution: {integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==} + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} + + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} + + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + + '@floating-ui/vue@2.0.1': + resolution: {integrity: sha512-043dyEKD9TDSfz080YH2vobubgg+NIo/9Fw4RAl7sEMpD8Am1DNrrSTl/GpMBjyGHoD/FbJY2QLawY+HSQsEIA==} + peerDependencies: + vue: '>=3.3.0' + + '@fontsource-variable/playpen-sans@5.3.0': + resolution: {integrity: sha512-IoqGZSrVkaGXgD61IGkSOF0nTNmb8I4gyxZxpuHXCocAj4he5sL4oLWy1BmyiZiDv0pUeopaKQv9Q2Zpnse87Q==} + + '@fontsource-variable/recursive@5.3.0': + resolution: {integrity: sha512-4B4/lWCVeZgdbpJdIIU1sOVO/ECjjM673ohuxvyQ6uCK41TPlGzKRNokKY84noUgGYnpwc//MW4k2KrOMY19jQ==} + + '@inertiajs/core@3.9.1': + resolution: {integrity: sha512-ScLQZ1/KXlvmqCEJMEZABSK5updJZIli1kaG/coWXpWMmpSLsazSJkR7esITYp7X5vTgrOGNIrcRmdMp/GQ0NA==} + peerDependencies: + axios: ^1.15.2 + peerDependenciesMeta: + axios: + optional: true + + '@inertiajs/vue3@3.9.1': + resolution: {integrity: sha512-pISiTjoCm86xHFMdG7QhkzKXrX3fMf9Ihgst08xalxv4pOzwQ5L/Hw/RnOzrqO34waykPEWgAr34nyo2IQ80mg==} + peerDependencies: + vue: ^3.0.0 + + '@internationalized/date@3.12.4': + resolution: {integrity: sha512-M1dEn4c1U1HsSlaVR8upZtSqvXrTkHDfv18H01uCSJyjVLDxnBR38v/fMxecmlwXKR4i9HeZcmgQAPE6A+aGJQ==} + + '@internationalized/number@3.6.9': + resolution: {integrity: sha512-GgWy2caO/+hV9sT/oCTWGHvbjmJMPT9kkXzoKRLnkEq7adghhR7UprhvY9sXrKfrp3NcDfhF6QQHXR1KfQbB8g==} + + '@ioredis/commands@2.0.0': + resolution: {integrity: sha512-vrx0AE/T0h7cRZwfo1M39Cr+ZhZrkf0V8mQN75wucKCxCLD9l/VX6no3gFvrLqD1IlG/1LtzWovqEw3t0Vr9zg==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@japa/assert@4.2.0': + resolution: {integrity: sha512-Krgrcee01BN1StlVwK5JQP6LL5t3DE3uFNbfFoDTfW7kQuHB0xh6yfaV0hrgcoiEjsqmm2OOsVWeju9aXK4vIA==} + engines: {node: '>=18.16.0'} + peerDependencies: + '@japa/runner': ^3.1.2 || ^4.0.0 || ^5.0.0 + + '@japa/browser-client@2.3.0': + resolution: {integrity: sha512-YNcN0l1dZRZpsFtBHWPq5dP/8+US1FALs/uqhGUhvIgKQgIA5I3PvzRmkry+Dh74U6/Mj+IO2kRJL+kPCdVnew==} + engines: {node: '>=18.16.0'} + peerDependencies: + '@japa/assert': ^2.0.0 || ^3.0.0 || ^4.0.0 + '@japa/runner': ^3.1.2 || ^4.0.0 || ^5.0.0 + playwright: ^1.57.0 + + '@japa/core@10.4.0': + resolution: {integrity: sha512-1zvKL29i7r/4jqTNBsw91hk1tp6wbqFXvyV2p+Og4axDRhIXjSAfauRvBL9QuB80bOa+pDIMQ5kCTaCplSm0Eg==} + engines: {node: '>=24.0.0'} + + '@japa/errors-printer@4.1.4': + resolution: {integrity: sha512-ogPT87QLaugKyPVcq+ZypcetVeJpXZN7RfVRlRDIrSHsHBw6ILCtNXghVxD9POjqxtUM7RON3sUkgZzLnVQA5g==} + engines: {node: '>=18.16.0'} + + '@japa/plugin-adonisjs@5.2.0': + resolution: {integrity: sha512-Knk3X/UeZiEvkXmTj9+dAIOdJHMqRUJFsUMw9y8at+AR1VbPJR9T+aU5SaOn6OtejEFnUMILwJYC3ohg23+vhw==} + engines: {node: '>=18.16.0'} + peerDependencies: + '@adonisjs/core': ^7.0.0-next.21 || ^7.0.0 + '@japa/api-client': ^3.1.0 + '@japa/browser-client': ^2.2.0 + '@japa/runner': ^4.0.0 || ^5.0.0 + playwright: ^1.57.0 + peerDependenciesMeta: + '@japa/api-client': + optional: true + '@japa/browser-client': + optional: true + playwright: + optional: true + + '@japa/runner@5.3.0': + resolution: {integrity: sha512-WCnTd1q2EpbKKa96NzL16kVxJXVLRj1VqbswNAn17hYSuMlNKKhPGNbAosB32QZVFcoe9fv4Ebh1HtjyAT/viw==} + engines: {node: '>=18.16.0'} + + '@jest/diff-sequences@30.5.0': + resolution: {integrity: sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.5.0': + resolution: {integrity: sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/schemas@30.5.0': + resolution: {integrity: sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -446,6 +1154,9 @@ packages: '@oxc-project/types@0.139.0': resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + '@oxc-project/types@0.153.0': + resolution: {integrity: sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==} + '@oxfmt/binding-android-arm-eabi@0.59.0': resolution: {integrity: sha512-bNTnfbuG7sAwb2PakMNaDukx5kXeW9duXOBeWtTOiLz3fXz3q2DlWguufPZ+c2IHEVrRXHD+M4aUgEWm841LDA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -690,6 +1401,10 @@ packages: cpu: [x64] os: [win32] + '@phc/format@1.0.0': + resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} + engines: {node: '>=10'} + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -697,6 +1412,67 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@poppinss/cliui@6.8.1': + resolution: {integrity: sha512-o/ssbwr+r6woG65rk9eFHnn9dVUphZr/Rk+4+05ENVMBWYpYhTJGdE9RobTG5JLFubvO4gWIyFeNlC+I4EM6eA==} + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.7.0': + resolution: {integrity: sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@poppinss/hooks@7.3.1': + resolution: {integrity: sha512-MyBiHAOmUPT8fY++IQIeiYnxknrLQ9WzrAlZlyyGbFh+C5Srdb+FhQbQkLivAQxIKkhiCeeoSpiGPcv5gDvirA==} + + '@poppinss/inspect@1.0.1': + resolution: {integrity: sha512-kLeEaBSGhlleyYvKc7c9s3uE6xv7cwyulE0EgHf4jU/CL96h0yC4mkdw1wvC1l1PYYQozCGy46FwMBAAMOobCA==} + + '@poppinss/macroable@1.1.2': + resolution: {integrity: sha512-FAVBRzzWhYP5mA3lCwLH1A0fKBqq5anyjGet90Z81aRK5c/+LTGUE1zJhZrErjaenBSOOI9BVUs3WVmotneFQA==} + + '@poppinss/matchit@3.2.0': + resolution: {integrity: sha512-9SoMICN+LMO7ZtMj2ja8N7RHlC4mmuv5WwIBXWjabMd2SyXE1dIydh29exlgm+dGMP84PjwvfJH1TmWL4qz1og==} + + '@poppinss/middleware@3.2.7': + resolution: {integrity: sha512-MZC0Z97ozSz+PpfyxUPUy/ImuthpqvBbY7qku7f4Q2maHz+2uXfchfO8OggXLS6zEJ078l+jpAHZ2rDIRdjeVg==} + + '@poppinss/multiparty@3.0.0': + resolution: {integrity: sha512-z9jchUzsv7E+7sa4tWHb0+95Byx7w0ydlPGxg3nzyb7h3QlRdeW8/QkU9SexUY4lsT12do93AfNBAhSuOoVqjA==} + + '@poppinss/oauth-client@7.2.0': + resolution: {integrity: sha512-LUCd/fIm2oOeTltnZRSJIxZL9uy9+qHpgtNtxIO+wp8E/1Dd7ogbqIWUFYMufCxTekOoYyQlWOcOQ9rmUw5D5g==} + engines: {node: '>=24.0.0'} + + '@poppinss/object-builder@1.1.0': + resolution: {integrity: sha512-FOrOq52l7u8goR5yncX14+k+Ewi5djnrt1JwXeS/FvnwAPOiveFhiczCDuvXdssAwamtrV2hp5Rw9v+n2T7hQg==} + engines: {node: '>=20.6.0'} + + '@poppinss/prompts@3.1.6': + resolution: {integrity: sha512-cKHfkID6b3wl1kbHJJRC/pznQ3KnRVydyk7CE38NfTV3VS45BDYCxeZZ7bfDin71qMzITh18lKnu8iuLxBngHA==} + + '@poppinss/qs@6.15.0': + resolution: {integrity: sha512-QzfMhxrRB5EPeGz0l8hTwKZ5dFX6ed0aETGbuD369StCO8Ad3SW4wWBYamOK5IKeM/dfOeKaCwUZPTnGcj+jKg==} + engines: {node: '>=0.6'} + + '@poppinss/string@1.7.2': + resolution: {integrity: sha512-A182GLDfi36iDCbhDrHB0xzrPM1fO3GHnhCDIdadf8C6eycgct4m7zusbLwEh6GPaj2Pz5BVos7XK16w7tZ7wQ==} + + '@poppinss/ts-exec@1.5.0': + resolution: {integrity: sha512-zkIE28rgHt2VFEN+A1QnHS7y7CQiM8kRSfvAAE1N8eZW8ghlju6uYZu3oIbISM0I0qs9E+KZLZAVY1djdTBoYg==} + engines: {node: '>=24.0.0'} + + '@poppinss/types@1.2.1': + resolution: {integrity: sha512-qUYnzl0m9HJTWsXtr8Xo7CwDx6wcjrvo14bOVbIMIlKJCzKrm3LX55dRTDr1/x4PpSvKVgmxvC6Ly2YiqXKOvQ==} + + '@poppinss/utils@7.1.1': + resolution: {integrity: sha512-m1pR6EsycFyDHWDyoWnTI2sgEpOAZuKECQRgZ9i+uGzU/DNoEXn70ldt1V3u2EKp2tNf9T9QqX1wBMHm+xcpiw==} + + '@poppinss/validator-lite@2.1.2': + resolution: {integrity: sha512-UhSG1ouT6r67VbEFHK/8ax3EMZYHioew9PqGmEZjV41G15aPZi6cyhXtBVvF9xqkHMflA5V680k7bQzV0kfD5w==} + '@redis/bloom@5.12.1': resolution: {integrity: sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==} engines: {node: '>= 18.19.0'} @@ -733,36 +1509,72 @@ packages: peerDependencies: '@redis/client': ^5.12.1 + '@rolldown/binding-android-arm-eabi@1.2.13': + resolution: {integrity: sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@rolldown/binding-android-arm64@1.1.5': resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.2.13': + resolution: {integrity: sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.1.5': resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.2.13': + resolution: {integrity: sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.1.5': resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.2.13': + resolution: {integrity: sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.1.5': resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.2.13': + resolution: {integrity: sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + resolution: {integrity: sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.1.5': resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -770,6 +1582,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.2.13': + resolution: {integrity: sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.1.5': resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -777,6 +1596,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.2.13': + resolution: {integrity: sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.1.5': resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -784,6 +1610,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + resolution: {integrity: sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.1.5': resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -791,6 +1624,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.13': + resolution: {integrity: sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.1.5': resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -798,6 +1638,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.13': + resolution: {integrity: sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.1.5': resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -805,12 +1652,25 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.2.13': + resolution: {integrity: sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.1.5': resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.2.13': + resolution: {integrity: sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.1.5': resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -822,12 +1682,24 @@ packages: cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.2.13': + resolution: {integrity: sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.1.5': resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.13': + resolution: {integrity: sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} @@ -847,12 +1719,140 @@ packages: resolution: {integrity: sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@silvia-odwyer/photon-node@0.3.4': resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + '@sinclair/typebox@0.34.52': + resolution: {integrity: sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@sindresorhus/is@8.1.0': + resolution: {integrity: sha512-2SX/1jW6CIMAiebvVv5ZInoCEuWQmMyBoJXXGC6Vjakjp/fpxP5eHs7/V6WKuPEIbuK06+VpjH+vjLQhr98rDQ==} + engines: {node: '>=22'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@sindresorhus/slugify@3.0.1': + resolution: {integrity: sha512-N1oPvN6sytRKZCskv0L+vSyvnUYi9JplPXZ90lT6EBsijjHrUdoXttb0Lna6pw1TWMe8vlajQnLDtU9KYHqtDg==} + engines: {node: '>=20'} + + '@sindresorhus/transliterate@2.3.1': + resolution: {integrity: sha512-gVaaGtKYMYAMmI8buULVH3A2TXVJ98QiwGwI7ddrWGuGidGC2uRt4FHs22+8iROJ0QTzju9CuMjlVsrvpqsdhA==} + engines: {node: '>=20'} + + '@speed-highlight/core@1.2.24': + resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==} + '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/core-darwin-arm64@1.16.18': + resolution: {integrity: sha512-ozgiCHyFDCwfXzTnaLR+i8WxEyt06GTudn9rPh08vj+u3Z8vMvt5Pi8T+BikyNXm7y++h6UMdqsnJuWrV+tk2A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.16.18': + resolution: {integrity: sha512-tuwxXi+sjxxTAi7GP3NeQXQxOf4SXSiFxKAMYLBdoy7JqGYby6uSDXojcFoLOhSp7oiNGstnaFXxfbP0Hpro9w==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.16.18': + resolution: {integrity: sha512-SMdhmY1P9Kveh0MRj6vqQF98bsjnDa0lBBvkd/lcpxmjj5QHJOQAU0N3g6h7GPWpBMs3h2g3lHu/QTDn+uMsXg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.16.18': + resolution: {integrity: sha512-ep/mQyhblQYZ6tkfq0IJspcVSFl5jdywks3kejanrbB31uuujRD/QWOoGNp2L3lLRdAdQvgl/M3pA7g3hSuQug==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.16.18': + resolution: {integrity: sha512-pkzGVxrAQu5+febW1a/Aiph3YJk0UiJKXoWbxnDVEIOZWkk5aETHTuyVsOQ3kOgn2dzNMvJVeqcoEQdH+ntqWQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-ppc64-gnu@1.16.18': + resolution: {integrity: sha512-v9kiu4as1pJyQ8ESFTtMNydZ99m86QXLfAtm+XiKPKS93pXL80BCaXokAs9ebioGkIXgmwfbzUCdUC62H3JWkw==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-s390x-gnu@1.16.18': + resolution: {integrity: sha512-vU7TKRJ26i86YQr4QY/5bdcH72KzkBbSSUfPlErW6d6KOR47BcVGlYZFTcMMYlmd3CVSXFHW18tBSila66YfoA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-gnu@1.16.18': + resolution: {integrity: sha512-Ml6kbe0BoVJkSgmYPAEUudGcu84jaQeqDN8xeMumbwNpT0vlmm7241Ddp9XKCjQABvjomnXF0OiNOAfjBhNDNw==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.16.18': + resolution: {integrity: sha512-TGU24+QmmS8y/hg0BLKgOU3W5TCcQC9bgGl8AB0R61gTNQdWdcmCehRLAJwlZfxtAml66xMJ6PWrX8NKrABOsA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.16.18': + resolution: {integrity: sha512-S53hm7Amc3YV8t2BUT6R7J+zSnwiGarG+GnxMca4W0uMkxBZ3Gl6jBwEgb6YqrYjf2DzOuRfauztqptCO76a/w==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.16.18': + resolution: {integrity: sha512-+6/10+OJmU12zWkrPVG0QeQEr8VsWeF8gyXrOfHZMIfMOfz8/ULXVZPhV9GhGMKSWake1xEJj2IYCiFRS/xMpQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.16.18': + resolution: {integrity: sha512-7LsVrIICAZWSajXT6DwO7PYSTnW9maamOCyQylaOh13Viptrgi/7hl9fP75SiHe+kscaJahGXcorgt4MOOh/1w==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.16.18': + resolution: {integrity: sha512-0cYQLkpcwUngg55TDwpwrrVOU+B6zh1NFbp+oS7dVFhmYkzaARelwugo/bzPJh1FrcnppmF+KTqioCGwyqbcEw==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} + + '@swc/types@0.1.28': + resolution: {integrity: sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==} + '@tailwindcss/node@4.3.3': resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} @@ -947,24 +1947,63 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 + '@tanstack/virtual-core@3.19.4': + resolution: {integrity: sha512-ygZ3O99Il18dl0gG0q7sH78iSkb96F07G+xK9V83eCgV8NQbcNd7R+cgcJJMFO7llBoebd0A82sCCstQq2Vp6Q==} + + '@tanstack/vue-virtual@3.13.45': + resolution: {integrity: sha512-AnYTTgpps/HyHJ9jgBW6dAPVTOY9UVb1AY8Gi2Th1dTDDUiUqalbq5W2hBrW0q8/DI8V5bt9HUgTvatbvZIukQ==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@ts-morph/common@0.29.0': + resolution: {integrity: sha512-35oUmphHbJvQ/+UTwFNme/t2p3FoKiGJ5auTjjpNTop2dyREspirjMy82PLSC1pnDJ8ah1GU98hwpVt64YXQsg==} + + '@tuyau/core@1.2.2': + resolution: {integrity: sha512-kFE+gxuWZ4F6KjMB6wXNEP44oVdBpYyuAsOxjHpGplC5d+ErSVjynh1vN0rkv9poQJI3z+r81JKqhpmJZs886Q==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@adonisjs/assembler': ^8.0.0-next.27 + '@adonisjs/core': ^7.0.0-next.16 + peerDependenciesMeta: + '@adonisjs/assembler': + optional: true + '@adonisjs/core': + optional: true + '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} '@types/cors@2.8.19': resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/express-serve-static-core@4.19.9': resolution: {integrity: sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==} '@types/express@4.17.25': resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} + '@types/he@1.2.3': + resolution: {integrity: sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==} + '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} @@ -980,6 +2019,9 @@ packages: '@types/lodash@4.17.24': resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + '@types/luxon@3.7.6': + resolution: {integrity: sha512-6KSjliQAXK8ZLgFQO4B7iE4Rpf/B3rItzCFuXezBY/XIAGxOdLd7vRNK9/StRPwiS/yJsVbB7HKpW46B8tcEuQ==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -989,6 +2031,12 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + '@types/node@26.6.5': + resolution: {integrity: sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/oauth@0.9.6': resolution: {integrity: sha512-H9TRCVKBNOhZZmyHLqFt9drPM9l+ShWiqqJijU1B8P3DX3ub84NjxDuy+Hjrz+fEca5Kwip3qPMKNyiLgNJtIA==} @@ -1001,6 +2049,9 @@ packages: '@types/passport@1.0.17': resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==} + '@types/pluralize@0.0.33': + resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} + '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} @@ -1028,6 +2079,12 @@ packages: '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@types/validator@13.15.10': + resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -1151,6 +2208,14 @@ packages: cpu: [x64] os: [win32] + '@vinejs/compiler@4.1.3': + resolution: {integrity: sha512-UyH7Zn8dkTMLeU+PF2WjCnWkFb2qYaOxAcvp/uXW0njtKNcJOnVJaPsnWYwqewkTcHN47yvOdzosj3kj3RAP5w==} + engines: {node: '>=18.0.0'} + + '@vinejs/vine@4.4.0': + resolution: {integrity: sha512-cfnNXjs9+f+22d3Eb8koyg2qlCbaT394XBlL4AeEr1WM+NH1omFcXwe1zrkW4hHwPDSfUd4lFUdNO6E+YnTeWQ==} + engines: {node: '>=18.16.0'} + '@vitejs/plugin-vue@5.2.4': resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1158,6 +2223,13 @@ packages: vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 + '@vitejs/plugin-vue@6.0.10': + resolution: {integrity: sha512-b80aUQh3n+qEzzZm5oQp3rT2QImeCx58K6eFl/RkJ3d65KW0kTuv5lNsLRVAjbW9YRUpo/wzmvzMgV34bTAItA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 || ^3.6.0-rc.10 + '@vladfrangu/async_event_emitter@2.4.7': resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -1182,36 +2254,66 @@ packages: '@vue/compiler-core@3.5.40': resolution: {integrity: sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==} + '@vue/compiler-core@3.5.43': + resolution: {integrity: sha512-zdiLhnbe1QQqgDT8xZMpNmyqZ3qlI+/Q/FHQco57Kwl/b05HhCzN6eVGN9QU9rbga4CrS0H5SYY8VGHZCt/1Hg==} + '@vue/compiler-dom@3.5.40': resolution: {integrity: sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==} + '@vue/compiler-dom@3.5.43': + resolution: {integrity: sha512-PEZoAk3NQmsn/ejMzSOCyTYqwGqczrWm70PuhBKjjv1+TCoQAaO/zOqNwjV+honlNstT5ILxtc+8r8UUfj+iEQ==} + '@vue/compiler-sfc@3.5.40': resolution: {integrity: sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==} + '@vue/compiler-sfc@3.5.43': + resolution: {integrity: sha512-FCbrG3XNCRl+js3huuKx4IVHBLTvMkJhVepjbxSPu1gn4yWLaYtGNQdjJGZaMytXB6qb76qQDDmDSLy/vkmleQ==} + '@vue/compiler-ssr@3.5.40': resolution: {integrity: sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==} + '@vue/compiler-ssr@3.5.43': + resolution: {integrity: sha512-GF62orf7KiJX9RqrHNGrYBudsQGD0OhJ5nDs90O8UiDuS40+YMYomiXu6w6EuvtXuRDc3MSNis3EaaSKAVSWpg==} + '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + '@vue/language-core@3.3.13': + resolution: {integrity: sha512-axA0Xemn5LuUKuKWob0/kVq7xQ2mJJM6VqA9Exvt35nM9yRC31goWVve/G/Zb2ZCLsXC8FHYjjfXlnshknSCew==} + '@vue/language-core@3.3.7': resolution: {integrity: sha512-LzmkKinXAMMoh8Jfi/jMUSDUjuPdv8mynH5WJGKfXyZtDw3hQ6GBaoI6Bcnl/Xqlu32q/0Z6i/trp4VXykzyLw==} '@vue/reactivity@3.5.40': resolution: {integrity: sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==} + '@vue/reactivity@3.5.43': + resolution: {integrity: sha512-G/c9GyOZNI2jVaaS6OX1EF1SSFSv7H0ERqNTl4+DTFMlZmB5eVAB53aLQNam/7NL2NPtaDD7RdVrzf8uJzMuOA==} + '@vue/runtime-core@3.5.40': resolution: {integrity: sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==} + '@vue/runtime-core@3.5.43': + resolution: {integrity: sha512-hU6U6VnVhBGQDpvlnnDlIB8ZGJBiOcgk2lh/0InltHiz3D8oSkluvuvY+do1G2H3+udeKFsmaBlgVYP7gXQzEw==} + '@vue/runtime-dom@3.5.40': resolution: {integrity: sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==} + '@vue/runtime-dom@3.5.43': + resolution: {integrity: sha512-Bb2Jc0YjjJdMt1SJmb9b2L/IWd3I8lIT9x9eS/xvvP9CiVgna0ffua74xKRmt4/uSJ+0r4iN8ex1jrqkhQGWQw==} + '@vue/server-renderer@3.5.40': resolution: {integrity: sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==} + '@vue/server-renderer@3.5.43': + resolution: {integrity: sha512-l2Ygjv9NehV94PSBxNWsAHC0j/eIIKbn92mBuWXAPGLnn6HfJ6MH5ubsd+Nk0YoZ5FRuxWI1P2VSoh+dbPQhCQ==} + '@vue/shared@3.5.40': resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==} + '@vue/shared@3.5.43': + resolution: {integrity: sha512-uksS7YGMR5NZyr4JNq0Rp+QyLns0ueaz20KwzIPW9R0LH1Vnt4E+XUM29PNseEbf1www2gOuhuDi5AKOIXag9Q==} + '@vue/tsconfig@0.7.0': resolution: {integrity: sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==} peerDependencies: @@ -1223,6 +2325,19 @@ packages: vue: optional: true + '@vueuse/core@14.4.0': + resolution: {integrity: sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@14.4.0': + resolution: {integrity: sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==} + + '@vueuse/shared@14.4.0': + resolution: {integrity: sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==} + peerDependencies: + vue: ^3.5.0 + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -1268,6 +2383,18 @@ packages: alien-signals@3.2.1: resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} + angular-html-parser@10.13.0: + resolution: {integrity: sha512-7s1jbhRE+I4POZHNiIRtm3FhDsfiH2dtPqdNBW2Y7vYvqcuRN1lGxPJucfLouRjiEYSvJbMg0XfOh88QTBm3Lw==} + engines: {node: '>= 14'} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1280,6 +2407,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -1305,6 +2436,13 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + argparse@3.0.3: + resolution: {integrity: sha512-Sn98ftV3KfsO8xfLPHG6oT8y+b0yvbrLgZjgPDXsharNY15tTAjqIsIju4S32nl6/iEUNNE4v+yL2Zhm8ooP3w==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + array-find-index@1.0.2: resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} engines: {node: '>=0.10.0'} @@ -1320,6 +2458,17 @@ packages: resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} engines: {node: '>=12'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} @@ -1348,6 +2497,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1355,6 +2508,10 @@ packages: resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} engines: {node: '>=6.0.0'} + basic-auth@2.0.1: + resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} + engines: {node: '>= 0.8'} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -1369,6 +2526,10 @@ packages: brace-expansion@2.1.2: resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1383,6 +2544,10 @@ packages: resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} engines: {node: '>=6.14.2'} + bundle-name@4.1.1: + resolution: {integrity: sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==} + engines: {node: '>=18'} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -1411,18 +2576,42 @@ packages: resolution: {integrity: sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==} engines: {node: '>=12.20'} + camelcase@9.0.0: + resolution: {integrity: sha512-TO9xmyXTZ9HUHI8M1OnvExxYB0eYVS/1e5s7IDMTAoIcwUd+aNcFODs6Xk83mobk0velyHFQgA1yIrvYc6wclw==} + engines: {node: '>=20'} + + case-anything@3.1.7: + resolution: {integrity: sha512-52UPzAJDZgxaNsYK4kvmov1kVaAfPc+OU2j0OSUZWbdWMuJd7Axi94XWSfSuafMd7K9avhsEnU6W6rXJdAd+Ug==} + engines: {node: '>=18'} + cbor@8.1.0: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + check-disk-space@3.4.0: + resolution: {integrity: sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==} + engines: {node: '>=16'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + chunkd@2.0.1: resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} @@ -1441,18 +2630,41 @@ packages: resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} engines: {node: '>=0.10.0'} + cli-boxes@4.0.1: + resolution: {integrity: sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw==} + engines: {node: '>=18.20 <19 || >=20.10'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-truncate@5.2.0: + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} + engines: {node: '>=20'} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cluster-key-slot@1.1.1: + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} + engines: {node: '>=0.10.0'} + cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + code-excerpt@4.0.0: resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1467,6 +2679,16 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.19: + resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} @@ -1482,14 +2704,25 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} + engines: {node: '>=18'} + convert-to-spaces@2.0.1: resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie-signature@1.0.7: resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} @@ -1497,6 +2730,9 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} @@ -1510,6 +2746,10 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + csrf@3.1.0: + resolution: {integrity: sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==} + engines: {node: '>= 0.8'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -1518,6 +2758,9 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + csv-stringify@6.9.0: + resolution: {integrity: sha512-6b3e29CILFfSQ2nDRuZMRROzQOpPuJ+s8zPB5H7eK5ncXBbFOyVuRLU5Sx/zAUmVri3Ly49GyC8NEme4SVSAbA==} + currently-unhandled@0.4.1: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} @@ -1526,6 +2769,9 @@ packages: resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} engines: {node: '>=6'} + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dayjs@1.11.21: resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} @@ -1537,6 +2783,15 @@ packages: supports-color: optional: true + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1558,10 +2813,29 @@ packages: resolution: {integrity: sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.1: + resolution: {integrity: sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==} + engines: {node: '>=18'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} @@ -1589,6 +2863,9 @@ packages: resolution: {integrity: sha512-tU2NFr823X3TXEc8KyR/4m296KLxPai4nirN3q9kHCpY4TKj96n9lHZnyLzRNMui8EbL07jg9hgH2PWWfKMGIg==} engines: {node: '>=18'} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -1604,6 +2881,22 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + edge-error@4.0.2: + resolution: {integrity: sha512-jB76VYn8wapDHKHSOmP3vbKLoa77RJYsTLNmfl8+cuCD69uxZtP3h+kqV+Prw/YkYmN7yHyp4IApE15pDByk0A==} + engines: {node: '>=18.16.0'} + + edge-lexer@6.0.5: + resolution: {integrity: sha512-paSprHn8GRzOUWTVLapgacqDBSOpJgOY60/V5QQ8bbNLHRKUMSxp8Z2oOO0WKtcKmb5+sAlmvG3izhbFulp19A==} + engines: {node: '>=24.0.0'} + + edge-parser@9.1.1: + resolution: {integrity: sha512-kem/vInJgTzHCABdFe060WGjyGva8j23QwVbZkNFXkNAQhRz3mga5kNBuPFYQ3t73nPT2vZ8WOGV4OCS0P16Cw==} + engines: {node: '>=24.0.0'} + + edge.js@6.5.1: + resolution: {integrity: sha512-+NgWA8KunEdhVB247GWdmqUZ3MSIExeUCAbWNgNvA0ONH43UL+a/l6AE8GsevT4beqVsbp4Q6USwSpfbnMqBkQ==} + engines: {node: '>=18.16.0'} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -1621,14 +2914,35 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enhanced-resolve@5.24.2: resolution: {integrity: sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw==} engines: {node: '>=10.13.0'} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + entities@8.1.0: + resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} + engines: {node: '>=20.19.0'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + error-stack-parser-es@2.0.1: + resolution: {integrity: sha512-J36ntO+rMQVRuR/umlmxmfLi4TpWwtmTnHoJoXTiC2xDNazs0VDPKcX6pbhZMDd2HFtH9isMBJXMdbki+A++Pg==} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -1637,14 +2951,24 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} + es-toolkit@1.52.0: + resolution: {integrity: sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==} + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-goat@4.0.0: + resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} + engines: {node: '>=12'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -1680,6 +3004,10 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + express@4.22.2: resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} engines: {node: '>= 0.10.0'} @@ -1687,6 +3015,9 @@ packages: fast-content-type-parse@1.1.0: resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} + fast-copy@4.1.2: + resolution: {integrity: sha512-DUHggaYcouhy5I1LacDJ+JDSqGlumVJP2EAi5Nwt1pWPeLpSvIjkrY+x4fsoI1/+GlTyq+DM9zdgWCFSfqNODA==} + fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} @@ -1706,12 +3037,19 @@ packages: fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-uri@2.4.2: resolution: {integrity: sha512-Ll1wlF3LBJ2+vFEeTSH9SFrjnXJorZQexrn0yHa4BJdGS+FFkWW3xU/YuIdmdyloSDuUgTYh/YeY/vUNcdCS/g==} fast-uri@3.1.3: resolution: {integrity: sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==} + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fastify-plugin@4.5.1: resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} @@ -1734,6 +3072,14 @@ packages: resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} engines: {node: '>=14'} + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + + file-type@22.1.1: + resolution: {integrity: sha512-sEB0oStmeLGtpmSAD88RDNuLsvhv4iC3u0lE25CUvfCULvj49xoQ3l3K525Vn+ZzsZ6DOLajQCV6RmhwwhqiJg==} + engines: {node: '>=22'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1742,10 +3088,18 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} + find-cache-directory@6.0.0: + resolution: {integrity: sha512-CvFd5ivA6HcSHbD+59P7CyzINHXzwhuQK8RY7CxJZtgDSAtRlHiCaQpZQ2lMR/WRyUIEmzUvL6G2AGurMfegZA==} + engines: {node: '>=20'} + find-my-way@8.2.2: resolution: {integrity: sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==} engines: {node: '>=14'} + find-up-simple@1.0.1: + resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} + engines: {node: '>=18'} + find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -1754,6 +3108,10 @@ packages: resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -1773,6 +3131,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -1792,18 +3154,44 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.7.0: + resolution: {integrity: sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-port@7.2.0: + resolution: {integrity: sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==} + engines: {node: '>=16'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + + get-tsconfig@4.14.3: + resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} + + getopts@2.3.0: + resolution: {integrity: sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -1820,6 +3208,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -1835,6 +3227,13 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} @@ -1842,6 +3241,16 @@ packages: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + + hot-hook@1.0.0: + resolution: {integrity: sha512-OkZm5tTE4ej8ur8VlcQwMm8G9sFxu4D+shM+ol/h4mrUhuZvFkjk5n/nWKmLq3COmy6epLN7XIIQJ75tnqCGIw==} + + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -1850,6 +3259,10 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + humanize-duration@3.34.0: resolution: {integrity: sha512-NDxhYxiiRzsST6xULIHuYWRvsCtviJXRdjarhyWyh78S4Ou+MWhM2k4HQ+y7iegdrzreXe11isd0au1N2PB/pQ==} @@ -1864,6 +3277,10 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + igniculus@1.5.0: + resolution: {integrity: sha512-vhj2J/cSzNg2G5tcK4Z1KZdeYmQa5keoxFULUYAxctK/zHJb1oraO7noCqnJxKe1b2eZdiiaSL1IHPOFAI8UYQ==} + engines: {node: '>=4.0.0'} + ignore-by-default@2.1.0: resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} engines: {node: '>=10 <11 || >=12 <13 || >=14'} @@ -1872,6 +3289,12 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -1880,9 +3303,25 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + + inflation@2.1.0: + resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==} + engines: {node: '>= 0.8.0'} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + interpret@2.2.0: + resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} + engines: {node: '>= 0.10'} + + ioredis@6.0.0: + resolution: {integrity: sha512-f+Dtubxfpf6KYFq7WVXJoOLn0bk4TJrMrN9SzeE+jrWrCWj7XX3fA6vkryafhADX+GMymRxgDJDOI33COkJc0w==} + engines: {node: '>=20.0.0'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -1899,6 +3338,15 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} + is-core-module@2.17.0: + resolution: {integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==} + engines: {node: '>= 0.4'} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-error@2.2.2: resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} @@ -1914,10 +3362,23 @@ packages: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -1926,6 +3387,10 @@ packages: resolution: {integrity: sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==} engines: {node: '>=8'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} @@ -1936,6 +3401,10 @@ packages: is-property@1.0.2: resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-typed-array@1.1.15: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} @@ -1944,6 +3413,17 @@ packages: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -1953,14 +3433,28 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jest-diff@30.5.2: + resolution: {integrity: sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-string-escape@1.0.1: resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} engines: {node: '>= 0.8'} + js-stringify@1.0.2: + resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@3.15.0: resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==} hasBin: true @@ -1988,9 +3482,76 @@ packages: jsonfile@5.0.0: resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==} + jsonschema@1.5.0: + resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==} + + jszip@3.10.2: + resolution: {integrity: sha512-3l+rb15IOWtUhU0H5MFqES/T6Kh7abYwjosBey/vD6hDt8zoEffkSC5Ws5SGtgVw3gBx2NEbhTeSW1+kWkpyTQ==} + + junk@4.0.1: + resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} + engines: {node: '>=12.20'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + knex-dynamic-connection@5.1.1: + resolution: {integrity: sha512-xtl22O5I8e+G3ie90FfRaiODnYDgLD1erJeaeKVP+zuj4WMNJpgdmhs0qVaeigAJXsthCYA+pjmegXZh4xg2TA==} + engines: {node: '>=24.0.0'} + + knex@3.3.0: + resolution: {integrity: sha512-LgWl031hNuLv9Lhxdd9093zULa2aNcoP04Bk29e5NidgRcEr/T0rAr2WYi4BhjTiCDoQiRU56meUE5rppLKZzQ==} + engines: {node: '>=16'} + hasBin: true + peerDependencies: + better-sqlite3: '*' + mariadb: '*' + mysql: '*' + mysql2: '*' + pg: '*' + pg-native: '*' + pg-query-stream: ^4.14.0 + sqlite3: '*' + tedious: '*' + peerDependenciesMeta: + better-sqlite3: + optional: true + mariadb: + optional: true + mysql: + optional: true + mysql2: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + sqlite3: + optional: true + tedious: + optional: true + knub-command-manager@9.1.0: resolution: {integrity: sha512-pEtpWElbBoTRSL8kWSPRrTIuTIdvYGkP/wzOn77cieumC02adfwEt1Cc09HFvVT4ib35nf1y31oul36csaG7Vg==} + ky@1.14.3: + resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} + engines: {node: '>=18'} + + laravel-precognition@2.1.0: + resolution: {integrity: sha512-W9ZobjRAReiIawSWxXUPR6q+Bvq5seO6tn+scdURl/JKOFKveXvR4Sno2KxGqQt2cI81nh8Vt2cFlaOMqXqLNw==} + peerDependencies: + axios: ^1.4.0 + peerDependenciesMeta: + axios: + optional: true + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + light-my-request@5.14.0: resolution: {integrity: sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==} @@ -2000,30 +3561,60 @@ packages: cpu: [arm64] os: [android] + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.32.0: resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.32.0: resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.32.0: resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.32.0: resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} @@ -2031,6 +3622,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} @@ -2038,6 +3636,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} @@ -2045,6 +3650,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} @@ -2052,22 +3664,48 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.32.0: resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.32.0: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + linkify-it@6.1.0: + resolution: {integrity: sha512-wJ/TwpSDTLepCrQoYWYIExIKg5Zchex2Nn5yk2mFnB+6PtdkHtyLx742md9csRjjOnGkKIS/RrbY7l8D6gT9Vw==} + load-json-file@7.0.1: resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2089,16 +3727,34 @@ packages: lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + log-update@7.2.0: + resolution: {integrity: sha512-iLs7dGSyjZiUgvrUvuD3FndAxVJk+TywBkkkwUSm9HdYoskJalWg5qVsEiXeufPvRVPbCUmNQewg798rx+sPXg==} + engines: {node: '>=20'} + long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + lru.min@1.1.4: resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lucide-vue-next@1.0.0: + resolution: {integrity: sha512-V6SPvx1IHTj/UY+FrIYWV5faISsPSb8BnWSFDxAtezWKvWc9ZZ40PDrdu1/Qb5vg4lHWr1hs1BAMGVGm6V1Xdg==} + deprecated: Package deprecated. Please use @lucide/vue instead. + peerDependencies: + vue: '>=3.0.1' + + luxon@3.7.2: + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} + magic-bytes.js@1.13.0: resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==} @@ -2109,6 +3765,10 @@ packages: resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} engines: {node: '>=6'} + markdown-it@15.0.2: + resolution: {integrity: sha512-q4IGxMv56jCqT4OCRCADBoDP3LO4MhmTXjFbphHPXs4g3j9Xg5RDnxqN8IF/3vIWEU+VCnUq+7JUg/cfy2E6Qw==} + hasBin: true + marked@5.1.2: resolution: {integrity: sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg==} engines: {node: '>= 16'} @@ -2126,10 +3786,17 @@ packages: resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} engines: {node: '>=8'} + mdurl@2.1.0: + resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + mem@9.0.2: resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} engines: {node: '>=12.20'} @@ -2153,10 +3820,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -2171,6 +3846,14 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -2213,6 +3896,9 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2238,6 +3924,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -2371,10 +4062,22 @@ packages: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} engines: {node: '>=12.19'} + normalize-package-data@8.0.0: + resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==} + engines: {node: ^20.17.0 || >=22.9.0} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-url@8.1.1: + resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==} + engines: {node: '>=14.16'} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + oauth@0.10.2: resolution: {integrity: sha512-JtFnB+8nxDEXgNyniwz573xxbKSOu3R8D40xQKqcjwJ2CDkYqUDI53o6IuzDJBx60Z8VKCm271+t8iFjakrl8Q==} @@ -2386,9 +4089,15 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + object-to-formdata@4.5.1: + resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + observable-fns@0.6.1: resolution: {integrity: sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==} + ohash@2.0.12: + resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -2397,6 +4106,17 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@11.0.4: + resolution: {integrity: sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==} + engines: {node: '>=20'} + oxfmt@0.59.0: resolution: {integrity: sha512-Xqk6cPZS1yMvVa7OAuenaDZUsgMDutvvbZ9/L5gSvAfW64+WN4HVhgipLj5rVERbYQt8fLs9TopyZ1rU1XEG/w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2462,13 +4182,31 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.9.0: + resolution: {integrity: sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parse-color@1.0.0: resolution: {integrity: sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==} + parse-imports@3.0.0: + resolution: {integrity: sha512-IwiqoJANa4O6M76LBWEvoS2iPIUqBOnKG1lV3/J0oVM6V2XjED+mYAXedEMX5xUglVjfGpZOfaEyuOUjBuUE4g==} + engines: {node: '>= 22'} + + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-ms@3.0.0: resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} engines: {node: '>=12'} + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -2504,6 +4242,13 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -2518,6 +4263,9 @@ packages: pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2529,12 +4277,27 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-pretty@13.2.0: + resolution: {integrity: sha512-jjghD1ML+Di/WxjJDz6j6Y4FT7hIXOlb8h27AyJ+ohtAXJXH4PS/xkv7si+RCCIW59HMgZsMKTDgzdr0RhuRrg==} + hasBin: true + pino-std-serializers@7.1.0: resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + pino@10.4.0: + resolution: {integrity: sha512-bk1ZMTwG/Vymx+zPoa28MhNzucFvXJWp3csrSuxuHPSMeUettaCoQ5Jvg07mtC4JGNpcfTwz41oVCnNgBK9+vA==} + hasBin: true + pino@9.14.0: resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} hasBin: true @@ -2543,14 +4306,32 @@ packages: resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + pkg-dir@8.0.0: + resolution: {integrity: sha512-4peoBq4Wks0riS0z8741NVv+/8IiTvqnZAr8QGgtdifrtpdXbNw/FxRS1l6NFqm4EMzuS0EDqNNx4XGaz8cuyQ==} + engines: {node: '>=18'} + pkg-up@3.1.0: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} + playwright-core@1.64.0: + resolution: {integrity: sha512-T9r+MZkTECl2+oUcZ26YgZzTrYidTsIhYYkJix+6iDOymOb1FB2RLLSOxRGnZGv5DStt+aduIVbt+E8WygXYpg==} + engines: {node: '>=20'} + hasBin: true + + playwright@1.64.0: + resolution: {integrity: sha512-kVzTnYFYEyQ9RGzBjNCd2+yEqWmVbxl3AHPynv3qQ6JTjv4a+kwRcnqQwIpuP3NnrnIrE/Q6wWAIAvMfIE2/Yg==} + engines: {node: '>=20'} + hasBin: true + plur@5.1.0: resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -2569,21 +4350,53 @@ packages: resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.29: + resolution: {integrity: sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==} + engines: {node: ^10 || ^12 || >=14} + + powershell-utils@0.2.1: + resolution: {integrity: sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==} + engines: {node: '>=20'} + + prettier-edge@1.0.0: + resolution: {integrity: sha512-D8DwcGGPVWhMUrrE0+R242laEezGmvOpdCdvwVZiySpebZ1H5o7xwmDYhRw//ckOz1EcLOtQyJt/eQ2UC3eXOw==} + engines: {node: '>=18'} + peerDependencies: + prettier: ^3.0.0 + prettier@3.9.6: resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} engines: {node: '>=14'} hasBin: true + pretty-format@30.5.1: + resolution: {integrity: sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + pretty-hrtime@1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + pretty-ms@8.0.0: resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} engines: {node: '>=14.16'} + pretty-ms@9.3.1: + resolution: {integrity: sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==} + engines: {node: '>=18'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process-warning@3.0.0: resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -2591,6 +4404,13 @@ packages: proxy-disposable@1.0.0: resolution: {integrity: sha512-Y673BKpFqk8XkYuoK9DGZ1RIzldz5SkzxTKc/+DkpaMdrDEbEalWlO/uMRMdJsXvdbTybJI26XDwN0KJpZDN4w==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + qs@6.15.3: resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} engines: {node: '>=0.6'} @@ -2601,26 +4421,69 @@ packages: quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + random-bytes@1.0.0: + resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} + engines: {node: '>= 0.8'} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + rate-limiter-flexible@9.1.1: + resolution: {integrity: sha512-imxFjzPCmvDLMe7d2tsgiSQvs5EI2fI9SNymmslAfOqznZhsZ+PqbIjIYKpuSbd3pKovR1aMG47qfCLIO/adVg==} + raw-body@2.5.3: resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} engines: {node: '>= 0.8'} - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-is@19.3.0: + resolution: {integrity: sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==} + + read-package-up@12.0.0: + resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==} + engines: {node: '>=20'} + + read-pkg@10.1.0: + resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==} + engines: {node: '>=20'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + real-require@1.0.0: + resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + + rechoir@0.8.0: + resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} + engines: {node: '>= 10.13.0'} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + redis@5.12.1: resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==} engines: {node: '>= 18.19.0'} @@ -2639,6 +4502,11 @@ packages: resolution: {integrity: sha512-FpHJ2gdS6VI0LF+HkksqkugJqlPZwxXW8xRRCWBrx/wh2MQnYsST0WUHCe36WqGk/KpLo9DEaLVzjl3CvxPDEw==} engines: {node: '>= 12.0.0'} + reka-ui@2.11.0: + resolution: {integrity: sha512-ilkpm4bIAol4jwzm4tpm3WVcffyGOpqksNZL1k1qO9QmIwAA+q8jroxjkUGLEn/GddfdExFfvofWfQiKZszUeQ==} + peerDependencies: + vue: '>= 3.4.0' + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -2658,10 +4526,26 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.13: + resolution: {integrity: sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + ret@0.4.3: resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==} engines: {node: '>=10'} + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -2669,14 +4553,29 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rndm@1.2.0: + resolution: {integrity: sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==} + rolldown@1.1.5: resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rolldown@1.2.13: + resolution: {integrity: sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2696,6 +4595,9 @@ packages: secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.1.1: + resolution: {integrity: sha512-lnd81MQEZKjhW/Gd2TQqdd4XP6QYNdDW/EP+I7nTrFHP9y2LmaGPIHk9xsnzcOiEr1c39c/e84xFgGviQKBTRw==} + seedrandom@3.0.5: resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} @@ -2708,6 +4610,10 @@ packages: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + serialize-error@7.0.1: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} @@ -2716,6 +4622,10 @@ packages: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -2723,6 +4633,9 @@ packages: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -2763,17 +4676,39 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slashes@3.0.12: + resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} + slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} + slice-ansi@8.0.0: + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} + + slugify@1.6.9: + resolution: {integrity: sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==} + engines: {node: '>=8.0.0'} + sonic-boom@4.2.1: resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + sonic-boom@5.0.2: + resolution: {integrity: sha512-/JEruzo6yhNVhsLblTRchgTQHIt7SsdJP0YyrfWaNKjIOQDfrdZv9gwYraYCAsmKV39/LAdV31FLL5NCDpoL/A==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -2781,6 +4716,22 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.24: + resolution: {integrity: sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ==} + + split-lines@3.0.0: + resolution: {integrity: sha512-d0TpRBL/VfKDXsk8JxPF7zgF5pCUDdBMSlEL36xBgVeaX448t+yGXcJaikUyzkoKOJ0l6KpMfygzJU9naIuivw==} + engines: {node: '>=12'} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -2800,6 +4751,9 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -2820,9 +4774,20 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@8.3.0: + resolution: {integrity: sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==} + engines: {node: '>=20'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-attributes@4.0.0: + resolution: {integrity: sha512-6Hq3K153wTTfhEHb4V/viuqmb0DRn08JCrRnmqc4Q/tmoNuvd4DEyqkiiJXtvVz8ZSUhlCQr7zCpCVTgrelesg==} + engines: {node: '>=14.16'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2838,10 +4803,38 @@ packages: strip-combining-marks@1.0.0: resolution: {integrity: sha512-8YrtmJKxvDmMIoJMOyvh/s3Oe8TxolM5ThgZPmE39vvkfXVuOHAUyiZ1yOZUxDg/kb1QLRyZ0CfQQqeTISAeTA==} + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + strtok3@10.4.0: + resolution: {integrity: sha512-zzNQzrgQUNHyFFDzGCkzgWPgxiBcfwqg+/RNK9cZHKRH95KuCKxqXBXe+jC/1Xq+MRLAe/DkizyPe3kR37QV3w==} + engines: {node: '>=18'} + supertap@3.0.1: resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + tailwindcss@4.3.3: resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} @@ -2849,23 +4842,50 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tarn@3.1.2: + resolution: {integrity: sha512-3RTvqKZcK/17jnJ8rMKFXbyNogywTs1z0gVPPwFsJGX46rkmUHOdIaSQ/aVO1rS7nH+soiXiWk7rvUXxndm8Dg==} + engines: {node: '>=8.0.0'} + temp-dir@3.0.0: resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} engines: {node: '>=14.16'} + tempura@0.4.1: + resolution: {integrity: sha512-NQ4Cs23jM6UUp3CcS5vjmyjTC6dtA5EsflBG2cyG0wZvP65AV26tJ920MGvTRYIImCY13RBpOhc7q4/pu+FG5A==} + engines: {node: '>=10'} + + terminal-size@4.0.1: + resolution: {integrity: sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ==} + engines: {node: '>=18'} + thread-stream@3.2.0: resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==} + thread-stream@4.2.0: + resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} + engines: {node: '>=20'} + threads@1.7.0: resolution: {integrity: sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==} + tildify@2.0.0: + resolution: {integrity: sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==} + engines: {node: '>=8'} + time-zone@1.0.0: resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} engines: {node: '>=4'} + timekeeper@2.3.1: + resolution: {integrity: sha512-LeQRS7/4JcC0PgdSFnfUiStQEdiuySlCj/5SJ18D+T1n9BoY7PxKFfCwLulpHXoLUFr67HxBddQdEX47lDGx1g==} + tiny-worker@2.3.0: resolution: {integrity: sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -2878,6 +4898,10 @@ packages: resolution: {integrity: sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==} hasBin: true + tmp-cache@1.1.0: + resolution: {integrity: sha512-j040fkL/x+XAZQ9K3bKGEPwgYhOZNBQLa3NXEADUiuno9C+3N2JJA4bVPDREixp604G3/vTXWA3DIPpA9lu1RQ==} + engines: {node: '>=6'} + tmp@0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} @@ -2898,6 +4922,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + ts-essentials@10.2.1: resolution: {integrity: sha512-+Id1fRkuir+CsgK2x04/icS2b4V1hQmq7ObzIrDjhN0ozfRYivnP7aaKMVJfLApQm0trjR39A6NIMVchiB9Erw==} peerDependencies: @@ -2909,6 +4937,9 @@ packages: ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} + ts-morph@28.0.0: + resolution: {integrity: sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g==} + ts-toolbelt@9.6.0: resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} @@ -2918,6 +4949,10 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsscmp@1.0.6: + resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} + engines: {node: '>=0.6.x'} + twemoji-parser@12.1.3: resolution: {integrity: sha512-ND4LZXF4X92/PFrzSgGkq6KPPg8swy/U0yRw1k/+izWRVmq1HYi3khPwV3XIB6FRudgVICAaBhJfW8e8G3HC7Q==} @@ -2928,10 +4963,22 @@ packages: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-fest@5.10.0: + resolution: {integrity: sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==} + engines: {node: '>=20'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -3004,12 +5051,26 @@ packages: engines: {node: '>=16.20.0'} hasBin: true + uc.micro@3.0.0: + resolution: {integrity: sha512-U3PppEkleoTnIfi8BozMx3yju3qc/L6SwqWo2Sw+54PX+PX0q9I+r1Um5HCmqD7n9VDX5/v3vQH/AjA6deDdtw==} + + uid-safe@2.1.5: + resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==} + engines: {node: '>= 0.8'} + uid2@0.0.4: resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==} + uint8array-extras@1.6.0: + resolution: {integrity: sha512-8iAasVS4wUx0gPLjH8Xtz2PeDzTSiy8QiLGu2DT3X5GU+egFEQhpnbtkehbAwjvDcxIERmCYcysiODFmE3Ud0Q==} + engines: {node: '>=18'} + undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@8.9.0: + resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} + undici@6.21.3: resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} engines: {node: '>=18.17'} @@ -3018,6 +5079,14 @@ packages: resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==} engines: {node: '>=18.17'} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unicorn-magic@0.4.1: + resolution: {integrity: sha512-lzlXPoVB0Uy/FvTaUgX39RbixYiSKoc3JSoSf01+0c2B6FR3qdYIPN7Qjo/AV7n6sqLCk0509cT3LRj1oSZ1+A==} + engines: {node: '>=20'} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -3046,6 +5115,13 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} + engines: {node: '>= 0.10'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -3097,6 +5173,49 @@ packages: yaml: optional: true + vite@8.3.4: + resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vscode-jsonrpc@9.0.1: resolution: {integrity: sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==} engines: {node: '>=14.0.0'} @@ -3121,6 +5240,26 @@ packages: peerDependencies: vue: ^3.5.0 + vue-sonner@2.0.9: + resolution: {integrity: sha512-i6BokNlNDL93fpzNxN/LZSn6D6MzlO+i3qXt6iVZne3x1k7R46d5HlFB4P8tYydhgqOrRbIZEsnRd3kG7qGXyw==} + peerDependencies: + '@nuxt/kit': ^4.0.3 + '@nuxt/schema': ^4.0.3 + nuxt: ^4.0.3 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + '@nuxt/schema': + optional: true + nuxt: + optional: true + + vue-tsc@3.3.13: + resolution: {integrity: sha512-jE4/bXdOMSHVxEGgQCqNllJy+9N3Gx6tfSAsg0yhFK/MAN6eXqISihupnDEKSCt12VVnjN2gI3AqLYcqoh5x/A==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + vue-tsc@3.3.7: resolution: {integrity: sha512-+C+rgD49wAQ5bUTl2sp5a8Bzg4YoldMNXM+g7CFe604MYcQ8PrZPMQhIjJSzKXtPBCa+C5ayMipqjbA7splekQ==} hasBin: true @@ -3146,6 +5285,14 @@ packages: typescript: optional: true + vue@3.5.43: + resolution: {integrity: sha512-o5qZoksdnjIKvW1srZ3ab7pcDNYAerBjRe54D0LBLfRdCYFrSgBHVXokMas35czQc0//lmx4/tuY4ZNQ+Rf2Ng==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + vuex@4.1.0: resolution: {integrity: sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==} peerDependencies: @@ -3164,6 +5311,10 @@ packages: engines: {node: '>= 8'} hasBin: true + wrap-ansi@10.0.2: + resolution: {integrity: sha512-6OLRNZqRntVGBm26ghZ5eZhCuWWyOkRCSn8XsOIuq5stpCE/tjLbdozd93naILZig0lmD8ANfRwnhn0DLeXGlg==} + engines: {node: '>=20'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -3172,6 +5323,9 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -3188,6 +5342,10 @@ packages: utf-8-validate: optional: true + wsl-utils@1.0.1: + resolution: {integrity: sha512-c16PKLIRxBYpR3jSWsdS7SFp0COm5SOQdiFjY818dYFHJbMGuLBszpF07LBWmOS1uzrHa9VGdynsEgoeKy0oOQ==} + engines: {node: '>=20'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -3201,6 +5359,10 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.3: resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} @@ -3209,11 +5371,412 @@ packages: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} + yoctocolors@2.2.0: + resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} + engines: {node: '>=18'} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.1: + resolution: {integrity: sha512-mxW3qiSnl+GRxXsaUMzv2Mbada1Y8CDltET9UxejDQe6DBYlSekghl5U5K0ReAikcHDi0G1vKZEmmo/NWAGKLA==} + zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} snapshots: + '@adonisjs/ace@14.1.1(youch@4.1.1)': + dependencies: + '@poppinss/cliui': 6.8.1 + '@poppinss/hooks': 7.3.1 + '@poppinss/macroable': 1.1.2 + '@poppinss/prompts': 3.1.6 + '@poppinss/utils': 7.1.1 + fastest-levenshtein: 1.0.16 + jsonschema: 1.5.0 + string-width: 8.3.0 + yargs-parser: 22.0.0 + youch: 4.1.1 + + '@adonisjs/ally@6.3.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/inertia@5.0.1(3f17abe654a593f174d8c7d5a3b95857))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@poppinss/oauth-client': 7.2.0 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@adonisjs/inertia': 5.0.1(3f17abe654a593f174d8c7d5a3b95857) + '@adonisjs/session': 8.1.0(770cc5139ed8289213226f432e14c982) + + '@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0)': + dependencies: + '@adonisjs/config': 6.1.0 + '@adonisjs/fold': 11.1.0 + '@poppinss/hooks': 7.3.1 + '@poppinss/macroable': 1.1.2 + '@poppinss/utils': 7.1.1 + glob-parent: 6.0.2 + tempura: 0.4.1 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + + '@adonisjs/assembler@8.5.2(typescript@6.0.3)': + dependencies: + '@adonisjs/env': 7.1.0 + '@antfu/install-pkg': 2.1.0 + '@ast-grep/napi': 0.45.3 + '@poppinss/cliui': 6.8.1 + '@poppinss/hooks': 7.3.1 + '@poppinss/utils': 7.1.1 + chokidar: 5.0.0 + dedent: 1.7.2 + execa: 9.6.1 + fast-glob: 3.3.3 + fdir: 6.5.0(picomatch@4.0.5) + get-port: 7.2.0 + get-tsconfig: 4.14.3 + import-meta-resolve: 4.2.0 + junk: 4.0.1 + open: 11.0.4 + parse-imports: 3.0.0 + picomatch: 4.0.5 + pretty-hrtime: 1.0.3 + tmp-cache: 1.1.0 + ts-morph: 28.0.0 + typescript: 6.0.3 + transitivePeerDependencies: + - babel-plugin-macros + + '@adonisjs/auth@10.1.0(c16d739126567016c4d2c00b96bddf22)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@adonisjs/presets': 3.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1)) + basic-auth: 2.0.1 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + '@adonisjs/session': 8.1.0(770cc5139ed8289213226f432e14c982) + '@japa/browser-client': 2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0) + '@japa/plugin-adonisjs': 5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0) + + '@adonisjs/bodyparser@11.0.4(@adonisjs/http-server@9.3.1(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/events@10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0)(@adonisjs/logger@7.1.1(pino-pretty@13.2.0))(@boringnode/encryption@1.0.1)(youch@4.1.1))(supports-color@10.2.2)': + dependencies: + '@adonisjs/http-server': 9.3.1(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/events@10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0)(@adonisjs/logger@7.1.1(pino-pretty@13.2.0))(@boringnode/encryption@1.0.1)(youch@4.1.1) + '@poppinss/macroable': 1.1.2 + '@poppinss/middleware': 3.2.7 + '@poppinss/multiparty': 3.0.0 + '@poppinss/qs': 6.15.0 + '@poppinss/utils': 7.1.1 + file-type: 22.1.1(supports-color@10.2.2) + inflation: 2.1.0 + media-typer: 1.1.1 + raw-body: 3.0.2 + transitivePeerDependencies: + - supports-color + + '@adonisjs/config@6.1.0': + dependencies: + '@poppinss/utils': 7.1.1 + + '@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1)': + dependencies: + '@adonisjs/ace': 14.1.1(youch@4.1.1) + '@adonisjs/application': 9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0) + '@adonisjs/bodyparser': 11.0.4(@adonisjs/http-server@9.3.1(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/events@10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0)(@adonisjs/logger@7.1.1(pino-pretty@13.2.0))(@boringnode/encryption@1.0.1)(youch@4.1.1))(supports-color@10.2.2) + '@adonisjs/config': 6.1.0 + '@adonisjs/env': 7.1.0 + '@adonisjs/events': 10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0) + '@adonisjs/fold': 11.1.0 + '@adonisjs/hash': 10.1.1 + '@adonisjs/health': 3.1.0 + '@adonisjs/http-server': 9.3.1(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/events@10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0)(@adonisjs/logger@7.1.1(pino-pretty@13.2.0))(@boringnode/encryption@1.0.1)(youch@4.1.1) + '@adonisjs/http-transformers': 2.3.1(@adonisjs/fold@11.1.0) + '@adonisjs/logger': 7.1.1(pino-pretty@13.2.0) + '@adonisjs/repl': 5.0.0 + '@boringnode/encryption': 1.0.1 + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.7.0 + '@poppinss/macroable': 1.1.2 + '@poppinss/utils': 7.1.1 + '@sindresorhus/is': 8.1.0 + '@types/he': 1.2.3 + error-stack-parser-es: 2.0.1 + he: 1.2.0 + pretty-hrtime: 1.0.3 + string-width: 8.3.0 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@vinejs/vine': 4.4.0 + edge.js: 6.5.1 + pino-pretty: 13.2.0 + youch: 4.1.1 + transitivePeerDependencies: + - supports-color + + '@adonisjs/cors@3.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + + '@adonisjs/env@7.1.0': + dependencies: + '@poppinss/utils': 7.1.1 + '@poppinss/validator-lite': 2.1.2 + split-lines: 3.0.0 + + '@adonisjs/events@10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0)': + dependencies: + '@adonisjs/application': 9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0) + '@adonisjs/fold': 11.1.0 + '@poppinss/utils': 7.1.1 + '@sindresorhus/is': 7.2.0 + emittery: 1.2.1 + + '@adonisjs/fold@11.1.0': + dependencies: + '@poppinss/utils': 7.1.1 + parse-imports: 3.0.0 + + '@adonisjs/hash@10.1.1': + dependencies: + '@phc/format': 1.0.0 + '@poppinss/utils': 7.1.1 + + '@adonisjs/health@3.1.0': + dependencies: + '@poppinss/utils': 7.1.1 + check-disk-space: 3.4.0 + + '@adonisjs/http-server@9.3.1(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/events@10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0)(@adonisjs/logger@7.1.1(pino-pretty@13.2.0))(@boringnode/encryption@1.0.1)(youch@4.1.1)': + dependencies: + '@adonisjs/application': 9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0) + '@adonisjs/events': 10.2.0(@adonisjs/application@9.1.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/config@6.1.0)(@adonisjs/fold@11.1.0))(@adonisjs/fold@11.1.0) + '@adonisjs/fold': 11.1.0 + '@adonisjs/logger': 7.1.1(pino-pretty@13.2.0) + '@boringnode/encryption': 1.0.1 + '@boringnode/route-matcher': 0.1.1 + '@poppinss/macroable': 1.1.2 + '@poppinss/matchit': 3.2.0 + '@poppinss/middleware': 3.2.7 + '@poppinss/qs': 6.15.0 + '@poppinss/types': 1.2.1 + '@poppinss/utils': 7.1.1 + '@sindresorhus/is': 8.1.0 + content-disposition: 1.1.0 + cookie-es: 3.1.1 + destroy: 1.2.0 + encodeurl: 2.0.0 + etag: 1.8.1 + fresh: 0.5.2 + mime-types: 3.0.2 + on-finished: 2.4.1 + proxy-addr: 2.0.7 + tmp-cache: 1.1.0 + type-is: 2.1.0 + vary: 1.1.2 + optionalDependencies: + youch: 4.1.1 + + '@adonisjs/http-transformers@2.3.1(@adonisjs/fold@11.1.0)': + dependencies: + '@adonisjs/fold': 11.1.0 + '@poppinss/exception': 1.2.3 + '@poppinss/types': 1.2.1 + + '@adonisjs/inertia@5.0.1(3f17abe654a593f174d8c7d5a3b95857)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@adonisjs/session': 8.1.0(770cc5139ed8289213226f432e14c982) + '@adonisjs/vite': 6.0.3(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/shield@9.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0))(edge.js@6.5.1))(edge.js@6.5.1)(vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0)) + '@poppinss/macroable': 1.1.2 + '@poppinss/utils': 7.1.1 + edge-error: 4.0.2 + edge.js: 6.5.1 + html-entities: 2.6.0 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@inertiajs/core': 3.9.1 + '@inertiajs/vue3': 3.9.1(vue@3.5.43(typescript@6.0.3)) + '@japa/plugin-adonisjs': 5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0) + '@tuyau/core': 1.2.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1)) + vue: 3.5.43(typescript@6.0.3) + + '@adonisjs/limiter@3.0.1(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2))(@adonisjs/redis@11.0.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2))': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + rate-limiter-flexible: 9.1.1 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + '@adonisjs/redis': 11.0.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2) + + '@adonisjs/logger@7.1.1(pino-pretty@13.2.0)': + dependencies: + '@poppinss/utils': 7.1.1 + abstract-logging: 2.0.1 + pino: 10.4.0 + optionalDependencies: + pino-pretty: 13.2.0 + + '@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@adonisjs/presets': 3.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1)) + '@faker-js/faker': 10.6.0 + '@poppinss/hooks': 7.3.1 + '@poppinss/macroable': 1.1.2 + '@poppinss/qs': 6.15.0 + '@poppinss/utils': 7.1.1 + deepmerge: 4.3.1 + fast-deep-equal: 3.1.3 + igniculus: 1.5.0 + kleur: 4.1.5 + knex: 3.3.0(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + knex-dynamic-connection: 5.1.1(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + pretty-hrtime: 1.0.3 + slash: 5.1.0 + tarn: 3.1.2 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@vinejs/vine': 4.4.0 + luxon: 3.7.2 + transitivePeerDependencies: + - better-sqlite3 + - mariadb + - mysql + - mysql2 + - pg + - pg-native + - pg-query-stream + - sqlite3 + - supports-color + - tedious + + '@adonisjs/presets@3.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + + '@adonisjs/prettier-config@1.5.0(prettier@3.9.6)': + dependencies: + prettier-edge: 1.0.0(prettier@3.9.6) + transitivePeerDependencies: + - prettier + + '@adonisjs/redis@11.0.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@poppinss/utils': 7.1.1 + emittery: 1.2.1 + ioredis: 6.0.0(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@adonisjs/repl@5.0.0': + dependencies: + '@poppinss/colors': 4.1.6 + string-width: 8.3.0 + + '@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@poppinss/macroable': 1.1.2 + '@poppinss/utils': 7.1.1 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@vinejs/vine@4.4.0)(luxon@3.7.2)(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + '@adonisjs/redis': 11.0.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2) + '@japa/browser-client': 2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0) + '@japa/plugin-adonisjs': 5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0) + edge.js: 6.5.1 + + '@adonisjs/shield@9.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0))(edge.js@6.5.1)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@adonisjs/session': 8.1.0(770cc5139ed8289213226f432e14c982) + csrf: 3.1.0 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@japa/plugin-adonisjs': 5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0) + edge.js: 6.5.1 + + '@adonisjs/static@2.0.1(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(supports-color@10.2.2)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + serve-static: 2.2.1(supports-color@10.2.2) + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + transitivePeerDependencies: + - supports-color + + '@adonisjs/tsconfig@2.0.0': {} + + '@adonisjs/vite@6.0.3(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/shield@9.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0))(edge.js@6.5.1))(edge.js@6.5.1)(vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@poppinss/utils': 7.1.1 + edge-error: 4.0.2 + picomatch: 4.0.7 + vite: 8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0) + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@adonisjs/shield': 9.0.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@adonisjs/session@8.1.0(770cc5139ed8289213226f432e14c982))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0))(edge.js@6.5.1) + edge.js: 6.5.1 + + '@antfu/install-pkg@2.1.0': + dependencies: + package-manager-detector: 1.9.0 + tinyexec: 1.3.1 + + '@arr/every@1.0.1': {} + + '@ast-grep/napi-darwin-arm64@0.45.3': + optional: true + + '@ast-grep/napi-darwin-x64@0.45.3': + optional: true + + '@ast-grep/napi-linux-arm64-gnu@0.45.3': + optional: true + + '@ast-grep/napi-linux-arm64-musl@0.45.3': + optional: true + + '@ast-grep/napi-linux-x64-gnu@0.45.3': + optional: true + + '@ast-grep/napi-linux-x64-musl@0.45.3': + optional: true + + '@ast-grep/napi-win32-arm64-msvc@0.45.3': + optional: true + + '@ast-grep/napi-win32-ia32-msvc@0.45.3': + optional: true + + '@ast-grep/napi-win32-x64-msvc@0.45.3': + optional: true + + '@ast-grep/napi@0.45.3': + optionalDependencies: + '@ast-grep/napi-darwin-arm64': 0.45.3 + '@ast-grep/napi-darwin-x64': 0.45.3 + '@ast-grep/napi-linux-arm64-gnu': 0.45.3 + '@ast-grep/napi-linux-arm64-musl': 0.45.3 + '@ast-grep/napi-linux-x64-gnu': 0.45.3 + '@ast-grep/napi-linux-x64-musl': 0.45.3 + '@ast-grep/napi-win32-arm64-msvc': 0.45.3 + '@ast-grep/napi-win32-ia32-msvc': 0.45.3 + '@ast-grep/napi-win32-x64-msvc': 0.45.3 + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/helper-string-parser@7.29.7': {} '@babel/helper-validator-identifier@7.29.7': {} @@ -3222,11 +5785,31 @@ snapshots: dependencies: '@babel/types': 7.29.7 + '@babel/parser@7.29.9': + dependencies: + '@babel/types': 7.29.8 + '@babel/types@7.29.7': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@borewit/text-codec@0.2.2': {} + + '@boringnode/encryption@1.0.1': + dependencies: + '@poppinss/utils': 7.1.1 + + '@boringnode/route-matcher@0.1.1': {} + + '@colors/colors@1.5.0': + optional: true + '@csstools/selector-resolve-nested@3.1.0(postcss-selector-parser@7.1.4)': dependencies: postcss-selector-parser: 7.1.4 @@ -3300,6 +5883,8 @@ snapshots: tslib: 2.8.1 optional: true + '@faker-js/faker@10.6.0': {} + '@fastify/accept-negotiator@1.1.0': {} '@fastify/ajv-compiler@3.6.0': @@ -3335,6 +5920,52 @@ snapshots: fastq: 1.20.1 glob: 10.5.0 + '@floating-ui/core@1.8.0': + dependencies: + '@floating-ui/utils': 0.2.12 + + '@floating-ui/dom@1.8.0': + dependencies: + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 + + '@floating-ui/utils@0.2.12': {} + + '@floating-ui/vue@2.0.1(vue@3.5.43(typescript@6.0.3))': + dependencies: + '@floating-ui/dom': 1.8.0 + '@floating-ui/utils': 0.2.12 + vue: 3.5.43(typescript@6.0.3) + + '@fontsource-variable/playpen-sans@5.3.0': {} + + '@fontsource-variable/recursive@5.3.0': {} + + '@inertiajs/core@3.9.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + es-toolkit: 1.52.0 + laravel-precognition: 2.1.0 + + '@inertiajs/vue3@3.9.1(vue@3.5.43(typescript@6.0.3))': + dependencies: + '@inertiajs/core': 3.9.1 + es-toolkit: 1.52.0 + laravel-precognition: 2.1.0 + vue: 3.5.43(typescript@6.0.3) + transitivePeerDependencies: + - axios + + '@internationalized/date@3.12.4': + dependencies: + '@swc/helpers': 0.5.23 + + '@internationalized/number@3.6.9': + dependencies: + '@swc/helpers': 0.5.23 + + '@ioredis/commands@2.0.0': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -3344,6 +5975,68 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@japa/assert@4.2.0(@japa/runner@5.3.0)': + dependencies: + '@japa/runner': 5.3.0 + '@poppinss/macroable': 1.1.2 + '@types/chai': 5.2.3 + assertion-error: 2.0.1 + chai: 6.3.0 + + '@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0)': + dependencies: + '@japa/assert': 4.2.0(@japa/runner@5.3.0) + '@japa/runner': 5.3.0 + '@poppinss/qs': 6.15.0 + '@sindresorhus/slugify': 3.0.1 + playwright: 1.64.0 + + '@japa/core@10.4.0': + dependencies: + '@poppinss/hooks': 7.3.1 + '@poppinss/macroable': 1.1.2 + '@poppinss/string': 1.7.2 + async-retry: 1.3.3 + emittery: 1.2.1 + string-width: 8.3.0 + + '@japa/errors-printer@4.1.4': + dependencies: + '@poppinss/colors': 4.1.6 + jest-diff: 30.5.2 + supports-color: 10.2.2 + youch: 4.1.1 + + '@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))(@japa/browser-client@2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0))(@japa/runner@5.3.0)(playwright@1.64.0)': + dependencies: + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@japa/runner': 5.3.0 + optionalDependencies: + '@japa/browser-client': 2.3.0(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)(playwright@1.64.0) + playwright: 1.64.0 + + '@japa/runner@5.3.0': + dependencies: + '@japa/core': 10.4.0 + '@japa/errors-printer': 4.1.4 + '@poppinss/colors': 4.1.6 + '@poppinss/hooks': 7.3.1 + '@poppinss/string': 1.7.2 + '@poppinss/utils': 7.1.1 + error-stack-parser-es: 1.0.5 + find-cache-directory: 6.0.0 + getopts: 2.3.0 + supports-color: 10.2.2 + timekeeper: 2.3.1 + + '@jest/diff-sequences@30.5.0': {} + + '@jest/get-type@30.5.0': {} + + '@jest/schemas@30.5.0': + dependencies: + '@sinclair/typebox': 0.34.52 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -3386,6 +6079,8 @@ snapshots: '@oxc-project/types@0.139.0': {} + '@oxc-project/types@0.153.0': {} + '@oxfmt/binding-android-arm-eabi@0.59.0': optional: true @@ -3500,11 +6195,95 @@ snapshots: '@oxlint/binding-win32-x64-msvc@1.74.0': optional: true + '@phc/format@1.0.0': {} + '@pinojs/redact@0.4.0': {} '@pkgjs/parseargs@0.11.0': optional: true + '@poppinss/cliui@6.8.1': + dependencies: + '@poppinss/colors': 4.1.6 + cli-boxes: 4.0.1 + cli-table3: 0.6.5 + cli-truncate: 5.2.0 + log-update: 7.2.0 + pretty-hrtime: 1.0.3 + string-width: 8.3.0 + supports-color: 10.2.2 + terminal-size: 4.0.1 + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.7.0': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@poppinss/hooks@7.3.1': {} + + '@poppinss/inspect@1.0.1': {} + + '@poppinss/macroable@1.1.2': {} + + '@poppinss/matchit@3.2.0': + dependencies: + '@arr/every': 1.0.1 + + '@poppinss/middleware@3.2.7': {} + + '@poppinss/multiparty@3.0.0': + dependencies: + http-errors: 2.0.1 + + '@poppinss/oauth-client@7.2.0': + dependencies: + '@poppinss/exception': 1.2.3 + ky: 1.14.3 + + '@poppinss/object-builder@1.1.0': {} + + '@poppinss/prompts@3.1.6': + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/exception': 1.2.3 + '@poppinss/object-builder': 1.1.0 + enquirer: 2.4.1 + + '@poppinss/qs@6.15.0': {} + + '@poppinss/string@1.7.2': + dependencies: + '@types/pluralize': 0.0.33 + case-anything: 3.1.7 + pluralize: 8.0.0 + slugify: 1.6.9 + + '@poppinss/ts-exec@1.5.0(@swc/helpers@0.5.23)': + dependencies: + '@swc/core': 1.16.18(@swc/helpers@0.5.23) + get-tsconfig: 4.14.3 + transitivePeerDependencies: + - '@swc/helpers' + + '@poppinss/types@1.2.1': {} + + '@poppinss/utils@7.1.1': + dependencies: + '@poppinss/exception': 1.2.3 + '@poppinss/object-builder': 1.1.0 + '@poppinss/string': 1.7.2 + '@poppinss/types': 1.2.1 + flattie: 1.1.1 + + '@poppinss/validator-lite@2.1.2': {} + '@redis/bloom@5.12.1(@redis/client@5.12.1)': dependencies: '@redis/client': 5.12.1 @@ -3525,42 +6304,81 @@ snapshots: dependencies: '@redis/client': 5.12.1 + '@rolldown/binding-android-arm-eabi@1.2.13': + optional: true + '@rolldown/binding-android-arm64@1.1.5': optional: true + '@rolldown/binding-android-arm64@1.2.13': + optional: true + '@rolldown/binding-darwin-arm64@1.1.5': optional: true + '@rolldown/binding-darwin-arm64@1.2.13': + optional: true + '@rolldown/binding-darwin-x64@1.1.5': optional: true + '@rolldown/binding-darwin-x64@1.2.13': + optional: true + '@rolldown/binding-freebsd-x64@1.1.5': optional: true + '@rolldown/binding-freebsd-x64@1.2.13': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.1.5': optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-arm64-musl@1.1.5': optional: true + '@rolldown/binding-linux-arm64-musl@1.2.13': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.1.5': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.1.5': optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-x64-gnu@1.1.5': optional: true + '@rolldown/binding-linux-x64-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-x64-musl@1.1.5': optional: true + '@rolldown/binding-linux-x64-musl@1.2.13': + optional: true + '@rolldown/binding-openharmony-arm64@1.1.5': optional: true + '@rolldown/binding-openharmony-arm64@1.2.13': + optional: true + '@rolldown/binding-wasm32-wasi@1.1.5': dependencies: '@emnapi/core': 1.11.1 @@ -3571,9 +6389,15 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.1.5': optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.13': + optional: true + '@rolldown/binding-win32-x64-msvc@1.1.5': optional: true + '@rolldown/binding-win32-x64-msvc@1.2.13': + optional: true + '@rolldown/pluginutils@1.0.1': {} '@sapphire/async-queue@1.5.5': {} @@ -3587,10 +6411,96 @@ snapshots: '@sapphire/snowflake@3.5.5': {} + '@sec-ant/readable-stream@0.4.1': {} + '@silvia-odwyer/photon-node@0.3.4': {} + '@sinclair/typebox@0.34.52': {} + + '@sindresorhus/is@7.2.0': {} + + '@sindresorhus/is@8.1.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@sindresorhus/slugify@3.0.1': + dependencies: + '@sindresorhus/transliterate': 2.3.1 + escape-string-regexp: 5.0.0 + + '@sindresorhus/transliterate@2.3.1': {} + + '@speed-highlight/core@1.2.24': {} + '@sqltools/formatter@1.2.5': {} + '@standard-schema/spec@1.1.0': {} + + '@swc/core-darwin-arm64@1.16.18': + optional: true + + '@swc/core-darwin-x64@1.16.18': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.16.18': + optional: true + + '@swc/core-linux-arm64-gnu@1.16.18': + optional: true + + '@swc/core-linux-arm64-musl@1.16.18': + optional: true + + '@swc/core-linux-ppc64-gnu@1.16.18': + optional: true + + '@swc/core-linux-s390x-gnu@1.16.18': + optional: true + + '@swc/core-linux-x64-gnu@1.16.18': + optional: true + + '@swc/core-linux-x64-musl@1.16.18': + optional: true + + '@swc/core-win32-arm64-msvc@1.16.18': + optional: true + + '@swc/core-win32-ia32-msvc@1.16.18': + optional: true + + '@swc/core-win32-x64-msvc@1.16.18': + optional: true + + '@swc/core@1.16.18(@swc/helpers@0.5.23)': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.28 + optionalDependencies: + '@swc/core-darwin-arm64': 1.16.18 + '@swc/core-darwin-x64': 1.16.18 + '@swc/core-linux-arm-gnueabihf': 1.16.18 + '@swc/core-linux-arm64-gnu': 1.16.18 + '@swc/core-linux-arm64-musl': 1.16.18 + '@swc/core-linux-ppc64-gnu': 1.16.18 + '@swc/core-linux-s390x-gnu': 1.16.18 + '@swc/core-linux-x64-gnu': 1.16.18 + '@swc/core-linux-x64-musl': 1.16.18 + '@swc/core-win32-arm64-msvc': 1.16.18 + '@swc/core-win32-ia32-msvc': 1.16.18 + '@swc/core-win32-x64-msvc': 1.16.18 + '@swc/helpers': 0.5.23 + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.23': + dependencies: + tslib: 2.8.1 + + '@swc/types@0.1.28': + dependencies: + '@swc/counter': 0.1.3 + '@tailwindcss/node@4.3.3': dependencies: '@jridgewell/remapping': 2.3.5 @@ -3659,6 +6569,36 @@ snapshots: tailwindcss: 4.3.3 vite: 8.1.5(@types/node@24.13.3)(jiti@2.7.0)(yaml@2.9.0) + '@tanstack/virtual-core@3.19.4': {} + + '@tanstack/vue-virtual@3.13.45(vue@3.5.43(typescript@6.0.3))': + dependencies: + '@tanstack/virtual-core': 3.19.4 + vue: 3.5.43(typescript@6.0.3) + + '@tokenizer/inflate@0.4.1(supports-color@10.2.2)': + dependencies: + debug: 4.4.3(supports-color@10.2.2) + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@ts-morph/common@0.29.0': + dependencies: + minimatch: 10.2.6 + path-browserify: 1.0.1 + tinyglobby: 0.2.17 + + '@tuyau/core@1.2.2(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@adonisjs/core@7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1))': + dependencies: + ky: 1.14.3 + object-to-formdata: 4.5.1 + optionalDependencies: + '@adonisjs/assembler': 8.5.2(typescript@6.0.3) + '@adonisjs/core': 7.6.0(@adonisjs/assembler@8.5.2(typescript@6.0.3))(@vinejs/vine@4.4.0)(edge.js@6.5.1)(pino-pretty@13.2.0)(supports-color@10.2.2)(youch@4.1.1) + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -3669,6 +6609,11 @@ snapshots: '@types/connect': 3.4.38 '@types/node': 24.13.3 + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + '@types/connect@3.4.38': dependencies: '@types/node': 24.13.3 @@ -3677,6 +6622,8 @@ snapshots: dependencies: '@types/node': 24.13.3 + '@types/deep-eql@4.0.2': {} + '@types/express-serve-static-core@4.19.9': dependencies: '@types/node': 24.13.3 @@ -3691,6 +6638,8 @@ snapshots: '@types/qs': 6.15.1 '@types/serve-static': 1.15.10 + '@types/he@1.2.3': {} + '@types/http-errors@2.0.5': {} '@types/js-yaml@3.12.10': {} @@ -3703,6 +6652,8 @@ snapshots: '@types/lodash@4.17.24': {} + '@types/luxon@3.7.6': {} + '@types/mime@1.3.5': {} '@types/multer@1.4.13': @@ -3713,6 +6664,12 @@ snapshots: dependencies: undici-types: 7.18.2 + '@types/node@26.6.5': + dependencies: + undici-types: 8.9.0 + + '@types/normalize-package-data@2.4.4': {} + '@types/oauth@0.9.6': dependencies: '@types/node': 24.13.3 @@ -3732,6 +6689,8 @@ snapshots: dependencies: '@types/express': 4.17.25 + '@types/pluralize@0.0.33': {} + '@types/qs@6.15.1': {} '@types/range-parser@1.2.7': {} @@ -3759,6 +6718,10 @@ snapshots: '@types/uuid@9.0.8': {} + '@types/validator@13.15.10': {} + + '@types/web-bluetooth@0.0.21': {} + '@types/ws@8.18.1': dependencies: '@types/node': 24.13.3 @@ -3823,11 +6786,32 @@ snapshots: '@typescript/typescript-win32-x64@7.0.2': optional: true + '@vinejs/compiler@4.1.3': {} + + '@vinejs/vine@4.4.0': + dependencies: + '@poppinss/macroable': 1.1.2 + '@poppinss/types': 1.2.1 + '@standard-schema/spec': 1.1.0 + '@types/validator': 13.15.10 + '@vinejs/compiler': 4.1.3 + camelcase: 9.0.0 + dayjs: 1.11.21 + dlv: 1.1.3 + normalize-url: 8.1.1 + validator: 13.15.35 + '@vitejs/plugin-vue@5.2.4(vite@8.1.5(@types/node@24.13.3)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))': dependencies: vite: 8.1.5(@types/node@24.13.3)(jiti@2.7.0)(yaml@2.9.0) vue: 3.5.40(typescript@6.0.3) + '@vitejs/plugin-vue@6.0.10(vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.43(typescript@6.0.3))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0) + vue: 3.5.43(typescript@6.0.3) + '@vladfrangu/async_event_emitter@2.4.7': {} '@volar/language-core@2.4.28': @@ -3854,11 +6838,24 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@3.5.43': + dependencies: + '@babel/parser': 7.29.9 + '@vue/shared': 3.5.43 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + '@vue/compiler-dom@3.5.40': dependencies: '@vue/compiler-core': 3.5.40 '@vue/shared': 3.5.40 + '@vue/compiler-dom@3.5.43': + dependencies: + '@vue/compiler-core': 3.5.43 + '@vue/shared': 3.5.43 + '@vue/compiler-sfc@3.5.40': dependencies: '@babel/parser': 7.29.7 @@ -3871,13 +6868,40 @@ snapshots: postcss: 8.5.19 source-map-js: 1.2.1 + '@vue/compiler-sfc@3.5.43': + dependencies: + '@babel/parser': 7.29.9 + '@vue/compiler-core': 3.5.43 + '@vue/compiler-dom': 3.5.43 + '@vue/compiler-ssr': 3.5.43 + '@vue/shared': 3.5.43 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.29 + source-map-js: 1.2.1 + '@vue/compiler-ssr@3.5.40': dependencies: '@vue/compiler-dom': 3.5.40 '@vue/shared': 3.5.40 + '@vue/compiler-ssr@3.5.43': + dependencies: + '@vue/compiler-dom': 3.5.43 + '@vue/shared': 3.5.43 + '@vue/devtools-api@6.6.4': {} + '@vue/language-core@3.3.13': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.40 + '@vue/shared': 3.5.40 + alien-signals: 3.2.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.5 + '@vue/language-core@3.3.7': dependencies: '@volar/language-core': 2.4.28 @@ -3892,11 +6916,20 @@ snapshots: dependencies: '@vue/shared': 3.5.40 + '@vue/reactivity@3.5.43': + dependencies: + '@vue/shared': 3.5.43 + '@vue/runtime-core@3.5.40': dependencies: '@vue/reactivity': 3.5.40 '@vue/shared': 3.5.40 + '@vue/runtime-core@3.5.43': + dependencies: + '@vue/reactivity': 3.5.43 + '@vue/shared': 3.5.43 + '@vue/runtime-dom@3.5.40': dependencies: '@vue/reactivity': 3.5.40 @@ -3904,19 +6937,47 @@ snapshots: '@vue/shared': 3.5.40 csstype: 3.2.3 + '@vue/runtime-dom@3.5.43': + dependencies: + '@vue/reactivity': 3.5.43 + '@vue/runtime-core': 3.5.43 + '@vue/shared': 3.5.43 + csstype: 3.2.3 + '@vue/server-renderer@3.5.40': dependencies: '@vue/compiler-ssr': 3.5.40 '@vue/runtime-dom': 3.5.40 '@vue/shared': 3.5.40 + '@vue/server-renderer@3.5.43': + dependencies: + '@vue/compiler-ssr': 3.5.43 + '@vue/runtime-dom': 3.5.43 + '@vue/shared': 3.5.43 + '@vue/shared@3.5.40': {} + '@vue/shared@3.5.43': {} + '@vue/tsconfig@0.7.0(typescript@6.0.3)(vue@3.5.40(typescript@6.0.3))': optionalDependencies: typescript: 6.0.3 vue: 3.5.40(typescript@6.0.3) + '@vueuse/core@14.4.0(vue@3.5.43(typescript@6.0.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.4.0 + '@vueuse/shared': 14.4.0(vue@3.5.43(typescript@6.0.3)) + vue: 3.5.43(typescript@6.0.3) + + '@vueuse/metadata@14.4.0': {} + + '@vueuse/shared@14.4.0(vue@3.5.43(typescript@6.0.3))': + dependencies: + vue: 3.5.43(typescript@6.0.3) + abstract-logging@2.0.1: {} accepts@1.3.8: @@ -3954,6 +7015,14 @@ snapshots: alien-signals@3.2.1: {} + angular-html-parser@10.13.0: {} + + ansi-colors@4.1.3: {} + + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -3962,6 +7031,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} ansis@4.3.1: {} @@ -3981,6 +7052,12 @@ snapshots: argparse@2.0.1: {} + argparse@3.0.3: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + array-find-index@1.0.2: {} array-flatten@1.1.1: {} @@ -3989,9 +7066,17 @@ snapshots: arrify@3.0.0: {} + assertion-error@2.0.1: {} + + astring@1.9.0: {} + + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + atomic-sleep@1.0.0: {} - ava@5.3.1: + ava@5.3.1(supports-color@10.2.2): dependencies: acorn: 8.17.0 acorn-walk: 8.3.5 @@ -4011,7 +7096,7 @@ snapshots: common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) emittery: 1.2.1 figures: 5.0.0 globby: 13.2.2 @@ -4052,19 +7137,25 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-js@1.5.1: {} base64url@3.0.1: {} + basic-auth@2.0.1: + dependencies: + safe-buffer: 5.1.2 + binary-extensions@2.3.0: {} blueimp-md5@2.19.0: {} - body-parser@1.20.6: + body-parser@1.20.6(supports-color@10.2.2): dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) depd: 2.0.0 destroy: 1.2.0 http-errors: 2.0.1 @@ -4081,6 +7172,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -4096,6 +7191,10 @@ snapshots: dependencies: node-gyp-build: 4.8.4 + bundle-name@4.1.1: + dependencies: + run-applescript: 7.1.0 + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -4123,12 +7222,25 @@ snapshots: callsites@4.2.0: {} + camelcase@9.0.0: {} + + case-anything@3.1.7: {} + cbor@8.1.0: dependencies: nofilter: 3.1.0 + chai@6.3.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chalk@5.6.2: {} + check-disk-space@3.4.0: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -4141,6 +7253,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + chunkd@2.0.1: {} ci-info@3.9.0: {} @@ -4153,19 +7269,40 @@ snapshots: clean-yaml-object@0.1.0: {} + cli-boxes@4.0.1: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@3.1.0: dependencies: slice-ansi: 5.0.0 string-width: 5.1.2 + cli-truncate@5.2.0: + dependencies: + slice-ansi: 8.0.0 + string-width: 8.3.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cluster-key-slot@1.1.1: {} + cluster-key-slot@1.1.2: {} + code-block-writer@13.0.3: {} + code-excerpt@4.0.0: dependencies: convert-to-spaces: 2.0.1 @@ -4178,6 +7315,12 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.19: {} + + colorette@2.0.20: {} + + commander@10.0.1: {} + common-path-prefix@3.0.0: {} concat-stream@2.0.0: @@ -4202,14 +7345,22 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.1.0: {} + content-type@1.0.5: {} + content-type@2.1.0: {} + convert-to-spaces@2.0.1: {} + cookie-es@3.1.1: {} + cookie-signature@1.0.7: {} cookie@0.7.2: {} + core-util-is@1.0.3: {} + cors@2.8.6: dependencies: object-assign: 4.1.1 @@ -4225,10 +7376,18 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + csrf@3.1.0: + dependencies: + rndm: 1.2.0 + tsscmp: 1.0.6 + uid-safe: 2.1.5 + cssesc@3.0.0: {} csstype@3.2.3: {} + csv-stringify@6.9.0: {} + currently-unhandled@0.4.1: dependencies: array-find-index: 1.0.2 @@ -4237,26 +7396,51 @@ snapshots: dependencies: time-zone: 1.0.0 + dateformat@4.6.3: {} + dayjs@1.11.21: {} - debug@2.6.9: + debug@2.6.9(supports-color@10.2.2): dependencies: ms: 2.0.0 + optionalDependencies: + supports-color: 10.2.2 - debug@4.4.3: + debug@4.3.4(supports-color@10.2.2): + dependencies: + ms: 2.1.2 + optionalDependencies: + supports-color: 10.2.2 + + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 dedent@1.7.2: {} deep-diff@1.0.2: {} + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.1: + dependencies: + bundle-name: 4.1.1 + default-browser-id: 5.0.1 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@3.0.0: {} + + defu@6.1.7: {} + denque@2.1.0: {} depd@2.0.0: {} @@ -4290,6 +7474,8 @@ snapshots: - bufferutil - utf-8-validate + dlv@1.1.3: {} + dotenv@16.6.1: {} dotenv@17.4.2: {} @@ -4302,6 +7488,32 @@ snapshots: eastasianwidth@0.2.0: {} + edge-error@4.0.2: {} + + edge-lexer@6.0.5: + dependencies: + edge-error: 4.0.2 + + edge-parser@9.1.1: + dependencies: + acorn: 8.17.0 + astring: 1.9.0 + edge-error: 4.0.2 + edge-lexer: 6.0.5 + js-stringify: 1.0.2 + + edge.js@6.5.1: + dependencies: + '@poppinss/inspect': 1.0.1 + '@poppinss/macroable': 1.1.2 + '@poppinss/utils': 7.1.1 + edge-error: 4.0.2 + edge-lexer: 6.0.5 + edge-parser: 9.1.1 + he: 1.2.0 + property-information: 7.2.0 + stringify-attributes: 4.0.0 + ee-first@1.1.1: {} emittery@1.2.1: {} @@ -4312,23 +7524,46 @@ snapshots: encodeurl@2.0.0: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + enhanced-resolve@5.24.2: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + entities@7.0.1: {} + entities@8.1.0: {} + + environment@1.1.0: {} + + error-stack-parser-es@1.0.5: {} + + error-stack-parser-es@2.0.1: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 + es-toolkit@1.52.0: {} + escalade@3.2.0: {} + escape-goat@4.0.0: {} + escape-html@1.0.3: {} escape-string-regexp@1.0.5: {} @@ -4337,8 +7572,7 @@ snapshots: escape-string-regexp@5.0.0: {} - esm@3.2.25: - optional: true + esm@3.2.25: {} esprima@4.0.1: {} @@ -4348,21 +7582,36 @@ snapshots: etag@1.8.1: {} - express@4.22.2: + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.1 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.2.0 + + express@4.22.2(supports-color@10.2.2): dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.6 + body-parser: 1.20.6(supports-color@10.2.2) content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.0.7 - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.2 + finalhandler: 1.3.2(supports-color@10.2.2) fresh: 0.5.2 http-errors: 2.0.1 merge-descriptors: 1.0.3 @@ -4374,8 +7623,8 @@ snapshots: qs: 6.15.3 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.2 - serve-static: 1.16.3 + send: 0.19.2(supports-color@10.2.2) + serve-static: 1.16.3(supports-color@10.2.2) setprototypeof: 1.2.0 statuses: 2.0.2 type-is: 1.6.18 @@ -4386,6 +7635,8 @@ snapshots: fast-content-type-parse@1.1.0: {} + fast-copy@4.1.2: {} + fast-decode-uri-component@1.0.1: {} fast-deep-equal@3.1.3: {} @@ -4414,10 +7665,14 @@ snapshots: dependencies: fast-decode-uri-component: 1.0.1 + fast-safe-stringify@2.1.1: {} + fast-uri@2.4.2: {} fast-uri@3.1.3: {} + fastest-levenshtein@1.0.16: {} + fastify-plugin@4.5.1: {} fastify@4.29.1: @@ -4452,13 +7707,26 @@ snapshots: escape-string-regexp: 5.0.0 is-unicode-supported: 1.3.0 + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + + file-type@22.1.1(supports-color@10.2.2): + dependencies: + '@tokenizer/inflate': 0.4.1(supports-color@10.2.2) + strtok3: 10.4.0 + token-types: 6.1.2 + uint8array-extras: 1.6.0 + transitivePeerDependencies: + - supports-color + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.2: + finalhandler@1.3.2(supports-color@10.2.2): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -4468,12 +7736,19 @@ snapshots: transitivePeerDependencies: - supports-color + find-cache-directory@6.0.0: + dependencies: + common-path-prefix: 3.0.0 + pkg-dir: 8.0.0 + find-my-way@8.2.2: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 safe-regex2: 3.1.0 + find-up-simple@1.0.1: {} + find-up@3.0.0: dependencies: locate-path: 3.0.0 @@ -4483,6 +7758,8 @@ snapshots: locate-path: 7.2.0 path-exists: 5.0.0 + flattie@1.1.1: {} + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -4498,6 +7775,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + fs-extra@8.1.0: dependencies: graceful-fs: 4.2.11 @@ -4515,6 +7794,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.7.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4528,15 +7809,34 @@ snapshots: hasown: 2.0.4 math-intrinsics: 1.1.0 + get-package-type@0.1.0: {} + + get-port@7.2.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 es-object-atoms: 1.1.2 + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + + get-tsconfig@4.14.3: + dependencies: + resolve-pkg-maps: 1.0.0 + + getopts@2.3.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -4558,6 +7858,8 @@ snapshots: graceful-fs@4.2.11: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -4572,10 +7874,28 @@ snapshots: dependencies: function-bind: 1.1.2 + he@1.2.0: {} + + help-me@5.0.0: {} + highlight.js@10.7.3: {} highlight.js@11.11.1: {} + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.5.3 + + hot-hook@1.0.0: + dependencies: + chokidar: 5.0.0 + fast-glob: 3.3.3 + parse-imports: 3.0.0 + picomatch: 4.0.5 + read-package-up: 12.0.0 + + html-entities@2.6.0: {} + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -4592,6 +7912,8 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + human-signals@8.0.1: {} + humanize-duration@3.34.0: {} iconv-lite@0.4.24: @@ -4604,16 +7926,39 @@ snapshots: ieee754@1.2.1: {} + igniculus@1.5.0: {} + ignore-by-default@2.1.0: {} ignore@5.3.2: {} + immediate@3.0.6: {} + + import-meta-resolve@4.2.0: {} + imurmurhash@0.1.4: {} indent-string@5.0.0: {} + index-to-position@1.2.0: {} + + inflation@2.1.0: {} + inherits@2.0.4: {} + interpret@2.2.0: {} + + ioredis@6.0.0(supports-color@10.2.2): + dependencies: + '@ioredis/commands': 2.0.0 + cluster-key-slot: 1.1.1 + debug: 4.4.3(supports-color@10.2.2) + denque: 2.1.0 + redis-errors: 1.2.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + ipaddr.js@1.9.1: {} irregular-plurals@3.5.0: {} @@ -4624,6 +7969,12 @@ snapshots: is-callable@1.2.7: {} + is-core-module@2.17.0: + dependencies: + hasown: 2.0.4 + + is-docker@3.0.0: {} + is-error@2.2.2: {} is-extglob@2.1.1: {} @@ -4632,26 +7983,48 @@ snapshots: is-fullwidth-code-point@4.0.0: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.7.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-number@7.0.0: {} is-observable@2.1.0: {} + is-plain-obj@4.1.0: {} + is-plain-object@5.0.0: {} is-promise@4.0.0: {} is-property@1.0.2: {} + is-stream@4.0.1: {} + is-typed-array@1.1.15: dependencies: which-typed-array: 1.1.22 is-unicode-supported@1.3.0: {} + is-unicode-supported@2.1.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} @@ -4662,10 +8035,23 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jest-diff@30.5.2: + dependencies: + '@jest/diff-sequences': 30.5.0 + '@jest/get-type': 30.5.0 + chalk: 4.1.2 + pretty-format: 30.5.1 + jiti@2.7.0: {} + joycon@3.1.1: {} + js-string-escape@1.0.1: {} + js-stringify@1.0.2: {} + + js-tokens@4.0.0: {} + js-yaml@3.15.0: dependencies: argparse: 1.0.10 @@ -4697,10 +8083,70 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonschema@1.5.0: {} + + jszip@3.10.2: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + junk@4.0.1: {} + + kleur@4.1.5: {} + + knex-dynamic-connection@5.1.1(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2): + dependencies: + debug: 4.4.3(supports-color@10.2.2) + knex: 3.3.0(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2) + transitivePeerDependencies: + - better-sqlite3 + - mariadb + - mysql + - mysql2 + - pg + - pg-native + - pg-query-stream + - sqlite3 + - supports-color + - tedious + + knex@3.3.0(mysql2@3.23.0(@types/node@26.6.5))(supports-color@10.2.2): + dependencies: + colorette: 2.0.19 + commander: 10.0.1 + debug: 4.3.4(supports-color@10.2.2) + escalade: 3.2.0 + esm: 3.2.25 + get-package-type: 0.1.0 + getopts: 2.3.0 + interpret: 2.2.0 + lodash: 4.18.1 + pg-connection-string: 2.6.2 + rechoir: 0.8.0 + resolve-from: 5.0.0 + tarn: 3.1.2 + tildify: 2.0.0 + optionalDependencies: + mysql2: 3.23.0(@types/node@26.6.5) + transitivePeerDependencies: + - supports-color + knub-command-manager@9.1.0: dependencies: escape-string-regexp: 2.0.0 + ky@1.14.3: {} + + laravel-precognition@2.1.0: + dependencies: + es-toolkit: 1.52.0 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + light-my-request@5.14.0: dependencies: cookie: 0.7.2 @@ -4710,36 +8156,69 @@ snapshots: lightningcss-android-arm64@1.32.0: optional: true + lightningcss-android-arm64@1.33.0: + optional: true + lightningcss-darwin-arm64@1.32.0: optional: true + lightningcss-darwin-arm64@1.33.0: + optional: true + lightningcss-darwin-x64@1.32.0: optional: true + lightningcss-darwin-x64@1.33.0: + optional: true + lightningcss-freebsd-x64@1.32.0: optional: true + lightningcss-freebsd-x64@1.33.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + lightningcss-linux-arm64-gnu@1.32.0: optional: true + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + lightningcss-linux-arm64-musl@1.32.0: optional: true + lightningcss-linux-arm64-musl@1.33.0: + optional: true + lightningcss-linux-x64-gnu@1.32.0: optional: true + lightningcss-linux-x64-gnu@1.33.0: + optional: true + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.32.0: + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: optional: true lightningcss-win32-x64-msvc@1.32.0: optional: true + lightningcss-win32-x64-msvc@1.33.0: + optional: true + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 @@ -4756,6 +8235,26 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + linkify-it@6.1.0: + dependencies: + uc.micro: 3.0.0 + load-json-file@7.0.1: {} locate-path@3.0.0: @@ -4773,12 +8272,28 @@ snapshots: lodash@4.18.1: {} + log-update@7.2.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 8.0.0 + strip-ansi: 7.2.0 + wrap-ansi: 10.0.2 + long@5.3.2: {} lru-cache@10.4.3: {} + lru-cache@11.5.3: {} + lru.min@1.1.4: {} + lucide-vue-next@1.0.0(vue@3.5.43(typescript@6.0.3)): + dependencies: + vue: 3.5.43(typescript@6.0.3) + + luxon@3.7.2: {} + magic-bytes.js@1.13.0: {} magic-string@0.30.21: @@ -4789,6 +8304,15 @@ snapshots: dependencies: p-defer: 1.0.0 + markdown-it@15.0.2: + dependencies: + argparse: 3.0.3 + entities: 8.1.0 + linkify-it: 6.1.0 + mdurl: 2.1.0 + punycode.js: 2.3.1 + uc.micro: 3.0.0 + marked@5.1.2: {} matcher@5.0.0: @@ -4801,8 +8325,12 @@ snapshots: dependencies: blueimp-md5: 2.19.0 + mdurl@2.1.0: {} + media-typer@0.3.0: {} + media-typer@1.1.1: {} + mem@9.0.2: dependencies: map-age-cleaner: 0.1.3 @@ -4821,16 +8349,28 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@3.0.0: {} mimic-fn@4.0.0: {} + mimic-function@5.0.1: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + minimatch@9.0.9: dependencies: brace-expansion: 2.1.2 @@ -4882,6 +8422,8 @@ snapshots: ms@2.0.0: {} + ms@2.1.2: {} + ms@2.1.3: {} muggle-string@0.4.1: {} @@ -4905,12 +8447,26 @@ snapshots: named-placeholders: 1.1.6 sql-escaper: 1.5.1 + mysql2@3.23.0(@types/node@26.6.5): + dependencies: + '@types/node': 26.6.5 + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.3 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + sql-escaper: 1.5.1 + named-placeholders@1.1.6: dependencies: lru.min: 1.1.4 nanoid@3.3.16: {} + nanoid@3.3.20: {} + negotiator@0.6.3: {} node-gyp-build@4.8.4: {} @@ -4919,22 +8475,56 @@ snapshots: nofilter@3.1.0: {} + normalize-package-data@8.0.0: + dependencies: + hosted-git-info: 9.0.3 + semver: 7.8.5 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} + normalize-url@8.1.1: {} + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + oauth@0.10.2: {} object-assign@4.1.1: {} object-inspect@1.13.4: {} + object-to-formdata@4.5.1: {} + observable-fns@0.6.1: {} + ohash@2.0.12: {} + on-exit-leak-free@2.1.2: {} on-finished@2.4.1: dependencies: ee-first: 1.1.1 + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@11.0.4: + dependencies: + default-browser: 5.5.1 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.2.1 + wsl-utils: 1.0.1 + oxfmt@0.59.0: dependencies: tinypool: 2.1.0 @@ -5013,12 +8603,29 @@ snapshots: package-json-from-dist@1.0.1: {} + package-manager-detector@1.9.0: {} + + pako@1.0.11: {} + parse-color@1.0.0: dependencies: color-convert: 0.5.3 + parse-imports@3.0.0: + dependencies: + es-module-lexer: 1.7.0 + slashes: 3.0.12 + + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.7 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-ms@3.0.0: {} + parse-ms@4.0.0: {} + parseurl@1.3.3: {} passport-custom@1.1.1: @@ -5049,6 +8656,10 @@ snapshots: path-key@3.1.1: {} + path-key@4.0.0: {} + + path-parse@1.0.7: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -5060,18 +8671,56 @@ snapshots: pause@0.0.1: {} + pg-connection-string@2.6.2: {} + picocolors@1.1.1: {} picomatch@2.3.2: {} picomatch@4.0.5: {} + picomatch@4.0.7: {} + pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.2.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 4.1.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pump: 3.0.4 + secure-json-parse: 4.1.1 + sonic-boom: 5.0.2 + strip-json-comments: 5.0.3 + pino-std-serializers@7.1.0: {} + pino@10.4.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 1.0.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.2.0 + pino@9.14.0: dependencies: '@pinojs/redact': 0.4.0 @@ -5091,14 +8740,26 @@ snapshots: find-up: 6.3.0 load-json-file: 7.0.1 + pkg-dir@8.0.0: + dependencies: + find-up-simple: 1.0.1 + pkg-up@3.1.0: dependencies: find-up: 3.0.0 + playwright-core@1.64.0: {} + + playwright@1.64.0: + dependencies: + playwright-core: 1.64.0 + plur@5.1.0: dependencies: irregular-plurals: 3.5.0 + pluralize@8.0.0: {} + possible-typed-array-names@1.1.0: {} postcss-nesting@13.0.2(postcss@8.5.19): @@ -5119,16 +8780,47 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.29: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + powershell-utils@0.2.1: {} + + prettier-edge@1.0.0(prettier@3.9.6): + dependencies: + angular-html-parser: 10.13.0 + edge-lexer: 6.0.5 + prettier: 3.9.6 + prettier@3.9.6: {} + pretty-format@30.5.1: + dependencies: + '@jest/react-is-18': react-is@18.3.1 + '@jest/react-is-19': react-is@19.3.0 + '@jest/schemas': 30.5.0 + ansi-styles: 5.2.0 + + pretty-hrtime@1.0.3: {} + pretty-ms@8.0.0: dependencies: parse-ms: 3.0.0 + pretty-ms@9.3.1: + dependencies: + parse-ms: 4.0.0 + + process-nextick-args@2.0.1: {} + process-warning@3.0.0: {} process-warning@5.0.0: {} + property-information@7.2.0: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -5136,6 +8828,13 @@ snapshots: proxy-disposable@1.0.0: {} + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode.js@2.3.1: {} + qs@6.15.3: dependencies: es-define-property: 1.0.1 @@ -5145,8 +8844,12 @@ snapshots: quick-format-unescaped@4.0.4: {} + random-bytes@1.0.0: {} + range-parser@1.2.1: {} + rate-limiter-flexible@9.1.1: {} + raw-body@2.5.3: dependencies: bytes: 3.1.2 @@ -5154,6 +8857,41 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + + react-is@18.3.1: {} + + react-is@19.3.0: {} + + read-package-up@12.0.0: + dependencies: + find-up-simple: 1.0.1 + read-pkg: 10.1.0 + type-fest: 5.10.0 + + read-pkg@10.1.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 8.0.0 + parse-json: 8.3.0 + type-fest: 5.10.0 + unicorn-magic: 0.4.1 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -5164,8 +8902,18 @@ snapshots: dependencies: picomatch: 2.3.2 + readdirp@5.1.1: {} + real-require@0.2.0: {} + real-require@1.0.0: {} + + rechoir@0.8.0: + dependencies: + resolve: 1.22.13 + + redis-errors@1.2.0: {} + redis@5.12.1: dependencies: '@redis/bloom': 5.12.1(@redis/client@5.12.1) @@ -5185,6 +8933,19 @@ snapshots: regexp-worker@1.1.1: {} + reka-ui@2.11.0(vue@3.5.43(typescript@6.0.3)): + dependencies: + '@floating-ui/vue': 2.0.1(vue@3.5.43(typescript@6.0.3)) + '@internationalized/date': 3.12.4 + '@internationalized/number': 3.6.9 + '@tanstack/vue-virtual': 3.13.45(vue@3.5.43(typescript@6.0.3)) + '@vueuse/core': 14.4.0(vue@3.5.43(typescript@6.0.3)) + '@vueuse/shared': 14.4.0(vue@3.5.43(typescript@6.0.3)) + aria-hidden: 1.2.6 + defu: 6.1.7 + ohash: 2.0.12 + vue: 3.5.43(typescript@6.0.3) + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -5197,12 +8958,30 @@ snapshots: resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.13: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.17.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + ret@0.4.3: {} + retry@0.13.1: {} + reusify@1.1.0: {} rfdc@1.4.1: {} + rndm@1.2.0: {} + rolldown@1.1.5: dependencies: '@oxc-project/types': 0.139.0 @@ -5224,10 +9003,35 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.1.5 '@rolldown/binding-win32-x64-msvc': 1.1.5 + rolldown@1.2.13: + dependencies: + '@oxc-project/types': 0.153.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.13 + '@rolldown/binding-android-arm64': 1.2.13 + '@rolldown/binding-darwin-arm64': 1.2.13 + '@rolldown/binding-darwin-x64': 1.2.13 + '@rolldown/binding-freebsd-x64': 1.2.13 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.13 + '@rolldown/binding-linux-arm64-gnu': 1.2.13 + '@rolldown/binding-linux-arm64-musl': 1.2.13 + '@rolldown/binding-linux-ppc64-gnu': 1.2.13 + '@rolldown/binding-linux-s390x-gnu': 1.2.13 + '@rolldown/binding-linux-x64-gnu': 1.2.13 + '@rolldown/binding-linux-x64-musl': 1.2.13 + '@rolldown/binding-openharmony-arm64': 1.2.13 + '@rolldown/binding-win32-arm64-msvc': 1.2.13 + '@rolldown/binding-win32-x64-msvc': 1.2.13 + + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-regex2@3.1.0: @@ -5244,13 +9048,15 @@ snapshots: secure-json-parse@2.7.0: {} + secure-json-parse@4.1.1: {} + seedrandom@3.0.5: {} semver@7.8.5: {} - send@0.19.2: + send@0.19.2(supports-color@10.2.2): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@10.2.2) depd: 2.0.0 destroy: 1.2.0 encodeurl: 2.0.0 @@ -5266,16 +9072,41 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.1(supports-color@10.2.2): + dependencies: + debug: 4.4.3(supports-color@10.2.2) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + serialize-error@7.0.1: dependencies: type-fest: 0.13.1 - serve-static@1.16.3: + serve-static@1.16.3(supports-color@10.2.2): + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1(supports-color@10.2.2): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.2 + send: 1.2.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -5290,6 +9121,8 @@ snapshots: gopd: 1.2.0 has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} sha.js@2.4.12: @@ -5336,17 +9169,34 @@ snapshots: slash@4.0.0: {} + slash@5.1.0: {} + + slashes@3.0.12: {} + slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.3 is-fullwidth-code-point: 4.0.0 + slice-ansi@8.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + slugify@1.6.9: {} + sonic-boom@4.2.1: dependencies: atomic-sleep: 1.0.0 + sonic-boom@5.0.2: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: {} + source-map-js@1.2.2: {} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 @@ -5354,6 +9204,22 @@ snapshots: source-map@0.6.1: {} + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.24 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.24 + + spdx-license-ids@3.0.24: {} + + split-lines@3.0.0: {} + split2@4.2.0: {} sprintf-js@1.0.3: {} @@ -5366,6 +9232,8 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + standard-as-callback@2.1.0: {} + statuses@2.0.1: {} statuses@2.0.2: {} @@ -5384,10 +9252,23 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.2.0 + string-width@8.3.0: + dependencies: + get-east-asian-width: 1.7.0 + strip-ansi: 7.2.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 + stringify-attributes@4.0.0: + dependencies: + escape-goat: 4.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -5400,6 +9281,14 @@ snapshots: strip-combining-marks@1.0.0: {} + strip-final-newline@4.0.0: {} + + strip-json-comments@5.0.3: {} + + strtok3@10.4.0: + dependencies: + '@tokenizer/token': 0.3.0 + supertap@3.0.1: dependencies: indent-string: 5.0.0 @@ -5407,20 +9296,40 @@ snapshots: serialize-error: 7.0.1 strip-ansi: 7.2.0 + supports-color@10.2.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tagged-tag@1.0.0: {} + tailwindcss@4.3.3: {} tapable@2.3.3: {} + tarn@3.1.2: {} + temp-dir@3.0.0: {} + tempura@0.4.1: {} + + terminal-size@4.0.1: {} + thread-stream@3.2.0: dependencies: real-require: 0.2.0 - threads@1.7.0: + thread-stream@4.2.0: + dependencies: + real-require: 1.0.0 + + threads@1.7.0(supports-color@10.2.2): dependencies: callsites: 3.1.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) is-observable: 2.1.0 observable-fns: 0.6.1 optionalDependencies: @@ -5428,13 +9337,19 @@ snapshots: transitivePeerDependencies: - supports-color + tildify@2.0.0: {} + time-zone@1.0.0: {} + timekeeper@2.3.1: {} + tiny-worker@2.3.0: dependencies: esm: 3.2.25 optional: true + tinyexec@1.3.1: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) @@ -5444,6 +9359,8 @@ snapshots: tlds@1.261.0: {} + tmp-cache@1.1.0: {} + tmp@0.2.5: {} to-buffer@1.2.2: @@ -5460,12 +9377,23 @@ snapshots: toidentifier@1.0.1: {} + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + ts-essentials@10.2.1(typescript@7.0.2): optionalDependencies: typescript: 7.0.2 ts-mixer@6.0.4: {} + ts-morph@28.0.0: + dependencies: + '@ts-morph/common': 0.29.0 + code-block-writer: 13.0.3 + ts-toolbelt@9.6.0: {} tsconfig-paths@3.15.0: @@ -5477,6 +9405,8 @@ snapshots: tslib@2.8.1: {} + tsscmp@1.0.6: {} + twemoji-parser@12.1.3: {} twemoji@12.1.6: @@ -5488,11 +9418,23 @@ snapshots: type-fest@0.13.1: {} + type-fest@4.41.0: {} + + type-fest@5.10.0: + dependencies: + tagged-tag: 1.0.0 + type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.1.0: + dependencies: + content-type: 2.1.0 + media-typer: 1.1.1 + mime-types: 3.0.2 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -5501,14 +9443,14 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.31(mysql2@3.23.0(@types/node@24.13.3))(redis@5.12.1): + typeorm@0.3.31(mysql2@3.23.0(@types/node@24.13.3))(redis@5.12.1)(supports-color@10.2.2): dependencies: '@sqltools/formatter': 1.2.5 ansis: 4.3.1 app-root-path: 3.1.0 buffer: 6.0.3 dayjs: 1.11.21 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) dedent: 1.7.2 dotenv: 16.6.1 glob: 10.5.0 @@ -5550,14 +9492,28 @@ snapshots: '@typescript/typescript-win32-arm64': 7.0.2 '@typescript/typescript-win32-x64': 7.0.2 + uc.micro@3.0.0: {} + + uid-safe@2.1.5: + dependencies: + random-bytes: 1.0.0 + uid2@0.0.4: {} + uint8array-extras@1.6.0: {} + undici-types@7.18.2: {} + undici-types@8.9.0: {} + undici@6.21.3: {} undici@6.27.0: {} + unicorn-magic@0.3.0: {} + + unicorn-magic@0.4.1: {} + universalify@0.1.2: {} unpipe@1.0.0: {} @@ -5574,6 +9530,13 @@ snapshots: uuid@9.0.1: {} + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + validator@13.15.35: {} + vary@1.1.2: {} vety@1.0.0-rc2(bufferutil@4.1.0)(typescript@7.0.2)(utf-8-validate@5.0.10): @@ -5600,6 +9563,19 @@ snapshots: jiti: 2.7.0 yaml: 2.9.0 + vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.29 + rolldown: 1.2.13 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.6.5 + fsevents: 2.3.3 + jiti: 2.7.0 + yaml: 2.9.0 + vscode-jsonrpc@9.0.1: {} vscode-languageserver-protocol@3.18.2: @@ -5620,6 +9596,14 @@ snapshots: '@vue/devtools-api': 6.6.4 vue: 3.5.40(typescript@6.0.3) + vue-sonner@2.0.9: {} + + vue-tsc@3.3.13(typescript@6.0.3): + dependencies: + '@volar/typescript': 2.4.28(typescript@6.0.3) + '@vue/language-core': 3.3.13 + typescript: 6.0.3 + vue-tsc@3.3.7(typescript@6.0.3): dependencies: '@volar/typescript': 2.4.28(typescript@6.0.3) @@ -5647,6 +9631,16 @@ snapshots: optionalDependencies: typescript: 6.0.3 + vue@3.5.43(typescript@6.0.3): + dependencies: + '@vue/compiler-dom': 3.5.43 + '@vue/compiler-sfc': 3.5.43 + '@vue/runtime-dom': 3.5.43 + '@vue/server-renderer': 3.5.43 + '@vue/shared': 3.5.43 + optionalDependencies: + typescript: 6.0.3 + vuex@4.1.0(vue@3.5.40(typescript@6.0.3)): dependencies: '@vue/devtools-api': 6.6.4 @@ -5668,6 +9662,11 @@ snapshots: dependencies: isexe: 2.0.0 + wrap-ansi@10.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 8.3.0 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -5680,6 +9679,8 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.2.0 + wrappy@1.0.2: {} + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 @@ -5690,12 +9691,19 @@ snapshots: bufferutil: 4.1.0 utf-8-validate: 5.0.10 + wsl-utils@1.0.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.2.1 + y18n@5.0.8: {} yaml@2.9.0: {} yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.3: dependencies: cliui: 8.0.1 @@ -5708,4 +9716,19 @@ snapshots: yocto-queue@1.2.2: {} + yoctocolors@2.2.0: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.1: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.7.0 + '@speed-highlight/core': 1.2.24 + cookie-es: 3.1.1 + youch-core: 0.3.3 + zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c277ca243..4f88b2811 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,13 +6,16 @@ packages: - 'shared' - 'dashboard' - 'config-checker' + - 'portal' allowBuilds: + '@swc/core': true bufferutil: true esbuild: true utf-8-validate: true minimumReleaseAge: 20160 # in minutes (2 weeks) +minimumReleaseAgeIgnoreMissingTime: false minimumReleaseAgeExclude: - 'vety' - 'knub-command-manager' diff --git a/portal/.adonisjs/client/data.d.ts b/portal/.adonisjs/client/data.d.ts new file mode 100644 index 000000000..fdad84d41 --- /dev/null +++ b/portal/.adonisjs/client/data.d.ts @@ -0,0 +1,21 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + +/// +import type { InferData, InferVariants } from '@adonisjs/core/types/transformers' +import type { InferSharedProps, InferFlashData } from '@adonisjs/inertia/types' +import type AuthPortalUserTransformer from '#backend/features/auth/transformers/PortalUserTransformer' +import type InertiaMiddleware from '#backend/middleware/inertiaMiddleware' + +export namespace Data { + export namespace Auth { + export type PortalUser = InferData + export namespace PortalUser { + export type Variants = InferVariants + } + } + export type SharedProps = InferSharedProps + export type FlashMessages = InferFlashData +} diff --git a/portal/.adonisjs/client/manifest.d.ts b/portal/.adonisjs/client/manifest.d.ts new file mode 100644 index 000000000..a0fe3b511 --- /dev/null +++ b/portal/.adonisjs/client/manifest.d.ts @@ -0,0 +1,12 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + +/// +/// +/// +/// +/// +/// +/// diff --git a/portal/.adonisjs/client/registry/index.ts b/portal/.adonisjs/client/registry/index.ts new file mode 100644 index 000000000..c8e2991e2 --- /dev/null +++ b/portal/.adonisjs/client/registry/index.ts @@ -0,0 +1,95 @@ +/* eslint-disable prettier/prettier */ +import type { AdonisEndpoint } from '@tuyau/core/types' +import type { Registry } from './schema.d.ts' +import type { ApiDefinition } from './tree.d.ts' + +const placeholder: any = {} + +const routes = { + 'splash.get_index': { + methods: ["GET","HEAD"], + pattern: '/', + tokens: [{"old":"/","type":0,"val":"/","end":""}], + types: placeholder as Registry['splash.get_index']['types'], + }, + 'privacy_policy.get_privacy_policy_page': { + methods: ["GET","HEAD"], + pattern: '/privacy-policy', + tokens: [{"old":"/privacy-policy","type":0,"val":"privacy-policy","end":""}], + types: placeholder as Registry['privacy_policy.get_privacy_policy_page']['types'], + }, + 'docs.get_index': { + methods: ["GET","HEAD"], + pattern: '/docs', + tokens: [{"old":"/docs","type":0,"val":"docs","end":""}], + types: placeholder as Registry['docs.get_index']['types'], + }, + 'auth.get_discord_login': { + methods: ["GET","HEAD"], + pattern: '/oauth/discord/login', + tokens: [{"old":"/oauth/discord/login","type":0,"val":"oauth","end":""},{"old":"/oauth/discord/login","type":0,"val":"discord","end":""},{"old":"/oauth/discord/login","type":0,"val":"login","end":""}], + types: placeholder as Registry['auth.get_discord_login']['types'], + }, + 'auth.get_discord_callback': { + methods: ["GET","HEAD"], + pattern: '/oauth/discord/callback', + tokens: [{"old":"/oauth/discord/callback","type":0,"val":"oauth","end":""},{"old":"/oauth/discord/callback","type":0,"val":"discord","end":""},{"old":"/oauth/discord/callback","type":0,"val":"callback","end":""}], + types: placeholder as Registry['auth.get_discord_callback']['types'], + }, + 'auth.post_logout': { + methods: ["POST"], + pattern: '/logout', + tokens: [{"old":"/logout","type":0,"val":"logout","end":""}], + types: placeholder as Registry['auth.post_logout']['types'], + }, + 'account.get_my_account_page': { + methods: ["GET","HEAD"], + pattern: '/account', + tokens: [{"old":"/account","type":0,"val":"account","end":""}], + types: placeholder as Registry['account.get_my_account_page']['types'], + }, + 'account.post_download_my_account_data': { + methods: ["POST"], + pattern: '/account/download-data', + tokens: [{"old":"/account/download-data","type":0,"val":"account","end":""},{"old":"/account/download-data","type":0,"val":"download-data","end":""}], + types: placeholder as Registry['account.post_download_my_account_data']['types'], + }, + 'account.post_delete_my_account_data': { + methods: ["POST"], + pattern: '/account/delete-data', + tokens: [{"old":"/account/delete-data","type":0,"val":"account","end":""},{"old":"/account/delete-data","type":0,"val":"delete-data","end":""}], + types: placeholder as Registry['account.post_delete_my_account_data']['types'], + }, + 'account.get_specific_account_page': { + methods: ["GET","HEAD"], + pattern: '/specific-account/:userId', + tokens: [{"old":"/specific-account/:userId","type":0,"val":"specific-account","end":""},{"old":"/specific-account/:userId","type":1,"val":"userId","end":""}], + types: placeholder as Registry['account.get_specific_account_page']['types'], + }, + 'account.post_download_specific_account_data': { + methods: ["POST"], + pattern: '/specific-account/:userId/download-data', + tokens: [{"old":"/specific-account/:userId/download-data","type":0,"val":"specific-account","end":""},{"old":"/specific-account/:userId/download-data","type":1,"val":"userId","end":""},{"old":"/specific-account/:userId/download-data","type":0,"val":"download-data","end":""}], + types: placeholder as Registry['account.post_download_specific_account_data']['types'], + }, + 'account.post_delete_specific_account_data': { + methods: ["POST"], + pattern: '/specific-account/:userId/delete-data', + tokens: [{"old":"/specific-account/:userId/delete-data","type":0,"val":"specific-account","end":""},{"old":"/specific-account/:userId/delete-data","type":1,"val":"userId","end":""},{"old":"/specific-account/:userId/delete-data","type":0,"val":"delete-data","end":""}], + types: placeholder as Registry['account.post_delete_specific_account_data']['types'], + }, +} as const satisfies Record + +export { routes } + +export const registry = { + routes, + $tree: {} as ApiDefinition, +} + +declare module '@tuyau/core/types' { + export interface UserRegistry { + routes: typeof routes + $tree: ApiDefinition + } +} diff --git a/portal/.adonisjs/client/registry/schema.d.ts b/portal/.adonisjs/client/registry/schema.d.ts new file mode 100644 index 000000000..8dacc5b4c --- /dev/null +++ b/portal/.adonisjs/client/registry/schema.d.ts @@ -0,0 +1,154 @@ +/* eslint-disable prettier/prettier */ +/// + +import type { ExtractBody, ExtractErrorResponse, ExtractQuery, ExtractQueryForGet, ExtractResponse } from '@tuyau/core/types' +import type { InferInput, SimpleError } from '@vinejs/vine/types' + +export type ParamValue = string | number | bigint | boolean + +export interface Registry { + 'splash.get_index': { + methods: ["GET","HEAD"] + pattern: '/' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'privacy_policy.get_privacy_policy_page': { + methods: ["GET","HEAD"] + pattern: '/privacy-policy' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'docs.get_index': { + methods: ["GET","HEAD"] + pattern: '/docs' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'auth.get_discord_login': { + methods: ["GET","HEAD"] + pattern: '/oauth/discord/login' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'auth.get_discord_callback': { + methods: ["GET","HEAD"] + pattern: '/oauth/discord/callback' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'auth.post_logout': { + methods: ["POST"] + pattern: '/logout' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'account.get_my_account_page': { + methods: ["GET","HEAD"] + pattern: '/account' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'account.post_download_my_account_data': { + methods: ["POST"] + pattern: '/account/download-data' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'account.post_delete_my_account_data': { + methods: ["POST"] + pattern: '/account/delete-data' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'account.get_specific_account_page': { + methods: ["GET","HEAD"] + pattern: '/specific-account/:userId' + types: { + body: {} + paramsTuple: [ParamValue] + params: { userId: ParamValue } + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'account.post_download_specific_account_data': { + methods: ["POST"] + pattern: '/specific-account/:userId/download-data' + types: { + body: {} + paramsTuple: [ParamValue] + params: { userId: ParamValue } + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } + 'account.post_delete_specific_account_data': { + methods: ["POST"] + pattern: '/specific-account/:userId/delete-data' + types: { + body: {} + paramsTuple: [ParamValue] + params: { userId: ParamValue } + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> + } + } +} diff --git a/portal/.adonisjs/client/registry/tree.d.ts b/portal/.adonisjs/client/registry/tree.d.ts new file mode 100644 index 000000000..ea2573f82 --- /dev/null +++ b/portal/.adonisjs/client/registry/tree.d.ts @@ -0,0 +1,27 @@ +/* eslint-disable prettier/prettier */ +import type { routes } from './index.ts' + +export interface ApiDefinition { + splash: { + getIndex: typeof routes['splash.get_index'] + } + privacyPolicy: { + getPrivacyPolicyPage: typeof routes['privacy_policy.get_privacy_policy_page'] + } + docs: { + getIndex: typeof routes['docs.get_index'] + } + auth: { + getDiscordLogin: typeof routes['auth.get_discord_login'] + getDiscordCallback: typeof routes['auth.get_discord_callback'] + postLogout: typeof routes['auth.post_logout'] + } + account: { + getMyAccountPage: typeof routes['account.get_my_account_page'] + postDownloadMyAccountData: typeof routes['account.post_download_my_account_data'] + postDeleteMyAccountData: typeof routes['account.post_delete_my_account_data'] + getSpecificAccountPage: typeof routes['account.get_specific_account_page'] + postDownloadSpecificAccountData: typeof routes['account.post_download_specific_account_data'] + postDeleteSpecificAccountData: typeof routes['account.post_delete_specific_account_data'] + } +} diff --git a/portal/.adonisjs/server/controllers.ts b/portal/.adonisjs/server/controllers.ts new file mode 100644 index 000000000..47e0b80cc --- /dev/null +++ b/portal/.adonisjs/server/controllers.ts @@ -0,0 +1,22 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + +export const controllers = { + account: { + Account: () => import('#backend/features/account/controllers/AccountController'), + }, + auth: { + Auth: () => import('#backend/features/auth/controllers/AuthController'), + }, + docs: { + Docs: () => import('#backend/features/docs/controllers/DocsController'), + }, + splash: { + Splash: () => import('#backend/features/splash/controllers/SplashController'), + }, + legal: { + PrivacyPolicy: () => import('#backend/features/legal/controllers/PrivacyPolicyController'), + }, +} diff --git a/portal/.adonisjs/server/events.ts b/portal/.adonisjs/server/events.ts new file mode 100644 index 000000000..a74e59b65 --- /dev/null +++ b/portal/.adonisjs/server/events.ts @@ -0,0 +1,6 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + +export const events = {} diff --git a/portal/.adonisjs/server/listeners.ts b/portal/.adonisjs/server/listeners.ts new file mode 100644 index 000000000..05f35f86d --- /dev/null +++ b/portal/.adonisjs/server/listeners.ts @@ -0,0 +1,6 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + +export const listeners = {} diff --git a/portal/.adonisjs/server/pages.d.ts b/portal/.adonisjs/server/pages.d.ts new file mode 100644 index 000000000..e326a4535 --- /dev/null +++ b/portal/.adonisjs/server/pages.d.ts @@ -0,0 +1,39 @@ +import '@adonisjs/inertia/types' + + + import type { + VNodeProps, + AllowedComponentProps, + ComponentInstance + } from 'vue' + + type ExtractProps = Omit< + ComponentInstance['$props'], + keyof VNodeProps | keyof AllowedComponentProps + > + + +declare module '@adonisjs/inertia/types' { + + export interface InertiaPages { + + 'features/account/pages/MyAccountPage': ExtractProps<(typeof import('../../inertia/features/account/pages/MyAccountPage.vue'))['default']> + + 'features/account/pages/SpecificAccountPage': ExtractProps<(typeof import('../../inertia/features/account/pages/SpecificAccountPage.vue'))['default']> + + 'features/auth/pages/LoginRequiredPage': ExtractProps<(typeof import('../../inertia/features/auth/pages/LoginRequiredPage.vue'))['default']> + + 'features/docs/pages/DocsIndex': ExtractProps<(typeof import('../../inertia/features/docs/pages/DocsIndex.vue'))['default']> + + 'features/errors/pages/NotFound': ExtractProps<(typeof import('../../inertia/features/errors/pages/NotFound.vue'))['default']> + + 'features/errors/pages/ServerError': ExtractProps<(typeof import('../../inertia/features/errors/pages/ServerError.vue'))['default']> + + 'features/splash/pages/SplashIndex': ExtractProps<(typeof import('../../inertia/features/splash/pages/SplashIndex.vue'))['default']> + + 'features/legal/pages/PrivacyPolicyPage': ExtractProps<(typeof import('../../inertia/features/legal/pages/PrivacyPolicyPage.vue'))['default']> + + } + +} + diff --git a/portal/.adonisjs/server/routes.d.ts b/portal/.adonisjs/server/routes.d.ts new file mode 100644 index 000000000..e5fe951ca --- /dev/null +++ b/portal/.adonisjs/server/routes.d.ts @@ -0,0 +1,48 @@ +import '@adonisjs/core/types/http' + +type ParamValue = string | number | bigint | boolean + +export type ScannedRoutes = { + ALL: { + 'splash.get_index': { paramsTuple?: []; params?: {} } + 'privacy_policy.get_privacy_policy_page': { paramsTuple?: []; params?: {} } + 'docs.get_index': { paramsTuple?: []; params?: {} } + 'auth.get_discord_login': { paramsTuple?: []; params?: {} } + 'auth.get_discord_callback': { paramsTuple?: []; params?: {} } + 'auth.post_logout': { paramsTuple?: []; params?: {} } + 'account.get_my_account_page': { paramsTuple?: []; params?: {} } + 'account.post_download_my_account_data': { paramsTuple?: []; params?: {} } + 'account.post_delete_my_account_data': { paramsTuple?: []; params?: {} } + 'account.get_specific_account_page': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + 'account.post_download_specific_account_data': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + 'account.post_delete_specific_account_data': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + } + GET: { + 'splash.get_index': { paramsTuple?: []; params?: {} } + 'privacy_policy.get_privacy_policy_page': { paramsTuple?: []; params?: {} } + 'docs.get_index': { paramsTuple?: []; params?: {} } + 'auth.get_discord_login': { paramsTuple?: []; params?: {} } + 'auth.get_discord_callback': { paramsTuple?: []; params?: {} } + 'account.get_my_account_page': { paramsTuple?: []; params?: {} } + 'account.get_specific_account_page': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + } + HEAD: { + 'splash.get_index': { paramsTuple?: []; params?: {} } + 'privacy_policy.get_privacy_policy_page': { paramsTuple?: []; params?: {} } + 'docs.get_index': { paramsTuple?: []; params?: {} } + 'auth.get_discord_login': { paramsTuple?: []; params?: {} } + 'auth.get_discord_callback': { paramsTuple?: []; params?: {} } + 'account.get_my_account_page': { paramsTuple?: []; params?: {} } + 'account.get_specific_account_page': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + } + POST: { + 'auth.post_logout': { paramsTuple?: []; params?: {} } + 'account.post_download_my_account_data': { paramsTuple?: []; params?: {} } + 'account.post_delete_my_account_data': { paramsTuple?: []; params?: {} } + 'account.post_download_specific_account_data': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + 'account.post_delete_specific_account_data': { paramsTuple: [ParamValue]; params: {'userId': ParamValue} } + } +} +declare module '@adonisjs/core/types/http' { + export interface RoutesList extends ScannedRoutes {} +} \ No newline at end of file diff --git a/portal/.env.example b/portal/.env.example new file mode 100644 index 000000000..84ca0230c --- /dev/null +++ b/portal/.env.example @@ -0,0 +1,5 @@ +HOST=0.0.0.0 +PORT=3003 +SESSION_DRIVER=redis +LOG_LEVEL=debug +LIMITER_STORE=redis diff --git a/portal/.env.test b/portal/.env.test new file mode 100644 index 000000000..28d2da02d --- /dev/null +++ b/portal/.env.test @@ -0,0 +1 @@ +SESSION_DRIVER=memory diff --git a/portal/.gitignore b/portal/.gitignore new file mode 100644 index 000000000..5870e82d6 --- /dev/null +++ b/portal/.gitignore @@ -0,0 +1,7 @@ +# Dependencies and AdonisJS build +build +tmp/* +!tmp/.gitkeep + +# Frontend assets compiled code +public/assets diff --git a/portal/ace.js b/portal/ace.js new file mode 100644 index 000000000..d7647d08f --- /dev/null +++ b/portal/ace.js @@ -0,0 +1,27 @@ +/* +|-------------------------------------------------------------------------- +| JavaScript entrypoint for running ace commands +|-------------------------------------------------------------------------- +| +| DO NOT MODIFY THIS FILE AS IT WILL BE OVERRIDDEN DURING THE BUILD +| PROCESS. +| +| See docs.adonisjs.com/guides/typescript-build-process#creating-production-build +| +| Since, we cannot run TypeScript source code using "node" binary, we need +| a JavaScript entrypoint to run ace commands. +| +| This file registers the "ts-node/esm" hook with the Node.js module system +| and then imports the "bin/console.ts" file. +| +*/ + +/** + * Register hook to process TypeScript files using @poppinss/ts-exec + */ +import "@poppinss/ts-exec"; + +/** + * Import ace console entrypoint + */ +await import("./bin/console.js"); diff --git a/portal/adonisrc.ts b/portal/adonisrc.ts new file mode 100644 index 000000000..93ec31848 --- /dev/null +++ b/portal/adonisrc.ts @@ -0,0 +1,168 @@ +import { indexEntities } from "@adonisjs/core/generators"; +import { defineConfig } from "@adonisjs/core/app"; +import { generateRegistry } from "@tuyau/core/hooks"; + +export default defineConfig({ + /* + |-------------------------------------------------------------------------- + | Experimental flags + |-------------------------------------------------------------------------- + | + | The following features will be enabled by default in the next major release + | of AdonisJS. You can opt into them today to avoid any breaking changes + | during upgrade. + | + */ + experimental: {}, + + /* + |-------------------------------------------------------------------------- + | Commands + |-------------------------------------------------------------------------- + | + | List of ace commands to register from packages. The application commands + | will be scanned automatically from the "./commands" directory. + | + */ + commands: [ + () => import("@adonisjs/core/commands"), + () => import("@adonisjs/lucid/commands"), + () => import("@adonisjs/session/commands"), + () => import("@adonisjs/inertia/commands"), + ], + + /* + |-------------------------------------------------------------------------- + | Service providers + |-------------------------------------------------------------------------- + | + | List of service providers to import and register when booting the + | application + | + */ + providers: [ + () => import("@adonisjs/core/providers/app_provider"), + () => import("@adonisjs/core/providers/hash_provider"), + { + file: () => import("@adonisjs/core/providers/repl_provider"), + environment: ["repl", "test"], + }, + () => import("@adonisjs/core/providers/vinejs_provider"), + () => import("@adonisjs/core/providers/edge_provider"), + () => import("@adonisjs/session/session_provider"), + () => import("@adonisjs/vite/vite_provider"), + () => import("@adonisjs/shield/shield_provider"), + () => import("@adonisjs/static/static_provider"), + () => import("@adonisjs/lucid/database_provider"), + () => import("@adonisjs/cors/cors_provider"), + () => import("@adonisjs/inertia/inertia_provider"), + () => import("@adonisjs/auth/auth_provider"), + () => import("@adonisjs/redis/redis_provider"), + () => import("#providers/apiProvider"), + () => import("@adonisjs/ally/ally_provider"), + () => import("@adonisjs/limiter/limiter_provider"), + ], + + /* + |-------------------------------------------------------------------------- + | Preloads + |-------------------------------------------------------------------------- + | + | List of modules to import before starting the application. + | + */ + preloads: [() => import("#start/routes"), () => import("#start/kernel"), () => import("#start/validator")], + + /* + |-------------------------------------------------------------------------- + | Tests + |-------------------------------------------------------------------------- + | + | List of test suites to organize tests by their type. Feel free to remove + | and add additional suites. + | + */ + tests: { + suites: [ + { + files: ["tests/unit/**/*.spec.{ts,js}"], + name: "unit", + timeout: 2000, + }, + { + files: ["tests/functional/**/*.spec.{ts,js}"], + name: "functional", + timeout: 30000, + }, + { + files: ["tests/browser/**/*.spec.{ts,js}"], + name: "browser", + timeout: 300000, + }, + ], + forceExit: false, + }, + + /* + |-------------------------------------------------------------------------- + | Metafiles + |-------------------------------------------------------------------------- + | + | A collection of files you want to copy to the build folder when creating + | the production build. + | + */ + metaFiles: [ + { + pattern: "resources/views/**/*.edge", + reloadServer: false, + }, + { + pattern: "public/**", + reloadServer: false, + }, + ], + + hooks: { + init: [ + indexEntities({ + controllers: { + source: "app", + importAlias: "#backend", + glob: ["**/controllers/*.ts"], + skipSegments: ["features", "controllers"], + }, + + events: { + source: "app", + importAlias: "#backend", + glob: ["**/events/*.ts"], + skipSegments: ["features", "events"], + }, + + listeners: { + source: "app", + importAlias: "#backend", + glob: ["**/listeners/*.ts"], + skipSegments: ["features", "listeners"], + }, + + transformers: { + enabled: true, + withSharedProps: true, + source: "app", + importAlias: "#backend", + glob: ["**/transformers/*.ts"], + skipSegments: ["features", "transformers"], + inertiaMiddlewareImportPath: "#backend/middleware/inertiaMiddleware", + }, + }), + + () => import("./hooks/indexInertiaPages.js"), + + generateRegistry(), + ], + buildStarting: [() => import("@adonisjs/vite/build_hook")], + devServerStarting: [() => import("./hooks/devHmrPort.js")], + }, +}); diff --git a/portal/app/crypt.ts b/portal/app/crypt.ts new file mode 100644 index 000000000..a2db45f88 --- /dev/null +++ b/portal/app/crypt.ts @@ -0,0 +1,39 @@ +import { rootEnv } from "#start/env"; +import crypto from "crypto"; + +const ALGORITHM = "aes-256-gcm"; + +const KEY = rootEnv.get("KEY"); + +export function encrypt(str: string): string { + // Based on https://gist.github.com/rjz/15baffeab434b8125ca4d783f4116d81 + + const iv = crypto.randomBytes(16); + const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv); + + let encrypted = cipher.update(str, "utf8", "base64"); + encrypted += cipher.final("base64"); + return `${iv.toString("base64")}.${cipher.getAuthTag().toString("base64")}.${encrypted}`; +} + +export function decrypt(encrypted: string): string { + // Based on https://gist.github.com/rjz/15baffeab434b8125ca4d783f4116d81 + + const [iv, authTag, encryptedStr] = encrypted.split("."); + const decipher = crypto.createDecipheriv(ALGORITHM, KEY, Buffer.from(iv, "base64")); + decipher.setAuthTag(Buffer.from(authTag, "base64")); + + let decrypted = decipher.update(encryptedStr, "base64", "utf8"); + decrypted += decipher.final("utf8"); + return decrypted; +} + +export function encryptJson(obj: any): string { + const serialized = JSON.stringify(obj); + return encrypt(serialized); +} + +export function decryptJson(encrypted: string): unknown { + const decrypted = decrypt(encrypted); + return JSON.parse(decrypted); +} diff --git a/portal/app/exceptions/handler.ts b/portal/app/exceptions/handler.ts new file mode 100644 index 000000000..c93096ae0 --- /dev/null +++ b/portal/app/exceptions/handler.ts @@ -0,0 +1,45 @@ +import app from "@adonisjs/core/services/app"; +import { type HttpContext, ExceptionHandler } from "@adonisjs/core/http"; +import type { StatusPageRange, StatusPageRenderer } from "@adonisjs/core/types/http"; + +export default class HttpExceptionHandler extends ExceptionHandler { + /** + * In debug mode, the exception handler will display verbose errors + * with pretty printed stack traces. + */ + protected debug = !app.inProduction; + + /** + * Status pages are used to display a custom HTML pages for certain error + * codes. You might want to enable them in production only, but feel + * free to enable them in development as well. + */ + protected renderStatusPages = app.inProduction; + + /** + * Status pages is a collection of error code range and a callback + * to return the HTML contents to send as a response. + */ + protected statusPages: Record = { + "404": (_, { inertia }) => inertia.render("features/errors/pages/NotFound", {}), + "500..599": (_, { inertia }) => inertia.render("features/errors/pages/ServerError", {}), + }; + + /** + * The method is used for handling errors and returning + * response to the client + */ + async handle(error: unknown, ctx: HttpContext) { + return super.handle(error, ctx); + } + + /** + * The method is used to report error to the logging service or + * the a third party error monitoring service. + * + * @note You should not attempt to send a response from this method. + */ + async report(error: unknown, ctx: HttpContext) { + return super.report(error, ctx); + } +} diff --git a/portal/app/features/account/accountDataDefinitions.ts b/portal/app/features/account/accountDataDefinitions.ts new file mode 100644 index 000000000..6a9bef919 --- /dev/null +++ b/portal/app/features/account/accountDataDefinitions.ts @@ -0,0 +1,571 @@ +import { decryptJson } from "#backend/crypt"; +import ApiAuditLog from "#backend/features/api/models/ApiAuditLog"; +import ApiLogin from "#backend/features/api/models/ApiLogin"; +import ApiPermission from "#backend/features/api/models/ApiPermission"; +import ApiUserInfo from "#backend/features/api/models/ApiUserInfo"; +import PortalUser from "#backend/features/auth/models/PortalUser"; +import Config from "#backend/features/config/models/Config"; +import AllowedGuild from "#backend/features/guilds/models/AllowedGuild"; +import SavedMessage from "#backend/features/messages/models/SavedMessage"; +import Reminder from "#backend/features/reminders/models/Reminder"; +import Supporter from "#backend/features/supporters/models/Supporter"; +import MemberTimezone from "#backend/features/timeAndDate/models/MemberTimezone"; +import { TransactionClientContract } from "@adonisjs/lucid/types/database"; +import db from "@adonisjs/lucid/services/db"; + +export interface DataContainer { + columns: Columns[]; + rows: Array>; +} + +interface UserSelfServeTools { + getData?: (userId: string) => Promise>; + deleteData?: (userId: string, trx: TransactionClientContract) => Promise; + getGuildIdsProcessingData?: (userId: string) => Promise; +} + +interface ServerSelfServeTools { + getUserData?: (guildId: string, userId: string) => Promise; + deleteUserData?: (guildId: string, userId: string, trx: TransactionClientContract) => Promise; +} + +export interface AccountDataCategory { + name: string; + prettyName: string; + controller: "zeppelin" | "server"; + userSelfServeTools: UserSelfServeTools; + serverSelfServeTools: ServerSelfServeTools; +} + +export const accountDataCategories: AccountDataCategory[] = []; + +function addAccountDataCategory(category: AccountDataCategory): void { + accountDataCategories.push(category); +} + +addAccountDataCategory({ + name: "dashboard_user_data", + prettyName: "Dashboard user data", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const apiUserInfos = await ApiUserInfo.query().where("id", "=", userId).select(); + + return { + columns: ["userId", "username", "discriminator", "avatar"], + rows: apiUserInfos.map((info) => { + const data = JSON.parse(info.data); + return { + userId: info.id, + username: data.username ?? "", + discriminator: data.discriminator ?? "", + avatar: data.avatar ?? "", + }; + }), + }; + }, + + deleteData: async (userId, trx) => { + await ApiUserInfo.query({ client: trx }).where("id", "=", userId).delete(); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "dashboard_login_data", + prettyName: "Dashboard login data", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const apiLogins = await ApiLogin.query().where("user_id", "=", userId).select(); + + return { + columns: ["userId", "loggedInAt", "expiresAt"], + rows: apiLogins.map((login) => { + return { + userId: login.userId, + loggedInAt: login.loggedInAt.toISO() ?? "", + expiresAt: login.expiresAt.toISO() ?? "", + }; + }), + }; + }, + + deleteData: async (userId, trx) => { + await ApiLogin.query({ client: trx }).where("user_id", "=", userId).delete(); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "new_dashboard_user_and_login_data", + prettyName: "New dashboard user and login data", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const portalUsers = await PortalUser.query().where("discord_user_id", "=", userId).select(); + + return { + columns: ["userId", "username", "avatarUrl", "createdAt", "lastLoginAt"], + rows: portalUsers.map((portalUser) => ({ + userId: portalUser.discordUserId, + username: portalUser.discordUsername, + avatarUrl: portalUser.discordAvatarUrl ?? "", + createdAt: portalUser.createdAt.toISO() ?? "", + lastLoginAt: portalUser.lastLoginAt.toISO() ?? "", + })), + }; + }, + + deleteData: async (userId, trx) => { + await PortalUser.query({ client: trx }).where("discord_user_id", "=", userId).delete(); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "dashboard_permissions", + prettyName: "Dashboard permissions", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const permissions = await ApiPermission.query().where("target_id", "=", userId).select(); + + return { + columns: ["serverId", "userId", "type", "permissions", "expiresAt"], + rows: permissions.map((p) => ({ + serverId: p.guildId, + userId: p.targetId, + type: p.type, + permissions: p.permissions, + expiresAt: p.expiresAt?.toISO() ?? "", + })), + }; + }, + + deleteData: async (userId, trx) => { + await ApiPermission.query({ client: trx }).where("target_id", "=", userId).delete(); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "dashboard_server_configuration_metadata", + prettyName: "Dashboard server configuration metadata", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const configMetadata = await Config.query() + .where("edited_by", "=", userId) + .select("configs.key", "configs.edited_by", "configs.edited_at"); + + return { + columns: ["key", "editedBy", "editedAt"], + rows: configMetadata.map((m) => ({ + key: m.key, + editedBy: m.editedBy, + editedAt: m.editedAt.toISO() ?? "", + })), + }; + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "dashboard_audit_logs", + prettyName: "Dashboard audit logs", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const auditLogEntries = await ApiAuditLog.query().where("author_id", "=", userId).select(); + + return { + columns: ["serverId", "authorId", "eventType", "timestamp"], + rows: auditLogEntries.map((item) => ({ + serverId: item.guildId, + authorId: item.authorId, + eventType: item.eventType, + timestamp: item.createdAt.toISO() ?? "", + })), + }; + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "data_about_servers_allowed_to_use_zeppelin", + prettyName: "Data about servers allowed to use Zeppelin", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const allowedGuilds = await AllowedGuild.query().where("owner_id", "=", userId).select(); + + return { + columns: ["serverId", "name", "icon", "ownerId", "createdAt", "updatedAt"], + rows: allowedGuilds.map((item) => ({ + serverId: item.id, + name: item.name ?? "", + icon: item.icon ?? "", + ownerId: item.ownerId ?? "", + createdAt: item.createdAt.toISO() ?? "", + updatedAt: item.updatedAt.toISO() ?? "", + })), + }; + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "supporters", + prettyName: "Supporters", + controller: "zeppelin", + + userSelfServeTools: { + getData: async (userId) => { + const supporters = await Supporter.query().where("user_id", "=", userId).select(); + + return { + columns: ["userId", "name", "amount"], + rows: supporters.map((item) => ({ + userId: item.userId, + name: item.name, + amount: item.amount ?? "", + })), + }; + }, + + deleteData: async (userId, trx) => { + await Supporter.query({ client: trx }).where("user_id", "=", userId).delete(); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "recent_messages", + prettyName: "Recent messages", + controller: "server", + + userSelfServeTools: { + getData: async (userId) => { + const recentMessages = await SavedMessage.query().where("user_id", "=", userId).select(); + + return { + columns: [ + "messageId", + "serverId", + "channelId", + "userId", + "isBot", + "data", + "postedAt", + "deletedAt", + "isPermanent", + ], + rows: recentMessages.map((item) => ({ + messageId: item.id, + serverId: item.guildId, + channelId: item.channelId, + userId: item.userId, + isBot: item.isBot ? "Yes" : "No", + data: JSON.stringify(decryptJson(item.data)), + postedAt: item.postedAt.toISO() ?? "", + deletedAt: item.deletedAt?.toISO() ?? "", + isPermanent: item.isPermanent ? "Yes" : "No", + })), + }; + }, + + getGuildIdsProcessingData: async (userId) => { + const result = await db.from("messages").where("user_id", "=", userId).select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "message_archives", + prettyName: "Message archives", + controller: "server", + + userSelfServeTools: {}, + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "server_configuration", + prettyName: "Server configuration", + controller: "server", + + userSelfServeTools: {}, + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "moderation_cases", + prettyName: "Moderation cases", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db + .from("cases") + .leftJoin("case_notes", "case_notes.case_id", "=", "cases.id") + .where((q) => { + q.orWhere("cases.user_id", "=", userId); + q.orWhere("cases.mod_id", "=", userId); + q.orWhere("cases.pp_id", "=", userId); + q.orWhere("case_notes.mod_id", "=", userId); + }) + .select(db.raw("DISTINCT cases.guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "mute_information", + prettyName: "Mute information", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db.from("mutes").where("user_id", "=", userId).select(db.raw("DISTINCT mutes.guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "counters", + prettyName: "Counters", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db + .from("counters") + .leftJoin("counter_values", "counter_values.counter_id", "=", "counters.id") + .where("counter_values.user_id", "=", userId) + .select(db.raw("DISTINCT counters.guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "persisted_member_data", + prettyName: "Persisted member data", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db.from("persisted_data").where("user_id", "=", userId).select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "member_timezones", + prettyName: "Member timezones", + controller: "server", + + userSelfServeTools: { + getData: async (userId) => { + const memberTimezones = await MemberTimezone.query().where("member_id", userId).select(); + + return { + columns: ["serverId", "userId", "timezone"], + rows: memberTimezones.map((item) => ({ + serverId: item.guildId, + userId: item.memberId, + timezone: item.timezone, + })), + }; + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "reminders", + prettyName: "Reminders", + controller: "server", + + userSelfServeTools: { + getData: async (userId) => { + const reminders = await Reminder.query().where("user_id", userId).select(); + + return { + columns: ["serverId", "userId", "channelId", "remindAt", "body", "createdAt"], + rows: reminders.map((item) => ({ + serverId: item.guildId, + userId: item.userId, + channelId: item.channelId, + remindAt: item.remindAt.toISO() ?? "", + body: item.body, + createdAt: item.createdAt.toISO() ?? "", + })), + }; + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "role_queue", + prettyName: "Role queue", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db.from("role_queue").where("user_id", "=", userId).select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "scheduled_posts", + prettyName: "Scheduled posts", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db + .from("scheduled_posts") + .where("author_id", "=", userId) + .select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "slowmode", + prettyName: "Slowmode", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db.from("slowmode_users").where("user_id", "=", userId).select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "starboard", + prettyName: "Starboard", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db + .from("starboard_reactions") + .where("reactor_id", "=", userId) + .select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "tags", + prettyName: "Tags", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db.from("tags").where("user_id", "=", userId).select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "temporary_bans", + prettyName: "Temporary bans", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db + .from("tempbans") + .where((q) => { + q.orWhere("user_id", "=", userId); + q.orWhere("mod_id", "=", userId); + }) + .select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); + +addAccountDataCategory({ + name: "vc_alerts", + prettyName: "Voice channel alerts", + controller: "server", + + userSelfServeTools: { + getGuildIdsProcessingData: async (userId) => { + const result = await db + .from("vc_alerts") + .where((q) => { + q.orWhere("user_id", "=", userId); + q.orWhere("requestor_id", "=", userId); + }) + .select(db.raw("DISTINCT guild_id")); + return result.map((r) => r.guild_id); + }, + }, + + serverSelfServeTools: {}, +}); diff --git a/portal/app/features/account/controllers/AccountController.ts b/portal/app/features/account/controllers/AccountController.ts new file mode 100644 index 000000000..d5b4b40bd --- /dev/null +++ b/portal/app/features/account/controllers/AccountController.ts @@ -0,0 +1,145 @@ +import { accountDataCategories, DataContainer } from "#backend/features/account/accountDataDefinitions"; +import AllowedGuild from "#backend/features/guilds/models/AllowedGuild"; +import type { HttpContext } from "@adonisjs/core/http"; +import db from "@adonisjs/lucid/services/db"; +import { stringify as toCsv } from "csv-stringify/sync"; +import JSZip from "jszip"; +import { Readable } from "node:stream"; + +interface CollectedData { + name: string; + prettyName: string; + data: DataContainer; +} + +export default class AccountController { + async getMyAccountPage({ inertia }: HttpContext) { + return inertia.render("features/account/pages/MyAccountPage", {}); + } + + async postDownloadMyAccountData({ response, auth }: HttpContext) { + const userId = auth.user!.discordUserId; + const zipBuffer = await buildAccountDataZip(userId); + + response.header("Content-Type", "application/zip"); + response.header("Content-Disposition", `attachment; filename="export-${userId}.zip"`); + response.header("Content-Length", String(zipBuffer.length)); + response.header("Cache-Control", "no-store"); + response.stream(Readable.from([zipBuffer])); + } + + async postDeleteMyAccountData({ response, auth, session, inertia }: HttpContext) { + const userId = auth.user!.discordUserId; + await deleteAccountData(userId); + + await auth.use("web").logout(); + + session.regenerate(); + session.flash("success", "Your data has been deleted and you have been logged out"); + + inertia.clearHistory(); + return response.redirect("/"); + } + + async getSpecificAccountPage({ inertia, params }: HttpContext) { + const userId = String(params.userId); + return inertia.render("features/account/pages/SpecificAccountPage", { userId }); + } + + async postDownloadSpecificAccountData({ params, response }: HttpContext) { + const userId = String(params.userId); + const zipBuffer = await buildAccountDataZip(userId); + + response.header("Content-Type", "application/zip"); + response.header("Content-Disposition", `attachment; filename="export-${userId}.zip"`); + response.header("Content-Length", String(zipBuffer.length)); + response.header("Cache-Control", "no-store"); + response.stream(Readable.from([zipBuffer])); + } + + async postDeleteSpecificAccountData({ params, response, session }: HttpContext) { + const userId = String(params.userId); + await deleteAccountData(userId); + + session.flash("success", `Data of user ${userId} has been deleted`); + response.redirect(`/specific-account/${userId}`); + } +} + +async function buildAccountDataZip(userId: string) { + const collectedDataList = await collectAccountData(userId); + const zip = new JSZip(); + for (const collectedData of collectedDataList) { + const rows = [ + collectedData.data.columns, + ...collectedData.data.rows.map((row) => { + return collectedData.data.columns.map((column) => row[column] ?? ""); + }), + ]; + zip.file(`${collectedData.name}.csv`, toCsv(rows, { escape_formulas: true })); + } + return zip.generateAsync({ + type: "nodebuffer", + compression: "DEFLATE", + compressionOptions: { level: 6 }, + }); +} + +async function collectAccountData(userId: string): Promise { + const collectedDataList: CollectedData[] = []; + const guildIdsProcessingData = new Set(); + for (const category of accountDataCategories) { + if (category.userSelfServeTools.getData) { + collectedDataList.push({ + name: category.name, + prettyName: category.prettyName, + data: await category.userSelfServeTools.getData(userId), + }); + } + if (category.userSelfServeTools.getGuildIdsProcessingData) { + for (const guildId of await category.userSelfServeTools.getGuildIdsProcessingData(userId)) { + guildIdsProcessingData.add(guildId); + } + } + } + + const guildsProcessingData: Map = new Map(); + if (guildIdsProcessingData.size) { + const guilds = await AllowedGuild.query().whereIn("id", Array.from(guildIdsProcessingData.values())).select(); + for (const guild of guilds) { + guildsProcessingData.set(guild.id, guild); + } + } + collectedDataList.push({ + name: "servers_processing_data_about_you", + prettyName: "Servers processing data about you", + data: { + columns: ["serverId", "serverName", "ownerId"], + rows: Array.from(guildIdsProcessingData.values()).map((guildId) => { + const guild = guildsProcessingData.get(guildId); + return { + serverId: guildId, + serverName: guild?.name ?? "", + ownerId: guild?.ownerId ?? "", + }; + }), + }, + }); + + return collectedDataList; +} + +async function deleteAccountData(userId: string): Promise { + const trx = await db.transaction(); + try { + for (const category of accountDataCategories) { + if (category.userSelfServeTools.deleteData) { + await category.userSelfServeTools.deleteData(userId, trx); + } + } + await trx.commit(); + } catch (err) { + await trx.rollback(); + throw err; + } +} diff --git a/portal/app/features/api/models/ApiAuditLog.ts b/portal/app/features/api/models/ApiAuditLog.ts new file mode 100644 index 000000000..84e153e46 --- /dev/null +++ b/portal/app/features/api/models/ApiAuditLog.ts @@ -0,0 +1,7 @@ +import { ApiAuditLogSchema } from "#database/schema"; + +export class ApiAuditLog extends ApiAuditLogSchema { + static table = "api_audit_log"; +} + +export default ApiAuditLog; diff --git a/portal/app/features/api/models/ApiLogin.ts b/portal/app/features/api/models/ApiLogin.ts new file mode 100644 index 000000000..f70b5ff95 --- /dev/null +++ b/portal/app/features/api/models/ApiLogin.ts @@ -0,0 +1,7 @@ +import { ApiLoginSchema } from "#database/schema"; + +export class ApiLogin extends ApiLoginSchema { + static table = "api_logins"; +} + +export default ApiLogin; diff --git a/portal/app/features/api/models/ApiPermission.ts b/portal/app/features/api/models/ApiPermission.ts new file mode 100644 index 000000000..738fe4131 --- /dev/null +++ b/portal/app/features/api/models/ApiPermission.ts @@ -0,0 +1,7 @@ +import { ApiPermissionSchema } from "#database/schema"; + +export class ApiPermission extends ApiPermissionSchema { + static table = "api_permissions"; +} + +export default ApiPermission; diff --git a/portal/app/features/api/models/ApiUserInfo.ts b/portal/app/features/api/models/ApiUserInfo.ts new file mode 100644 index 000000000..29587b86c --- /dev/null +++ b/portal/app/features/api/models/ApiUserInfo.ts @@ -0,0 +1,7 @@ +import { ApiUserInfoSchema } from "#database/schema"; + +export class ApiUserInfo extends ApiUserInfoSchema { + static table = "api_user_info"; +} + +export default ApiUserInfo; diff --git a/portal/app/features/archives/models/Archive.ts b/portal/app/features/archives/models/Archive.ts new file mode 100644 index 000000000..d6bfa8b21 --- /dev/null +++ b/portal/app/features/archives/models/Archive.ts @@ -0,0 +1,7 @@ +import { ArchiveSchema } from "#database/schema"; + +export class Archive extends ArchiveSchema { + static table = "archives"; +} + +export default Archive; diff --git a/portal/app/features/auth/controllers/AuthController.ts b/portal/app/features/auth/controllers/AuthController.ts new file mode 100644 index 000000000..6f7505779 --- /dev/null +++ b/portal/app/features/auth/controllers/AuthController.ts @@ -0,0 +1,56 @@ +import PortalUser from "#backend/features/auth/models/PortalUser"; +import type { HttpContext } from "@adonisjs/core/http"; +import { DateTime } from "luxon"; + +function normalizeUsername(username: string) { + return username.match(/^(.+)(#.*)?$/)![1]; +} + +export default class AuthController { + async getDiscordLogin({ ally, session }: HttpContext) { + // Return URL on failed login + session.put("redirect.previousUrl", "/"); + return ally.use("discord").redirect(); + } + + async getDiscordCallback({ ally, auth, response }: HttpContext) { + const discordUser = await ally.use("discord").user(); + + const user = await navigator.locks.request(`login-callback-${discordUser.id}`, async () => { + const existingUser = await PortalUser.query().where("discord_user_id", discordUser.id).first(); + + if (existingUser) { + existingUser.discordUsername = normalizeUsername(discordUser.name); + existingUser.discordAvatarUrl = discordUser.avatarUrl; + existingUser.lastLoginAt = DateTime.now(); + return existingUser.save(); + } + + const newUser = new PortalUser(); + newUser.discordUserId = discordUser.id; + newUser.discordUsername = normalizeUsername(discordUser.name); + newUser.discordAvatarUrl = discordUser.avatarUrl; + newUser.lastLoginAt = DateTime.now(); + return newUser.save(); + }); + + await auth.use("web").login(user); + + return response.redirect().withQs(false).toIntended("/account"); + } + + async postLogout({ auth, session, inertia, response }: HttpContext) { + if (!auth.user) { + session.flash("success", "You are not logged in"); + return response.redirect("/"); + } + + await auth.use("web").logout(); + + session.regenerate(); + session.flash("success", "You have been logged out"); + + inertia.clearHistory(); + return response.redirect("/"); + } +} diff --git a/portal/app/features/auth/middleware/authPageMiddleware.ts b/portal/app/features/auth/middleware/authPageMiddleware.ts new file mode 100644 index 000000000..14b23ab61 --- /dev/null +++ b/portal/app/features/auth/middleware/authPageMiddleware.ts @@ -0,0 +1,22 @@ +import { HttpContext } from "@adonisjs/core/http"; +import { NextFn } from "@adonisjs/core/types/http"; + +export class AuthPageMiddleware { + async handle({ auth, inertia, request, response, session }: HttpContext, next: NextFn) { + if (await auth.check()) { + return next(); + } + + if (request.method() !== "GET") { + return response.unauthorized({ + message: "Authentication required", + }); + } + + session.setIntendedUrl(request.url()); + + return response.send(await inertia.render("features/auth/pages/LoginRequiredPage", {})); + } +} + +export default AuthPageMiddleware; diff --git a/portal/app/features/auth/models/PortalUser.ts b/portal/app/features/auth/models/PortalUser.ts new file mode 100644 index 000000000..3b09fa263 --- /dev/null +++ b/portal/app/features/auth/models/PortalUser.ts @@ -0,0 +1,7 @@ +import { PortalUserSchema } from "#database/schema"; + +export class PortalUser extends PortalUserSchema { + static table = "portal_users"; +} + +export default PortalUser; diff --git a/portal/app/features/auth/transformers/PortalUserTransformer.ts b/portal/app/features/auth/transformers/PortalUserTransformer.ts new file mode 100644 index 000000000..3cad715e0 --- /dev/null +++ b/portal/app/features/auth/transformers/PortalUserTransformer.ts @@ -0,0 +1,10 @@ +import type { PortalUser } from "#backend/features/auth/models/PortalUser"; +import { BaseTransformer } from "@adonisjs/core/transformers"; + +export class PortalUserTransformer extends BaseTransformer { + toObject() { + return this.pick(this.resource, ["discordUserId", "discordUsername", "discordAvatarUrl"]); + } +} + +export default PortalUserTransformer; diff --git a/portal/app/features/autoReactions/models/AutoReaction.ts b/portal/app/features/autoReactions/models/AutoReaction.ts new file mode 100644 index 000000000..8481538e5 --- /dev/null +++ b/portal/app/features/autoReactions/models/AutoReaction.ts @@ -0,0 +1,7 @@ +import { AutoReactionSchema } from "#database/schema"; + +export class AutoReaction extends AutoReactionSchema { + static table = "auto_reactions"; +} + +export default AutoReaction; diff --git a/portal/app/features/automod/models/AntiraidLevel.ts b/portal/app/features/automod/models/AntiraidLevel.ts new file mode 100644 index 000000000..bfadbb166 --- /dev/null +++ b/portal/app/features/automod/models/AntiraidLevel.ts @@ -0,0 +1,7 @@ +import { AntiraidLevelSchema } from "#database/schema"; + +export class AntiraidLevel extends AntiraidLevelSchema { + static table = "antiraid_levels"; +} + +export default AntiraidLevel; diff --git a/portal/app/features/cases/models/Case.ts b/portal/app/features/cases/models/Case.ts new file mode 100644 index 000000000..866706f01 --- /dev/null +++ b/portal/app/features/cases/models/Case.ts @@ -0,0 +1,7 @@ +import { CaseSchema } from "#database/schema"; + +export class Case extends CaseSchema { + static table = "cases"; +} + +export default Case; diff --git a/portal/app/features/cases/models/CaseNote.ts b/portal/app/features/cases/models/CaseNote.ts new file mode 100644 index 000000000..2dd978281 --- /dev/null +++ b/portal/app/features/cases/models/CaseNote.ts @@ -0,0 +1,7 @@ +import { CaseNoteSchema } from "#database/schema"; + +export class CaseNote extends CaseNoteSchema { + static table = "case_notes"; +} + +export default CaseNote; diff --git a/portal/app/features/config/models/Config.ts b/portal/app/features/config/models/Config.ts new file mode 100644 index 000000000..4e9adcf60 --- /dev/null +++ b/portal/app/features/config/models/Config.ts @@ -0,0 +1,7 @@ +import { ConfigSchema } from "#database/schema"; + +export class Config extends ConfigSchema { + static table = "configs"; +} + +export default Config; diff --git a/portal/app/features/contextMenus/models/ContextMenu.ts b/portal/app/features/contextMenus/models/ContextMenu.ts new file mode 100644 index 000000000..c06c6b371 --- /dev/null +++ b/portal/app/features/contextMenus/models/ContextMenu.ts @@ -0,0 +1,7 @@ +import { ContextMenuSchema } from "#database/schema"; + +export class ContextMenu extends ContextMenuSchema { + static table = "context_menus"; +} + +export default ContextMenu; diff --git a/portal/app/features/counters/models/Counter.ts b/portal/app/features/counters/models/Counter.ts new file mode 100644 index 000000000..b837001ff --- /dev/null +++ b/portal/app/features/counters/models/Counter.ts @@ -0,0 +1,7 @@ +import { CounterSchema } from "#database/schema"; + +export class Counter extends CounterSchema { + static table = "counters"; +} + +export default Counter; diff --git a/portal/app/features/counters/models/CounterTrigger.ts b/portal/app/features/counters/models/CounterTrigger.ts new file mode 100644 index 000000000..6080dd282 --- /dev/null +++ b/portal/app/features/counters/models/CounterTrigger.ts @@ -0,0 +1,7 @@ +import { CounterTriggerSchema } from "#database/schema"; + +export class CounterTrigger extends CounterTriggerSchema { + static table = "counter_triggers"; +} + +export default CounterTrigger; diff --git a/portal/app/features/counters/models/CounterTriggerState.ts b/portal/app/features/counters/models/CounterTriggerState.ts new file mode 100644 index 000000000..149c742d5 --- /dev/null +++ b/portal/app/features/counters/models/CounterTriggerState.ts @@ -0,0 +1,7 @@ +import { CounterTriggerStateSchema } from "#database/schema"; + +export class CounterTriggerState extends CounterTriggerStateSchema { + static table = "counter_trigger_states"; +} + +export default CounterTriggerState; diff --git a/portal/app/features/counters/models/CounterValue.ts b/portal/app/features/counters/models/CounterValue.ts new file mode 100644 index 000000000..67260fe0d --- /dev/null +++ b/portal/app/features/counters/models/CounterValue.ts @@ -0,0 +1,7 @@ +import { CounterValueSchema } from "#database/schema"; + +export class CounterValue extends CounterValueSchema { + static table = "counter_values"; +} + +export default CounterValue; diff --git a/portal/app/features/docs/controllers/DocsController.ts b/portal/app/features/docs/controllers/DocsController.ts new file mode 100644 index 000000000..d5744b6e1 --- /dev/null +++ b/portal/app/features/docs/controllers/DocsController.ts @@ -0,0 +1,7 @@ +import type { HttpContext } from "@adonisjs/core/http"; + +export default class DocsController { + async getIndex({ inertia }: HttpContext) { + return inertia.render("features/docs/pages/DocsIndex", {}); + } +} diff --git a/portal/app/features/docs/utils/docsLayoutData.ts b/portal/app/features/docs/utils/docsLayoutData.ts new file mode 100644 index 000000000..5e90500f5 --- /dev/null +++ b/portal/app/features/docs/utils/docsLayoutData.ts @@ -0,0 +1,44 @@ +import { MenuCategory } from "#backend/features/menu/types"; +import { docsData } from "@zeppelinbot/shared/docsData.js"; + +const sortedGuildPlugins = docsData.guildPlugins.toSorted((a, b) => { + if (a.prettyName.toLowerCase() > b.prettyName.toLowerCase()) return 1; + if (a.prettyName.toLowerCase() < b.prettyName.toLowerCase()) return 1; + return 0; +}); + +const menu: MenuCategory[] = [ + { + title: "General", + items: [ + { + label: "Introduction", + path: "/docs", + }, + ], + }, + { + title: "Plugins", + items: sortedGuildPlugins + .filter((p) => p.type === "stable") + .map((p) => ({ + label: p.prettyName, + path: `/docs/plugins/${p.name}`, + })), + }, + { + title: "Legacy plugins", + items: sortedGuildPlugins + .filter((p) => p.type === "legacy") + .map((p) => ({ + label: p.prettyName, + path: `/docs/plugins/${p.name}`, + })), + }, +]; + +export const docsLayoutData = { + menu, +}; + +export type DocsLayoutData = typeof docsLayoutData; diff --git a/portal/app/features/docs/utils/formatZodConfigSchema.ts b/portal/app/features/docs/utils/formatZodConfigSchema.ts new file mode 100644 index 000000000..85c7c0fd6 --- /dev/null +++ b/portal/app/features/docs/utils/formatZodConfigSchema.ts @@ -0,0 +1,104 @@ +import { z } from "zod"; +import { $ZodPipeDef } from "zod/v4/core"; + +function indentLine(str: string, indentLength: number) { + return " ".repeat(indentLength) + str; +} + +function indentLines(str: string, indentLength: number) { + return str + .split("\n") + .map((line) => indentLine(line, indentLength)) + .join("\n"); +} + +function isZodObject(schema: z.ZodType): schema is z.ZodObject { + return schema.def.type === "object"; +} + +function isZodRecord(schema: z.ZodType): schema is z.ZodRecord { + return schema.def.type === "record"; +} + +function isZodOptional(schema: z.ZodType): schema is z.ZodOptional { + return schema.def.type === "optional"; +} + +function isZodArray(schema: z.ZodType): schema is z.ZodArray { + return schema.def.type === "array"; +} + +function isZodUnion(schema: z.ZodType): schema is z.ZodUnion { + return schema.def.type === "union"; +} + +function isZodNullable(schema: z.ZodType): schema is z.ZodNullable { + return schema.def.type === "nullable"; +} + +function isZodDefault(schema: z.ZodType): schema is z.ZodDefault { + return schema.def.type === "default"; +} + +function isZodLiteral(schema: z.ZodType): schema is z.ZodLiteral { + return schema.def.type === "literal"; +} + +function isZodIntersection(schema: z.ZodType): schema is z.ZodIntersection { + return schema.def.type === "intersection"; +} + +export function formatZodConfigSchema(schema: z.ZodType): string { + if (isZodObject(schema)) { + return ( + `{\n` + + Object.entries(schema.def.shape) + .map(([k, value]) => indentLines(`${k}: ${formatZodConfigSchema(value as z.ZodType)}`, 2)) + .join("\n") + + "\n}" + ); + } + if (isZodRecord(schema)) { + return "{\n" + indentLines(`[string]: ${formatZodConfigSchema(schema.valueType as z.ZodType)}`, 2) + "\n}"; + } + if (isZodOptional(schema)) { + return `Optional<${formatZodConfigSchema(schema.def.innerType)}>`; + } + if (isZodArray(schema)) { + return `Array<${formatZodConfigSchema(schema.def.element)}>`; + } + if (isZodUnion(schema)) { + return schema.def.options.map((t: any) => formatZodConfigSchema(t)).join(" | "); + } + if (isZodNullable(schema)) { + return `Nullable<${formatZodConfigSchema(schema.def.innerType)}>`; + } + if (isZodDefault(schema)) { + return formatZodConfigSchema(schema.def.innerType); + } + if (isZodLiteral(schema)) { + return schema.def.values.join(" | "); + } + if (isZodIntersection(schema)) { + return [ + formatZodConfigSchema(schema.def.left as z.ZodType), + formatZodConfigSchema(schema.def.right as z.ZodType), + ].join(" & "); + } + if (schema.def.type === "string") { + return "string"; + } + if (schema.def.type === "number") { + return "number"; + } + if (schema.def.type === "boolean") { + return "boolean"; + } + if (schema.def.type === "never") { + return "never"; + } + if (schema.def.type === "pipe") { + return formatZodConfigSchema((schema.def as $ZodPipeDef).in as z.ZodType); + } + return "unknown"; +} diff --git a/portal/app/features/guilds/models/AllowedGuild.ts b/portal/app/features/guilds/models/AllowedGuild.ts new file mode 100644 index 000000000..717248b82 --- /dev/null +++ b/portal/app/features/guilds/models/AllowedGuild.ts @@ -0,0 +1,7 @@ +import { AllowedGuildSchema } from "#database/schema"; + +export class AllowedGuild extends AllowedGuildSchema { + static table = "allowed_guilds"; +} + +export default AllowedGuild; diff --git a/portal/app/features/legal/controllers/PrivacyPolicyController.ts b/portal/app/features/legal/controllers/PrivacyPolicyController.ts new file mode 100644 index 000000000..ffa86fb5e --- /dev/null +++ b/portal/app/features/legal/controllers/PrivacyPolicyController.ts @@ -0,0 +1,20 @@ +import { readFile } from "node:fs/promises"; +import { isAbsolute } from "node:path"; +import app from "@adonisjs/core/services/app"; +import type { HttpContext } from "@adonisjs/core/http"; +import { portalEnv } from "#start/env"; + +export default class PrivacyPolicyController { + async getPrivacyPolicyPage({ inertia }: HttpContext) { + let markdown = "No privacy policy configured. Please contact the site administrator."; + const configuredPath = portalEnv.get("PORTAL_PRIVACY_POLICY_PATH"); + if (configuredPath) { + const filePath = isAbsolute(configuredPath) ? configuredPath : app.makePath(configuredPath); + markdown = await readFile(filePath, "utf8"); + } + + return inertia.render("features/legal/pages/PrivacyPolicyPage", { + privacyPolicyMd: markdown, + }); + } +} diff --git a/portal/app/features/locateUser/models/VcAlert.ts b/portal/app/features/locateUser/models/VcAlert.ts new file mode 100644 index 000000000..8fe19241f --- /dev/null +++ b/portal/app/features/locateUser/models/VcAlert.ts @@ -0,0 +1,7 @@ +import { VcAlertSchema } from "#database/schema"; + +export class VcAlert extends VcAlertSchema { + static table = "vc_alerts"; +} + +export default VcAlert; diff --git a/portal/app/features/members/models/MemberCacheItem.ts b/portal/app/features/members/models/MemberCacheItem.ts new file mode 100644 index 000000000..eb1590a12 --- /dev/null +++ b/portal/app/features/members/models/MemberCacheItem.ts @@ -0,0 +1,7 @@ +import { MemberCacheSchema } from "#database/schema"; + +export class MemberCacheItem extends MemberCacheSchema { + static table = "member_cache"; +} + +export default MemberCacheItem; diff --git a/portal/app/features/menu/types.ts b/portal/app/features/menu/types.ts new file mode 100644 index 000000000..9790f2940 --- /dev/null +++ b/portal/app/features/menu/types.ts @@ -0,0 +1,10 @@ +export type MenuItem = { + label: string; + path: string; + activeStartsWith?: boolean; +}; + +export type MenuCategory = { + title: string; + items: MenuItem[]; +}; diff --git a/portal/app/features/messages/models/SavedMessage.ts b/portal/app/features/messages/models/SavedMessage.ts new file mode 100644 index 000000000..c17bd201b --- /dev/null +++ b/portal/app/features/messages/models/SavedMessage.ts @@ -0,0 +1,7 @@ +import { MessageSchema } from "#database/schema"; + +export class SavedMessage extends MessageSchema { + static table = "messages"; +} + +export default SavedMessage; diff --git a/portal/app/features/modActions/models/Tempban.ts b/portal/app/features/modActions/models/Tempban.ts new file mode 100644 index 000000000..92a264076 --- /dev/null +++ b/portal/app/features/modActions/models/Tempban.ts @@ -0,0 +1,7 @@ +import { TempbanSchema } from "#database/schema"; + +export class Tempban extends TempbanSchema { + static table = "tempbans"; +} + +export default Tempban; diff --git a/portal/app/features/mutes/models/Mute.ts b/portal/app/features/mutes/models/Mute.ts new file mode 100644 index 000000000..845e243b6 --- /dev/null +++ b/portal/app/features/mutes/models/Mute.ts @@ -0,0 +1,7 @@ +import { MuteSchema } from "#database/schema"; + +export class Mute extends MuteSchema { + static table = "mutes"; +} + +export default Mute; diff --git a/portal/app/features/nameHistory/models/NicknameHistoryEntry.ts b/portal/app/features/nameHistory/models/NicknameHistoryEntry.ts new file mode 100644 index 000000000..7f246fdcc --- /dev/null +++ b/portal/app/features/nameHistory/models/NicknameHistoryEntry.ts @@ -0,0 +1,7 @@ +import { NicknameHistorySchema } from "#database/schema"; + +export class NicknameHistoryEntry extends NicknameHistorySchema { + static table = "nickname_history"; +} + +export default NicknameHistoryEntry; diff --git a/portal/app/features/nameHistory/models/UsernameHistoryEntry.ts b/portal/app/features/nameHistory/models/UsernameHistoryEntry.ts new file mode 100644 index 000000000..08257e69e --- /dev/null +++ b/portal/app/features/nameHistory/models/UsernameHistoryEntry.ts @@ -0,0 +1,7 @@ +import { UsernameHistorySchema } from "#database/schema"; + +export class UsernameHistoryEntry extends UsernameHistorySchema { + static table = "username_history"; +} + +export default UsernameHistoryEntry; diff --git a/portal/app/features/persist/models/PersistedData.ts b/portal/app/features/persist/models/PersistedData.ts new file mode 100644 index 000000000..4e87ce16d --- /dev/null +++ b/portal/app/features/persist/models/PersistedData.ts @@ -0,0 +1,7 @@ +import { PersistedDatumSchema } from "#database/schema"; + +export class PersistedData extends PersistedDatumSchema { + static table = "persisted_data"; +} + +export default PersistedData; diff --git a/portal/app/features/pingableRoles/models/PingableRole.ts b/portal/app/features/pingableRoles/models/PingableRole.ts new file mode 100644 index 000000000..a90776c53 --- /dev/null +++ b/portal/app/features/pingableRoles/models/PingableRole.ts @@ -0,0 +1,7 @@ +import { PingableRoleSchema } from "#database/schema"; + +export class PingableRole extends PingableRoleSchema { + static table = "pingable_roles"; +} + +export default PingableRole; diff --git a/portal/app/features/post/models/ScheduledPost.ts b/portal/app/features/post/models/ScheduledPost.ts new file mode 100644 index 000000000..925fdefd4 --- /dev/null +++ b/portal/app/features/post/models/ScheduledPost.ts @@ -0,0 +1,7 @@ +import { ScheduledPostSchema } from "#database/schema"; + +export class ScheduledPost extends ScheduledPostSchema { + static table = "scheduled_posts"; +} + +export default ScheduledPost; diff --git a/portal/app/features/reactionRoles/models/ReactionRole.ts b/portal/app/features/reactionRoles/models/ReactionRole.ts new file mode 100644 index 000000000..1a3f94da6 --- /dev/null +++ b/portal/app/features/reactionRoles/models/ReactionRole.ts @@ -0,0 +1,7 @@ +import { ReactionRoleSchema } from "#database/schema"; + +export class ReactionRole extends ReactionRoleSchema { + static table = "reaction_roles"; +} + +export default ReactionRole; diff --git a/portal/app/features/reminders/models/Reminder.ts b/portal/app/features/reminders/models/Reminder.ts new file mode 100644 index 000000000..0191524f0 --- /dev/null +++ b/portal/app/features/reminders/models/Reminder.ts @@ -0,0 +1,7 @@ +import { ReminderSchema } from "#database/schema"; + +export class Reminder extends ReminderSchema { + static table = "reminders"; +} + +export default Reminder; diff --git a/portal/app/features/roleButtons/models/RoleButton.ts b/portal/app/features/roleButtons/models/RoleButton.ts new file mode 100644 index 000000000..68fe6f5e4 --- /dev/null +++ b/portal/app/features/roleButtons/models/RoleButton.ts @@ -0,0 +1,7 @@ +import { RoleButtonSchema } from "#database/schema"; + +export class RoleButton extends RoleButtonSchema { + static table = "role_buttons"; +} + +export default RoleButton; diff --git a/portal/app/features/roleManager/models/RoleQueueItem.ts b/portal/app/features/roleManager/models/RoleQueueItem.ts new file mode 100644 index 000000000..8dc7a0ee4 --- /dev/null +++ b/portal/app/features/roleManager/models/RoleQueueItem.ts @@ -0,0 +1,7 @@ +import { RoleQueueSchema } from "#database/schema"; + +export class RoleQueueItem extends RoleQueueSchema { + static table = "role_queue"; +} + +export default RoleQueueItem; diff --git a/portal/app/features/selfGrantableRoles/models/SelfGrantableRole.ts b/portal/app/features/selfGrantableRoles/models/SelfGrantableRole.ts new file mode 100644 index 000000000..b7fd590c5 --- /dev/null +++ b/portal/app/features/selfGrantableRoles/models/SelfGrantableRole.ts @@ -0,0 +1,7 @@ +import { SelfGrantableRoleSchema } from "#database/schema"; + +export class SelfGrantableRole extends SelfGrantableRoleSchema { + static table = "self_grantable_roles"; +} + +export default SelfGrantableRole; diff --git a/portal/app/features/slowmode/models/SlowmodeChannel.ts b/portal/app/features/slowmode/models/SlowmodeChannel.ts new file mode 100644 index 000000000..1e43a7198 --- /dev/null +++ b/portal/app/features/slowmode/models/SlowmodeChannel.ts @@ -0,0 +1,7 @@ +import { SlowmodeChannelSchema } from "#database/schema"; + +export class SlowmodeChannel extends SlowmodeChannelSchema { + static table = "slowmode_channels"; +} + +export default SlowmodeChannel; diff --git a/portal/app/features/slowmode/models/SlowmodeUser.ts b/portal/app/features/slowmode/models/SlowmodeUser.ts new file mode 100644 index 000000000..8b8a7f3ce --- /dev/null +++ b/portal/app/features/slowmode/models/SlowmodeUser.ts @@ -0,0 +1,7 @@ +import { SlowmodeUserSchema } from "#database/schema"; + +export class SlowmodeUser extends SlowmodeUserSchema { + static table = "slowmode_users"; +} + +export default SlowmodeUser; diff --git a/portal/app/features/splash/controllers/SplashController.ts b/portal/app/features/splash/controllers/SplashController.ts new file mode 100644 index 000000000..355b52a35 --- /dev/null +++ b/portal/app/features/splash/controllers/SplashController.ts @@ -0,0 +1,7 @@ +import type { HttpContext } from "@adonisjs/core/http"; + +export default class SplashController { + async getIndex({ inertia }: HttpContext) { + return inertia.render("features/splash/pages/SplashIndex", { example: "hi" }); + } +} diff --git a/portal/app/features/starboard/models/StarboardMessage.ts b/portal/app/features/starboard/models/StarboardMessage.ts new file mode 100644 index 000000000..255008f71 --- /dev/null +++ b/portal/app/features/starboard/models/StarboardMessage.ts @@ -0,0 +1,7 @@ +import { StarboardMessageSchema } from "#database/schema"; + +export class StarboardMessage extends StarboardMessageSchema { + static table = "starboard_messages"; +} + +export default StarboardMessage; diff --git a/portal/app/features/starboard/models/StarboardReaction.ts b/portal/app/features/starboard/models/StarboardReaction.ts new file mode 100644 index 000000000..f6673139f --- /dev/null +++ b/portal/app/features/starboard/models/StarboardReaction.ts @@ -0,0 +1,7 @@ +import { StarboardReactionSchema } from "#database/schema"; + +export class StarboardReaction extends StarboardReactionSchema { + static table = "starboard_reactions"; +} + +export default StarboardReaction; diff --git a/portal/app/features/supporters/models/Supporter.ts b/portal/app/features/supporters/models/Supporter.ts new file mode 100644 index 000000000..bfd58e53b --- /dev/null +++ b/portal/app/features/supporters/models/Supporter.ts @@ -0,0 +1,7 @@ +import { SupporterSchema } from "#database/schema"; + +export class Supporter extends SupporterSchema { + static table = "supporters"; +} + +export default Supporter; diff --git a/portal/app/features/tags/models/Tag.ts b/portal/app/features/tags/models/Tag.ts new file mode 100644 index 000000000..3aef71f4e --- /dev/null +++ b/portal/app/features/tags/models/Tag.ts @@ -0,0 +1,7 @@ +import { TagSchema } from "#database/schema"; + +export class Tag extends TagSchema { + static table = "tags"; +} + +export default Tag; diff --git a/portal/app/features/tags/models/TagResponse.ts b/portal/app/features/tags/models/TagResponse.ts new file mode 100644 index 000000000..ccabbf8d1 --- /dev/null +++ b/portal/app/features/tags/models/TagResponse.ts @@ -0,0 +1,7 @@ +import { TagResponseSchema } from "#database/schema"; + +export class TagResponse extends TagResponseSchema { + static table = "tag_responses"; +} + +export default TagResponse; diff --git a/portal/app/features/timeAndDate/models/MemberTimezone.ts b/portal/app/features/timeAndDate/models/MemberTimezone.ts new file mode 100644 index 000000000..a7f5cba0b --- /dev/null +++ b/portal/app/features/timeAndDate/models/MemberTimezone.ts @@ -0,0 +1,7 @@ +import { MemberTimezoneSchema } from "#database/schema"; + +export class MemberTimezone extends MemberTimezoneSchema { + static table = "member_timezones"; +} + +export default MemberTimezone; diff --git a/portal/app/features/webhooks/models/Webhook.ts b/portal/app/features/webhooks/models/Webhook.ts new file mode 100644 index 000000000..1a9aa4f34 --- /dev/null +++ b/portal/app/features/webhooks/models/Webhook.ts @@ -0,0 +1,7 @@ +import { WebhookSchema } from "#database/schema"; + +export class Webhook extends WebhookSchema { + static table = "webhooks"; +} + +export default Webhook; diff --git a/portal/app/isStaff.ts b/portal/app/isStaff.ts new file mode 100644 index 000000000..c3f3da0a0 --- /dev/null +++ b/portal/app/isStaff.ts @@ -0,0 +1,10 @@ +import { rootEnv } from "#start/env"; + +const staffUserIds = (rootEnv.get("STAFF") ?? "") + .split(",") + .map((v) => v.trim()) + .filter((v) => Boolean(v)); + +export function isStaff(userId: string) { + return staffUserIds.includes(userId); +} diff --git a/portal/app/middleware/authMiddleware.ts b/portal/app/middleware/authMiddleware.ts new file mode 100644 index 000000000..fb5e5fdb7 --- /dev/null +++ b/portal/app/middleware/authMiddleware.ts @@ -0,0 +1,12 @@ +import type { HttpContext } from "@adonisjs/core/http"; +import type { NextFn } from "@adonisjs/core/types/http"; +import type { Authenticators } from "@adonisjs/auth/types"; + +export default class AuthMiddleware { + redirectTo = "/login"; + + async handle(ctx: HttpContext, next: NextFn, options: { guards?: (keyof Authenticators)[] } = {}) { + await ctx.auth.authenticateUsing(options.guards, { loginRoute: this.redirectTo }); + return next(); + } +} diff --git a/portal/app/middleware/containerBindingsMiddleware.ts b/portal/app/middleware/containerBindingsMiddleware.ts new file mode 100644 index 000000000..3d5f95c4a --- /dev/null +++ b/portal/app/middleware/containerBindingsMiddleware.ts @@ -0,0 +1,19 @@ +import { Logger } from "@adonisjs/core/logger"; +import { HttpContext } from "@adonisjs/core/http"; +import { type NextFn } from "@adonisjs/core/types/http"; + +/** + * The container bindings middleware binds classes to their request + * specific value using the container resolver. + * + * - We bind "HttpContext" class to the "ctx" object + * - And bind "Logger" class to the "ctx.logger" object + */ +export default class ContainerBindingsMiddleware { + handle(ctx: HttpContext, next: NextFn) { + ctx.containerResolver.bindValue(HttpContext, ctx); + ctx.containerResolver.bindValue(Logger, ctx.logger); + + return next(); + } +} diff --git a/portal/app/middleware/guestMiddleware.ts b/portal/app/middleware/guestMiddleware.ts new file mode 100644 index 000000000..28cd12911 --- /dev/null +++ b/portal/app/middleware/guestMiddleware.ts @@ -0,0 +1,28 @@ +import type { HttpContext } from "@adonisjs/core/http"; +import type { NextFn } from "@adonisjs/core/types/http"; +import type { Authenticators } from "@adonisjs/auth/types"; + +/** + * Guest middleware is used to deny access to routes that should + * be accessed by unauthenticated users. + * + * For example, the login page should not be accessible if the user + * is already logged-in + */ +export default class GuestMiddleware { + /** + * The URL to redirect to when user is logged-in + */ + redirectTo = "/"; + + async handle(ctx: HttpContext, next: NextFn, options: { guards?: (keyof Authenticators)[] } = {}) { + for (let guard of options.guards || [ctx.auth.defaultGuard]) { + if (await ctx.auth.use(guard).check()) { + ctx.session.reflash(); + return ctx.response.redirect(this.redirectTo, true); + } + } + + return next(); + } +} diff --git a/portal/app/middleware/inertiaMiddleware.ts b/portal/app/middleware/inertiaMiddleware.ts new file mode 100644 index 000000000..a78190c62 --- /dev/null +++ b/portal/app/middleware/inertiaMiddleware.ts @@ -0,0 +1,62 @@ +import type { HttpContext } from "@adonisjs/core/http"; +import type { NextFn } from "@adonisjs/core/types/http"; +import BaseInertiaMiddleware from "@adonisjs/inertia/inertia_middleware"; +import { PortalUserTransformer } from "#backend/features/auth/transformers/PortalUserTransformer"; + +export default class InertiaMiddleware extends BaseInertiaMiddleware { + share(ctx: HttpContext) { + /** + * The share method is called everytime an Inertia page is rendered. In + * certain cases, a page may get rendered before the session middleware + * or the auth middleware are executed. For example: During a 404 request. + * + * In that case, we must always assume that HttpContext is not fully hydrated + * with all the properties + */ + const { auth, request } = ctx as Partial; + + const theme: "light" | "dark" = + request?.plainCookie("app_theme", { + defaultValue: "light", + encoded: false, + }) ?? "light"; + + /** + * Data shared with all Inertia pages. Make sure you are using + * transformers for rich data-types like Models. + */ + return { + errors: ctx.inertia.always(this.getValidationErrors(ctx)), + user: ctx.inertia.always(auth?.user ? PortalUserTransformer.transform(auth.user) : undefined), + preferences: ctx.inertia.always({ theme }), + }; + } + + flash(ctx: HttpContext) { + /** + * Flash messages travel in the dedicated `flash` field of the page + * object instead of props, and the client strips them from history + * state so they never reappear when navigating back. + */ + const { session } = ctx as Partial; + + const success: string | undefined = session?.flashMessages.get("success"); + const error: string | undefined = session?.flashMessages.get("error"); + + return { success, error }; + } + + async handle(ctx: HttpContext, next: NextFn) { + await this.init(ctx); + + const output = await next(); + this.dispose(ctx); + + return output; + } +} + +declare module "@adonisjs/inertia/types" { + type MiddlewareSharedProps = InferSharedProps; + export interface SharedProps extends MiddlewareSharedProps {} +} diff --git a/portal/app/middleware/isStaffMiddleware.ts b/portal/app/middleware/isStaffMiddleware.ts new file mode 100644 index 000000000..02b7ccf63 --- /dev/null +++ b/portal/app/middleware/isStaffMiddleware.ts @@ -0,0 +1,15 @@ +import { isStaff } from "#backend/isStaff"; +import type { HttpContext } from "@adonisjs/core/http"; +import type { NextFn } from "@adonisjs/core/types/http"; + +export default class IsStaffMiddleware { + async handle({ auth, response }: HttpContext, next: NextFn) { + const user = auth.getUserOrFail(); + + if (!isStaff(user.discordUserId)) { + return response.forbidden("Access denied"); + } + + return next(); + } +} diff --git a/portal/app/middleware/silentAuthMiddleware.ts b/portal/app/middleware/silentAuthMiddleware.ts new file mode 100644 index 000000000..8969ed4b1 --- /dev/null +++ b/portal/app/middleware/silentAuthMiddleware.ts @@ -0,0 +1,16 @@ +import type { HttpContext } from "@adonisjs/core/http"; +import type { NextFn } from "@adonisjs/core/types/http"; + +/** + * Silent auth middleware can be used as a global middleware to silent check + * if the user is logged-in or not. + * + * The request continues as usual, even when the user is not logged-in. + */ +export default class SilentAuthMiddleware { + async handle(ctx: HttpContext, next: NextFn) { + await ctx.auth.check(); + + return next(); + } +} diff --git a/portal/bin/console.ts b/portal/bin/console.ts new file mode 100644 index 000000000..a6a8c569a --- /dev/null +++ b/portal/bin/console.ts @@ -0,0 +1,47 @@ +/* +|-------------------------------------------------------------------------- +| Ace entry point +|-------------------------------------------------------------------------- +| +| The "console.ts" file is the entrypoint for booting the AdonisJS +| command-line framework and executing commands. +| +| Commands do not boot the application, unless the currently running command +| has "options.startApp" flag set to true. +| +*/ + +await import("reflect-metadata"); +const { Ignitor, prettyPrintError } = await import("@adonisjs/core/ignitor"); + +/** + * URL to the application root. AdonisJS need it to resolve + * paths to file and directories for scaffolding commands + */ +const APP_ROOT = new URL("../", import.meta.url); + +/** + * The importer is used to import files in context of the + * application. + */ +const IMPORTER = (filePath: string) => { + if (filePath.startsWith("./") || filePath.startsWith("../")) { + return import(new URL(filePath, APP_ROOT).href); + } + return import(filePath); +}; + +new Ignitor(APP_ROOT, { importer: IMPORTER }) + .tap((app) => { + app.booting(async () => { + await import("#start/env"); + }); + app.listen("SIGTERM", () => app.terminate()); + app.listenIf(app.managedByPm2, "SIGINT", () => app.terminate()); + }) + .ace() + .handle(process.argv.splice(2)) + .catch((error) => { + process.exitCode = 1; + prettyPrintError(error); + }); diff --git a/portal/bin/server.ts b/portal/bin/server.ts new file mode 100644 index 000000000..529d06ecf --- /dev/null +++ b/portal/bin/server.ts @@ -0,0 +1,45 @@ +/* +|-------------------------------------------------------------------------- +| HTTP server entrypoint +|-------------------------------------------------------------------------- +| +| The "server.ts" file is the entrypoint for starting the AdonisJS HTTP +| server. Either you can run this file directly or use the "serve" +| command to run this file and monitor file changes +| +*/ + +await import("reflect-metadata"); +const { Ignitor, prettyPrintError } = await import("@adonisjs/core/ignitor"); + +/** + * URL to the application root. AdonisJS need it to resolve + * paths to file and directories for scaffolding commands + */ +const APP_ROOT = new URL("../", import.meta.url); + +/** + * The importer is used to import files in context of the + * application. + */ +const IMPORTER = (filePath: string) => { + if (filePath.startsWith("./") || filePath.startsWith("../")) { + return import(new URL(filePath, APP_ROOT).href); + } + return import(filePath); +}; + +new Ignitor(APP_ROOT, { importer: IMPORTER }) + .tap((app) => { + app.booting(async () => { + await import("#start/env"); + }); + app.listen("SIGTERM", () => app.terminate()); + app.listenIf(app.managedByPm2, "SIGINT", () => app.terminate()); + }) + .httpServer() + .start() + .catch((error) => { + process.exitCode = 1; + prettyPrintError(error); + }); diff --git a/portal/bin/test.ts b/portal/bin/test.ts new file mode 100644 index 000000000..08acc0584 --- /dev/null +++ b/portal/bin/test.ts @@ -0,0 +1,60 @@ +/* +|-------------------------------------------------------------------------- +| Test runner entrypoint +|-------------------------------------------------------------------------- +| +| The "test.ts" file is the entrypoint for running tests using Japa. +| +| Either you can run this file directly or use the "test" +| command to run this file and monitor file changes. +| +*/ + +process.env.NODE_ENV = "test"; + +import "reflect-metadata"; +import { Ignitor, prettyPrintError } from "@adonisjs/core/ignitor"; +import { configure, processCLIArgs, run } from "@japa/runner"; + +/** + * URL to the application root. AdonisJS need it to resolve + * paths to file and directories for scaffolding commands + */ +const APP_ROOT = new URL("../", import.meta.url); + +/** + * The importer is used to import files in context of the + * application. + */ +const IMPORTER = (filePath: string) => { + if (filePath.startsWith("./") || filePath.startsWith("../")) { + return import(new URL(filePath, APP_ROOT).href); + } + return import(filePath); +}; + +new Ignitor(APP_ROOT, { importer: IMPORTER }) + .tap((app) => { + app.booting(async () => { + await import("#start/env"); + }); + app.listen("SIGTERM", () => app.terminate()); + app.listenIf(app.managedByPm2, "SIGINT", () => app.terminate()); + }) + .testRunner() + .configure(async (app) => { + const { runnerHooks, ...config } = await import("../tests/bootstrap.js"); + + processCLIArgs(process.argv.splice(2)); + configure({ + ...app.rcFile.tests, + ...config, + setup: runnerHooks.setup, + teardown: runnerHooks.teardown.concat([() => app.terminate()]), + }); + }) + .run(() => run()) + .catch((error) => { + process.exitCode = 1; + prettyPrintError(error); + }); diff --git a/portal/config/ally.ts b/portal/config/ally.ts new file mode 100644 index 000000000..8b23e4105 --- /dev/null +++ b/portal/config/ally.ts @@ -0,0 +1,17 @@ +import { rootEnv } from "#start/env"; +import { defineConfig, services } from "@adonisjs/ally"; + +const allyConfig = defineConfig({ + discord: services.discord({ + clientId: rootEnv.get("CLIENT_ID"), + clientSecret: rootEnv.get("CLIENT_SECRET"), + callbackUrl: `${rootEnv.get("PORTAL_URL")}/oauth/discord/callback`, + scopes: ["identify"], + }), +}); + +export default allyConfig; + +declare module "@adonisjs/ally/types" { + interface SocialProviders extends InferSocialProviders {} +} diff --git a/portal/config/app.ts b/portal/config/app.ts new file mode 100644 index 000000000..1191620a8 --- /dev/null +++ b/portal/config/app.ts @@ -0,0 +1,80 @@ +import app from "@adonisjs/core/services/app"; +import { defineConfig } from "@adonisjs/core/http"; + +/** + * The configuration settings used by the HTTP server + */ +export const http = defineConfig({ + /** + * Generate a unique request id for each incoming request. + * Useful to correlate logs and debug a request flow. + */ + generateRequestId: true, + + /** + * Allow HTTP method spoofing via the "_method" form/query parameter. + * This lets HTML forms target PUT/PATCH/DELETE routes while still + * submitting with POST. + */ + allowMethodSpoofing: false, + + /** + * Enabling async local storage will let you access HTTP context + * from anywhere inside your application. + */ + useAsyncLocalStorage: false, + + router: { + matcher: "tree", + }, + + /** + * Redirect configuration controls the behavior of + * response.redirect().back() and query string forwarding. + */ + redirect: { + /** + * When enabled, all redirects automatically carry over the current + * request's query string parameters to the redirect destination. + * Use withQs(false) to opt out for a specific redirect. + */ + forwardQueryString: true, + }, + + /** + * Manage cookies configuration. The settings for the session id cookie are + * defined inside the "config/session.ts" file. + */ + cookie: { + /** + * Restrict the cookie to a specific domain. + * Keep empty to use the current host. + */ + domain: "", + + /** + * Restrict the cookie to a URL path. '/' means all routes. + */ + path: "/", + + /** + * Default lifetime for cookies managed by the HTTP layer. + */ + maxAge: "2h", + + /** + * Prevent JavaScript access to the cookie in the browser. + */ + httpOnly: true, + + /** + * Send cookies only over HTTPS in production. + */ + secure: app.inProduction, + + /** + * Cross-site policy for cookie sending. + */ + sameSite: "lax", + }, +}); diff --git a/portal/config/auth.ts b/portal/config/auth.ts new file mode 100644 index 000000000..552daa9ff --- /dev/null +++ b/portal/config/auth.ts @@ -0,0 +1,39 @@ +import { defineConfig } from "@adonisjs/auth"; +import { sessionGuard, sessionUserProvider } from "@adonisjs/auth/session"; +import type { InferAuthenticators, InferAuthEvents, Authenticators } from "@adonisjs/auth/types"; + +const authConfig = defineConfig({ + /** + * Default guard used when no guard is explicitly specified. + */ + default: "web", + + guards: { + /** + * Session-based guard for browser authentication. + */ + web: sessionGuard({ + /** + * Enable persistent login using remember-me tokens. + */ + useRememberMeTokens: false, + + provider: sessionUserProvider({ + model: () => import("#backend/features/auth/models/PortalUser"), + }), + }), + }, +}); + +export default authConfig; + +/** + * Inferring types from the configured auth + * guards. + */ +declare module "@adonisjs/auth/types" { + export interface Authenticators extends InferAuthenticators {} +} +declare module "@adonisjs/core/types" { + interface EventsList extends InferAuthEvents {} +} diff --git a/portal/config/bodyparser.ts b/portal/config/bodyparser.ts new file mode 100644 index 000000000..e3d8e469d --- /dev/null +++ b/portal/config/bodyparser.ts @@ -0,0 +1,73 @@ +import { defineConfig } from "@adonisjs/core/bodyparser"; + +const bodyParserConfig = defineConfig({ + /** + * Parse request bodies for these HTTP methods. + * Keep this aligned with methods that receive payloads in your routes. + */ + allowedMethods: ["POST", "PUT", "PATCH", "DELETE"], + + /** + * Config for the "application/x-www-form-urlencoded" + * content-type parser. + */ + form: { + /** + * Normalize empty string values to null. + */ + convertEmptyStringsToNull: true, + + /** + * Content types handled by the form parser. + */ + types: ["application/x-www-form-urlencoded"], + }, + + /** + * Config for the JSON parser. + */ + json: { + /** + * Normalize empty string values to null. + */ + convertEmptyStringsToNull: true, + + /** + * Content types handled by the JSON parser. + */ + types: ["application/json", "application/json-patch+json", "application/vnd.api+json", "application/csp-report"], + }, + + /** + * Config for the "multipart/form-data" content-type parser. + * File uploads are handled by the multipart parser. + */ + multipart: { + /** + * Automatically process uploaded files into the system tmp directory. + */ + autoProcess: true, + + /** + * Normalize empty string values to null. + */ + convertEmptyStringsToNull: true, + + /** + * Routes where multipart processing is handled manually. + */ + processManually: [], + + /** + * Maximum accepted payload size for multipart requests. + */ + limit: "20mb", + + /** + * Content types handled by the multipart parser. + */ + types: ["multipart/form-data"], + }, +}); + +export default bodyParserConfig; diff --git a/portal/config/cors.ts b/portal/config/cors.ts new file mode 100644 index 000000000..40abe38f3 --- /dev/null +++ b/portal/config/cors.ts @@ -0,0 +1,50 @@ +import app from "@adonisjs/core/services/app"; +import { defineConfig } from "@adonisjs/cors"; + +/** + * Configuration options to tweak the CORS policy. The following + * options are documented on the official documentation website. + * + * https://docs.adonisjs.com/guides/security/cors + */ +const corsConfig = defineConfig({ + /** + * Enable or disable CORS handling globally. + */ + enabled: true, + + /** + * In development, allow every origin to simplify local front/backend setup. + * In production, keep an explicit allowlist (empty by default, so no + * cross-origin browser access is allowed until configured). + */ + origin: app.inDev ? true : [], + + /** + * HTTP methods accepted for cross-origin requests. + */ + methods: ["GET", "HEAD", "POST", "PUT", "DELETE"], + + /** + * Reflect request headers by default. Use a string array to restrict + * allowed headers. + */ + headers: true, + + /** + * Response headers exposed to the browser. + */ + exposeHeaders: [], + + /** + * Allow cookies/authorization headers on cross-origin requests. + */ + credentials: true, + + /** + * Cache CORS preflight response for N seconds. + */ + maxAge: 90, +}); + +export default corsConfig; diff --git a/portal/config/database.ts b/portal/config/database.ts new file mode 100644 index 000000000..80714a0b3 --- /dev/null +++ b/portal/config/database.ts @@ -0,0 +1,47 @@ +import { rootEnv } from "#start/env"; +import { defineConfig } from "@adonisjs/lucid"; + +const dbConfig = defineConfig({ + /** + * Default connection used for all queries. + */ + connection: "mysql", + + connections: { + mysql: { + client: "mysql2", + + connection: { + host: rootEnv.get("DB_HOST", "mysql"), + port: rootEnv.get("DB_PORT", 3306), + user: rootEnv.get("DB_USER", "zeppelin"), + password: rootEnv.get("DB_PASSWORD", rootEnv.get("DEVELOPMENT_MYSQL_PASSWORD", "")), + database: rootEnv.get("DB_DATABASE", "zeppelin"), + timezone: "Z", + supportBigNumbers: true, + bigNumberStrings: true, + charset: "utf8mb4", + }, + + migrations: { + /** + * Sort migration files naturally by filename. + */ + naturalSort: true, + + /** + * Paths containing migration files. + */ + paths: ["database/migrations"], + }, + + schemaGeneration: { + enabled: true, + rulesPaths: ["./database/schemaRules.js"], + excludeTables: ["migrations"], + }, + }, + }, +}); + +export default dbConfig; diff --git a/portal/config/encryption.ts b/portal/config/encryption.ts new file mode 100644 index 000000000..3cd9cc47d --- /dev/null +++ b/portal/config/encryption.ts @@ -0,0 +1,34 @@ +import { rootEnv } from "#start/env"; +import { defineConfig, drivers } from "@adonisjs/core/encryption"; + +const encryptionConfig = defineConfig({ + /** + * Default encryption driver used by the application. + */ + default: "gcm", + + list: { + gcm: drivers.aes256gcm({ + /** + * Keys used for encryption/decryption. + * First key encrypts, all keys are tried for decryption. + */ + keys: [rootEnv.get("KEY")], + + /** + * Stable identifier for this driver. + */ + id: "gcm", + }), + }, +}); + +export default encryptionConfig; + +/** + * Inferring types for the list of encryptors you have configured + * in your application. + */ +declare module "@adonisjs/core/types" { + export interface EncryptorsList extends InferEncryptors {} +} diff --git a/portal/config/hash.ts b/portal/config/hash.ts new file mode 100644 index 000000000..87fd78670 --- /dev/null +++ b/portal/config/hash.ts @@ -0,0 +1,75 @@ +import { defineConfig, drivers } from "@adonisjs/core/hash"; + +/** + * Hashing configuration. + * + * This starter uses Node.js scrypt under the hood. + * Node.js reference: https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback + */ +const hashConfig = defineConfig({ + /** + * Default hasher used by the application. + */ + default: "scrypt", + + list: { + /** + * Scrypt is memory-hard, which makes brute-force attacks more expensive. + */ + scrypt: drivers.scrypt({ + /** + * Work factor (Node alias: N / cost). + * Higher values increase security and CPU+memory usage. + * + * Tuning guideline: + * - Start with 16384. + * - Increase gradually (for example 32768) and benchmark login/signup latency. + * - Keep values practical for your slowest production machine. + * + * Node constraint: value must be a power of two greater than 1. + */ + cost: 16384, + + /** + * Block size (Node alias: r / blockSize). + * Increases memory and CPU linearly. + * + * Tuning guideline: + * - Keep 8 unless you have a measured reason to change it. + * - Raise only with benchmark data, because memory usage grows quickly. + */ + blockSize: 8, + + /** + * Parallelization (Node alias: p / parallelization). + * Controls how many independent computations are performed. + * + * Tuning guideline: + * - Keep 1 for most applications. + * - Increase only after load testing if your infrastructure benefits from it. + */ + parallelization: 1, + + /** + * Maximum memory limit in bytes (Node alias: maxmem / maxMemory). + * Hashing throws if the estimated memory usage is above this limit. + * Node documents the check as approximately: 128 * N * r > maxmem. + * + * Tuning guideline: + * - Keep this aligned with your cost/blockSize choices. + * - Increase carefully on memory-constrained environments. + */ + maxMemory: 33554432, + }), + }, +}); + +export default hashConfig; + +/** + * Inferring types for the list of hashers you have configured + * in your application. + */ +declare module "@adonisjs/core/types" { + export interface HashersList extends InferHashers {} +} diff --git a/portal/config/inertia.ts b/portal/config/inertia.ts new file mode 100644 index 000000000..c4f91fef6 --- /dev/null +++ b/portal/config/inertia.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "@adonisjs/inertia"; + +const inertiaConfig = defineConfig({ + /** + * Server-side rendering options. + */ + ssr: { + /** + * Toggle SSR mode for Inertia pages. + */ + enabled: false, + + /** + * Entry file used by the SSR server build. + */ + entrypoint: "inertia/ssr.ts", + }, +}); + +export default inertiaConfig; diff --git a/portal/config/limiter.ts b/portal/config/limiter.ts new file mode 100644 index 000000000..5d1a72d84 --- /dev/null +++ b/portal/config/limiter.ts @@ -0,0 +1,19 @@ +import { portalEnv } from "#start/env"; +import { defineConfig, stores } from "@adonisjs/limiter"; + +const limiterConfig = defineConfig({ + default: portalEnv.get("LIMITER_STORE", "redis"), + stores: { + redis: stores.redis({ + keyPrefix: "portal:limiter:", + }), + + memory: stores.memory({}), + }, +}); + +export default limiterConfig; + +declare module "@adonisjs/limiter/types" { + export interface LimitersList extends InferLimiters {} +} diff --git a/portal/config/logger.ts b/portal/config/logger.ts new file mode 100644 index 000000000..edd3b8ecd --- /dev/null +++ b/portal/config/logger.ts @@ -0,0 +1,50 @@ +import { portalEnv } from "#start/env"; +import app from "@adonisjs/core/services/app"; +import { defineConfig, targets } from "@adonisjs/core/logger"; + +const loggerConfig = defineConfig({ + /** + * Default logger name used by ctx.logger and app logger calls. + */ + default: "app", + + loggers: { + app: { + /** + * Toggle this logger on/off. + */ + enabled: true, + + /** + * Logger name shown in log records. + */ + name: "zeppelin-portal", + + /** + * Minimum level to output (trace, debug, info, warn, error, fatal). + */ + level: portalEnv.get("LOG_LEVEL", "info"), + + /** + * Configure where logs are written. + * Pretty logs in development, stdout in production. + */ + transport: { + targets: targets() + .pushIf(!app.inProduction, targets.pretty()) + .pushIf(app.inProduction, targets.file({ destination: 1 })) + .toArray(), + }, + }, + }, +}); + +export default loggerConfig; + +/** + * Inferring types for the list of loggers you have configured + * in your application. + */ +declare module "@adonisjs/core/types" { + export interface LoggersList extends InferLoggers {} +} diff --git a/portal/config/redis.ts b/portal/config/redis.ts new file mode 100644 index 000000000..7e8cbdf50 --- /dev/null +++ b/portal/config/redis.ts @@ -0,0 +1,26 @@ +import { rootEnv } from "#start/env"; +import { defineConfig } from "@adonisjs/redis"; +import type { InferConnections } from "@adonisjs/redis/types"; + +const url = new URL(rootEnv.get("REDIS_URL", "redis://redis:6379")); + +const redisConfig = defineConfig({ + connection: "main", + connections: { + main: { + host: url.hostname, + port: url.port ? Number(url.port) : 6379, + username: decodeURIComponent(url.username), + password: decodeURIComponent(url.password), + db: url.pathname !== "/" && url.pathname ? Number(url.pathname.slice(1)) : 0, + ...(url.protocol === "rediss:" ? { tls: {} } : {}), + keyPrefix: "portal:", + }, + }, +}); + +export default redisConfig; + +declare module "@adonisjs/redis/types" { + interface RedisConnections extends InferConnections {} +} diff --git a/portal/config/session.ts b/portal/config/session.ts new file mode 100644 index 000000000..5678e6ba3 --- /dev/null +++ b/portal/config/session.ts @@ -0,0 +1,72 @@ +import { portalEnv } from "#start/env"; +import { defineConfig, stores } from "@adonisjs/session"; + +const sessionConfig = defineConfig({ + /** + * Enable or disable session support globally. + */ + enabled: true, + + /** + * Cookie name storing the session identifier. + */ + cookieName: "portalSession", + + /** + * When set to true, the session id cookie will be deleted + * once the user closes the browser. + */ + clearWithBrowser: true, + + /** + * Define how long to keep the session data alive without + * any activity. + */ + age: "2h", + + /** + * Configuration for session cookie and the + * cookie store. + */ + cookie: { + /** + * Restrict the cookie to a URL path. '/' means all routes. + */ + path: "/", + + /** + * Prevent JavaScript access to the cookie in the browser. + */ + httpOnly: true, + + /** + * Send cookies only over HTTPS in production. + */ + secure: true, + + /** + * Cross-site policy for cookie sending. + */ + // Allow the session cookie on the top-level OAuth callback from Discord. + sameSite: "lax", + }, + + /** + * The store to use. Make sure to validate the environment + * variable in order to infer the store name without any + * errors. + */ + store: portalEnv.get("SESSION_DRIVER", "redis"), + + /** + * List of configured stores. Refer documentation to see + * list of available stores and their config. + */ + stores: { + redis: stores.redis({ + connection: "main", + }), + }, +}); + +export default sessionConfig; diff --git a/portal/config/shield.ts b/portal/config/shield.ts new file mode 100644 index 000000000..3d30d92cd --- /dev/null +++ b/portal/config/shield.ts @@ -0,0 +1,95 @@ +import { defineConfig } from "@adonisjs/shield"; + +const shieldConfig = defineConfig({ + /** + * Configure CSP policies for your app. Refer documentation + * to learn more. + */ + csp: { + /** + * Enable the Content-Security-Policy header. + */ + enabled: false, + + /** + * Per-resource CSP directives. + */ + directives: {}, + + /** + * Report violations without blocking resources. + */ + reportOnly: false, + }, + + /** + * Configure CSRF protection options. Refer documentation + * to learn more. + */ + csrf: { + /** + * Enable CSRF token verification for state-changing requests. + */ + enabled: true, + + /** + * Route patterns to exclude from CSRF checks. + * Useful for external webhooks or API endpoints. + */ + exceptRoutes: [], + + /** + * Expose an encrypted XSRF-TOKEN cookie for frontend HTTP clients. + */ + enableXsrfCookie: true, + + /** + * HTTP methods protected by CSRF validation. + */ + methods: ["POST", "PUT", "PATCH", "DELETE"], + }, + + /** + * Control how your website should be embedded inside + * iframes. + */ + xFrame: { + /** + * Enable the X-Frame-Options header. + */ + enabled: true, + + /** + * Block all framing attempts. Default value is DENY. + */ + action: "DENY", + }, + + /** + * Force browser to always use HTTPS. + */ + hsts: { + /** + * Enable the Strict-Transport-Security header. + */ + enabled: true, + + /** + * HSTS policy duration remembered by browsers. + */ + maxAge: "180 days", + }, + + /** + * Disable browsers from sniffing content types and rely only + * on the response content-type header. + */ + contentTypeSniffing: { + /** + * Enable X-Content-Type-Options: nosniff. + */ + enabled: true, + }, +}); + +export default shieldConfig; diff --git a/portal/config/static.ts b/portal/config/static.ts new file mode 100644 index 000000000..5fd46835c --- /dev/null +++ b/portal/config/static.ts @@ -0,0 +1,32 @@ +import { defineConfig } from "@adonisjs/static"; + +/** + * Configuration options to tweak the static files middleware. + * The complete set of options are documented on the + * official documentation website. + * + * https://docs.adonisjs.com/guides/basics/static-file-server + */ +const staticServerConfig = defineConfig({ + /** + * Enable or disable static file serving middleware. + */ + enabled: true, + + /** + * Generate ETag headers for client/proxy caching. + */ + etag: true, + + /** + * Include Last-Modified headers for conditional requests. + */ + lastModified: true, + + /** + * Policy for files starting with a dot. + */ + dotFiles: "ignore", +}); + +export default staticServerConfig; diff --git a/portal/config/vite.ts b/portal/config/vite.ts new file mode 100644 index 000000000..62ea2fbd1 --- /dev/null +++ b/portal/config/vite.ts @@ -0,0 +1,34 @@ +import { defineConfig } from "@adonisjs/vite"; + +const viteBackendConfig = defineConfig({ + /** + * The output of vite will be written inside this + * directory. The path should be relative from + * the application root. + */ + buildDirectory: "public/assets", + + /** + * The path to the manifest file generated by the + * "vite build" command. + */ + manifestFile: "public/assets/.vite/manifest.json", + + /** + * Feel free to change the value of the "assetsUrl" to + * point to a CDN in production. + */ + assetsUrl: "/assets", + + /** + * HTML attributes added to generated script tags. + */ + scriptAttributes: { + /** + * Execute scripts after HTML parsing is complete. + */ + defer: true, + }, +}); + +export default viteBackendConfig; diff --git a/portal/database/migrations/.gitkeep b/portal/database/migrations/.gitkeep new file mode 100644 index 000000000..d52e26635 --- /dev/null +++ b/portal/database/migrations/.gitkeep @@ -0,0 +1,3 @@ +# We don't currently use Adonis's migrations at all. +# All migrations are handled by the /backend project instead. +# schema.ts is generated based on database inspection. diff --git a/portal/database/schema.ts b/portal/database/schema.ts new file mode 100644 index 000000000..c667102f7 --- /dev/null +++ b/portal/database/schema.ts @@ -0,0 +1,771 @@ +/** + * This file is automatically generated + * DO NOT EDIT manually + * Run "node ace migration:run" command to re-generate this file + */ + +import { BaseModel, column } from "@adonisjs/lucid/orm"; +import { DateTime } from "luxon"; + +export class AllowedGuildSchema extends BaseModel { + static $columns = ["createdAt", "icon", "id", "name", "ownerId", "updatedAt"] as const; + $columns = AllowedGuildSchema.$columns; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare icon: string | null; + @column({ isPrimary: true }) + declare id: string; + @column() + declare name: string; + @column() + declare ownerId: string; + @column.dateTime({ autoCreate: true, autoUpdate: true }) + declare updatedAt: DateTime; +} + +export class AntiraidLevelSchema extends BaseModel { + static $columns = ["guildId", "level"] as const; + $columns = AntiraidLevelSchema.$columns; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare level: string; +} + +export class ApiAuditLogSchema extends BaseModel { + static $columns = ["authorId", "createdAt", "eventData", "eventType", "guildId", "id"] as const; + $columns = ApiAuditLogSchema.$columns; + @column() + declare authorId: string; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare eventData: string; + @column() + declare eventType: string; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; +} + +export class ApiLoginSchema extends BaseModel { + static $columns = ["expiresAt", "id", "loggedInAt", "token", "userId"] as const; + $columns = ApiLoginSchema.$columns; + @column.dateTime() + declare expiresAt: DateTime; + @column({ isPrimary: true }) + declare id: string; + @column.dateTime() + declare loggedInAt: DateTime; + @column() + declare token: string; + @column() + declare userId: string; +} + +export class ApiPermissionSchema extends BaseModel { + static $columns = ["expiresAt", "guildId", "permissions", "targetId", "type"] as const; + $columns = ApiPermissionSchema.$columns; + @column.dateTime() + declare expiresAt: DateTime | null; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare permissions: string; + @column() + declare targetId: string; + @column() + declare type: string; +} + +export class ApiUserInfoSchema extends BaseModel { + static $columns = ["data", "id", "updatedAt"] as const; + $columns = ApiUserInfoSchema.$columns; + @column() + declare data: string; + @column({ isPrimary: true }) + declare id: string; + @column.dateTime({ autoCreate: true, autoUpdate: true }) + declare updatedAt: DateTime; +} + +export class ArchiveSchema extends BaseModel { + static $columns = ["body", "createdAt", "expiresAt", "guildId", "id"] as const; + $columns = ArchiveSchema.$columns; + @column() + declare body: string; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column.dateTime() + declare expiresAt: DateTime | null; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: string; +} + +export class AutoReactionSchema extends BaseModel { + static $columns = ["channelId", "guildId", "reactions"] as const; + $columns = AutoReactionSchema.$columns; + @column() + declare channelId: string; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare reactions: string; +} + +export class CaseNoteSchema extends BaseModel { + static $columns = ["body", "caseId", "createdAt", "id", "modId", "modName"] as const; + $columns = CaseNoteSchema.$columns; + @column() + declare body: string; + @column() + declare caseId: number; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column({ isPrimary: true }) + declare id: number; + @column() + declare modId: string | null; + @column() + declare modName: string | null; +} + +export class CaseSchema extends BaseModel { + static $columns = [ + "auditLogId", + "caseNumber", + "createdAt", + "guildId", + "id", + "isHidden", + "logMessageId", + "modId", + "modName", + "ppId", + "ppName", + "type", + "userId", + "userName", + ] as const; + $columns = CaseSchema.$columns; + @column() + declare auditLogId: string | null; + @column() + declare caseNumber: number; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare isHidden: boolean; + @column() + declare logMessageId: string | null; + @column() + declare modId: string | null; + @column() + declare modName: string | null; + @column() + declare ppId: string | null; + @column() + declare ppName: string | null; + @column() + declare type: number; + @column() + declare userId: string; + @column() + declare userName: string; +} + +export class ConfigSchema extends BaseModel { + static $columns = ["config", "editedAt", "editedBy", "id", "isActive", "key"] as const; + $columns = ConfigSchema.$columns; + @column() + declare config: string; + @column.dateTime() + declare editedAt: DateTime; + @column() + declare editedBy: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare isActive: boolean; + @column() + declare key: string; +} + +export class ContextMenuSchema extends BaseModel { + static $columns = ["actionName", "contextId", "guildId"] as const; + $columns = ContextMenuSchema.$columns; + @column() + declare actionName: string; + @column({ isPrimary: true }) + declare contextId: string; + @column() + declare guildId: string; +} + +export class CounterTriggerStateSchema extends BaseModel { + static $columns = ["channelId", "id", "triggerId", "userId"] as const; + $columns = CounterTriggerStateSchema.$columns; + @column() + declare channelId: string; + @column({ isPrimary: true }) + declare id: string; + @column() + declare triggerId: number; + @column() + declare userId: string; +} + +export class CounterTriggerSchema extends BaseModel { + static $columns = [ + "comparisonOp", + "comparisonValue", + "counterId", + "deleteAt", + "id", + "name", + "reverseComparisonOp", + "reverseComparisonValue", + ] as const; + $columns = CounterTriggerSchema.$columns; + @column() + declare comparisonOp: string; + @column() + declare comparisonValue: number; + @column() + declare counterId: number; + @column.dateTime() + declare deleteAt: DateTime | null; + @column({ isPrimary: true }) + declare id: number; + @column() + declare name: string; + @column() + declare reverseComparisonOp: string; + @column() + declare reverseComparisonValue: number; +} + +export class CounterValueSchema extends BaseModel { + static $columns = ["channelId", "counterId", "id", "userId", "value"] as const; + $columns = CounterValueSchema.$columns; + @column() + declare channelId: string; + @column() + declare counterId: number; + @column({ isPrimary: true }) + declare id: string; + @column() + declare userId: string; + @column() + declare value: number; +} + +export class CounterSchema extends BaseModel { + static $columns = ["deleteAt", "guildId", "id", "lastDecayAt", "name", "perChannel", "perUser"] as const; + $columns = CounterSchema.$columns; + @column.dateTime() + declare deleteAt: DateTime | null; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column.dateTime() + declare lastDecayAt: DateTime; + @column() + declare name: string; + @column() + declare perChannel: boolean; + @column() + declare perUser: boolean; +} + +export class MemberCacheSchema extends BaseModel { + static $columns = ["deleteAt", "guildId", "id", "lastSeen", "nickname", "roles", "userId", "username"] as const; + $columns = MemberCacheSchema.$columns; + @column.dateTime() + declare deleteAt: DateTime | null; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column.date() + declare lastSeen: DateTime; + @column() + declare nickname: string | null; + @column() + declare roles: string; + @column() + declare userId: string; + @column() + declare username: string; +} + +export class MemberTimezoneSchema extends BaseModel { + static $columns = ["guildId", "memberId", "timezone"] as const; + $columns = MemberTimezoneSchema.$columns; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare memberId: string; + @column() + declare timezone: string; +} + +export class MessageSchema extends BaseModel { + static $columns = [ + "channelId", + "data", + "deletedAt", + "guildId", + "id", + "isBot", + "isPermanent", + "postedAt", + "userId", + ] as const; + $columns = MessageSchema.$columns; + @column() + declare channelId: string; + @column() + declare data: string; + @column.dateTime() + declare deletedAt: DateTime | null; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: string; + @column() + declare isBot: boolean; + @column() + declare isPermanent: boolean; + @column.dateTime() + declare postedAt: DateTime; + @column() + declare userId: string; +} + +export class MuteSchema extends BaseModel { + static $columns = [ + "caseId", + "createdAt", + "expiresAt", + "guildId", + "muteRole", + "rolesToRestore", + "timeoutExpiresAt", + "type", + "userId", + ] as const; + $columns = MuteSchema.$columns; + @column() + declare caseId: number | null; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime | null; + @column.dateTime() + declare expiresAt: DateTime | null; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare muteRole: string | null; + @column() + declare rolesToRestore: string | null; + @column.dateTime() + declare timeoutExpiresAt: DateTime | null; + @column() + declare type: boolean; + @column() + declare userId: string; +} + +export class NicknameHistorySchema extends BaseModel { + static $columns = ["guildId", "id", "nickname", "timestamp", "userId"] as const; + $columns = NicknameHistorySchema.$columns; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare nickname: string | null; + @column.dateTime() + declare timestamp: DateTime; + @column() + declare userId: string; +} + +export class PersistedDatumSchema extends BaseModel { + static $columns = ["guildId", "isVoiceMuted", "nickname", "roles", "userId"] as const; + $columns = PersistedDatumSchema.$columns; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare isVoiceMuted: number; + @column() + declare nickname: string | null; + @column() + declare roles: string | null; + @column() + declare userId: string; +} + +export class PhishermanCacheSchema extends BaseModel { + static $columns = ["data", "domain", "expiresAt", "id"] as const; + $columns = PhishermanCacheSchema.$columns; + @column() + declare data: string; + @column() + declare domain: string; + @column.dateTime() + declare expiresAt: DateTime; + @column({ isPrimary: true }) + declare id: number; +} + +export class PhishermanKeyCacheSchema extends BaseModel { + static $columns = ["expiresAt", "hash", "id", "isValid"] as const; + $columns = PhishermanKeyCacheSchema.$columns; + @column.dateTime() + declare expiresAt: DateTime; + @column() + declare hash: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare isValid: boolean; +} + +export class PingableRoleSchema extends BaseModel { + static $columns = ["channelId", "guildId", "id", "roleId"] as const; + $columns = PingableRoleSchema.$columns; + @column() + declare channelId: string; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare roleId: string; +} + +export class PortalUserSchema extends BaseModel { + static $columns = ["createdAt", "discordAvatarUrl", "discordUserId", "discordUsername", "id", "lastLoginAt"] as const; + $columns = PortalUserSchema.$columns; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare discordAvatarUrl: string | null; + @column() + declare discordUserId: string; + @column() + declare discordUsername: string; + @column({ isPrimary: true }) + declare id: number; + @column.dateTime() + declare lastLoginAt: DateTime; +} + +export class ReactionRoleSchema extends BaseModel { + static $columns = ["channelId", "emoji", "guildId", "isExclusive", "messageId", "order", "roleId"] as const; + $columns = ReactionRoleSchema.$columns; + @column() + declare channelId: string; + @column() + declare emoji: string; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare isExclusive: boolean; + @column() + declare messageId: string; + @column() + declare order: number | null; + @column() + declare roleId: string; +} + +export class ReminderSchema extends BaseModel { + static $columns = ["body", "channelId", "createdAt", "guildId", "id", "remindAt", "userId"] as const; + $columns = ReminderSchema.$columns; + @column() + declare body: string; + @column() + declare channelId: string; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column.dateTime() + declare remindAt: DateTime; + @column() + declare userId: string; +} + +export class RoleButtonSchema extends BaseModel { + static $columns = ["channelId", "guildId", "hash", "id", "messageId", "name"] as const; + $columns = RoleButtonSchema.$columns; + @column() + declare channelId: string; + @column() + declare guildId: string; + @column() + declare hash: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare messageId: string; + @column() + declare name: string; +} + +export class RoleQueueSchema extends BaseModel { + static $columns = ["guildId", "id", "priority", "roleId", "shouldAdd", "userId"] as const; + $columns = RoleQueueSchema.$columns; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare priority: number; + @column() + declare roleId: string; + @column() + declare shouldAdd: boolean; + @column() + declare userId: string; +} + +export class ScheduledPostSchema extends BaseModel { + static $columns = [ + "attachments", + "authorId", + "authorName", + "channelId", + "content", + "enableMentions", + "guildId", + "id", + "postAt", + "repeatInterval", + "repeatTimes", + "repeatUntil", + ] as const; + $columns = ScheduledPostSchema.$columns; + @column() + declare attachments: string; + @column() + declare authorId: string; + @column() + declare authorName: string; + @column() + declare channelId: string; + @column() + declare content: string; + @column() + declare enableMentions: boolean; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column.dateTime() + declare postAt: DateTime; + @column() + declare repeatInterval: number | null; + @column() + declare repeatTimes: number | null; + @column.dateTime() + declare repeatUntil: DateTime | null; +} + +export class SelfGrantableRoleSchema extends BaseModel { + static $columns = ["aliases", "channelId", "guildId", "id", "roleId"] as const; + $columns = SelfGrantableRoleSchema.$columns; + @column() + declare aliases: string; + @column() + declare channelId: string; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare roleId: string; +} + +export class SlowmodeChannelSchema extends BaseModel { + static $columns = ["channelId", "guildId", "slowmodeSeconds"] as const; + $columns = SlowmodeChannelSchema.$columns; + @column() + declare channelId: string; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare slowmodeSeconds: number; +} + +export class SlowmodeUserSchema extends BaseModel { + static $columns = ["channelId", "expiresAt", "guildId", "userId"] as const; + $columns = SlowmodeUserSchema.$columns; + @column() + declare channelId: string; + @column.dateTime() + declare expiresAt: DateTime; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare userId: string; +} + +export class StarboardMessageSchema extends BaseModel { + static $columns = ["guildId", "messageId", "starboardChannelId", "starboardMessageId"] as const; + $columns = StarboardMessageSchema.$columns; + @column() + declare guildId: string; + @column() + declare messageId: string; + @column() + declare starboardChannelId: string; + @column({ isPrimary: true }) + declare starboardMessageId: string; +} + +export class StarboardReactionSchema extends BaseModel { + static $columns = ["guildId", "id", "messageId", "reactorId"] as const; + $columns = StarboardReactionSchema.$columns; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare messageId: string; + @column() + declare reactorId: string; +} + +export class StatSchema extends BaseModel { + static $columns = ["createdAt", "guildId", "id", "key", "source", "value"] as const; + $columns = StatSchema.$columns; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: string; + @column() + declare key: string; + @column() + declare source: string; + @column() + declare value: number; +} + +export class SupporterSchema extends BaseModel { + static $columns = ["amount", "name", "userId"] as const; + $columns = SupporterSchema.$columns; + @column() + declare amount: string | null; + @column() + declare name: string; + @column({ isPrimary: true }) + declare userId: string; +} + +export class TagResponseSchema extends BaseModel { + static $columns = ["commandMessageId", "guildId", "id", "responseMessageId"] as const; + $columns = TagResponseSchema.$columns; + @column() + declare commandMessageId: string; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare responseMessageId: string; +} + +export class TagSchema extends BaseModel { + static $columns = ["body", "createdAt", "guildId", "tag", "userId"] as const; + $columns = TagSchema.$columns; + @column() + declare body: string; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime | null; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare tag: string; + @column() + declare userId: string; +} + +export class TempbanSchema extends BaseModel { + static $columns = ["createdAt", "expiresAt", "guildId", "modId", "userId"] as const; + $columns = TempbanSchema.$columns; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column.dateTime() + declare expiresAt: DateTime; + @column({ isPrimary: true }) + declare guildId: string; + @column() + declare modId: string; + @column() + declare userId: string; +} + +export class UsernameHistorySchema extends BaseModel { + static $columns = ["id", "timestamp", "userId", "username"] as const; + $columns = UsernameHistorySchema.$columns; + @column({ isPrimary: true }) + declare id: number; + @column.dateTime() + declare timestamp: DateTime; + @column() + declare userId: string; + @column() + declare username: string | null; +} + +export class VcAlertSchema extends BaseModel { + static $columns = ["active", "body", "channelId", "expiresAt", "guildId", "id", "requestorId", "userId"] as const; + $columns = VcAlertSchema.$columns; + @column() + declare active: boolean; + @column() + declare body: string; + @column() + declare channelId: string; + @column.dateTime() + declare expiresAt: DateTime; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: number; + @column() + declare requestorId: string; + @column() + declare userId: string; +} + +export class WebhookSchema extends BaseModel { + static $columns = ["channelId", "createdAt", "guildId", "id", "token"] as const; + $columns = WebhookSchema.$columns; + @column() + declare channelId: string; + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime; + @column() + declare guildId: string; + @column({ isPrimary: true }) + declare id: string; + @column() + declare token: string; +} diff --git a/portal/database/schemaRules.ts b/portal/database/schemaRules.ts new file mode 100644 index 000000000..44745c207 --- /dev/null +++ b/portal/database/schemaRules.ts @@ -0,0 +1,40 @@ +import { DatabaseColumn, type SchemaRules } from "@adonisjs/lucid/types/schema_generator"; + +export default { + types: { + // We have supportBigNumbers + bigNumberStrings enabled in database.ts, so use "string" for bigints + // Note: Does not work for primary keys (Lucid's primary key rules override this). See separate primaryKey rule below. + bigint: { + tsType: "string", + decorators: [{ name: "@column" }], + }, + }, + + // Override Lucid's primary key rule so bigints are correctly typed as "string" with supportBigNumbers + bigNumberStrings + primaryKey: (_tableName: string, primaryKeys: string[], columns: Record) => { + const columnName = primaryKeys[0]; + if (!columnName || !columns[columnName]) { + return undefined; + } + + const column = columns[columnName]; + let tsType: string; + if (/^bigint\b/.test(column.type)) { + tsType = "string"; + } else if (/^(tinyint|smallint|mediumint|int|integer)\b/.test(column.type)) { + tsType = "number"; + } else if (/^(char|varchar|uuid)\b/.test(column.type)) { + tsType = "string"; + } else { + throw new Error(`Unsupported primary key type: ${column.type}`); + } + + return { + columnName, + columnInfo: { + tsType, + decorators: [{ name: "@column", args: { isPrimary: true } }], + }, + }; + }, +} satisfies SchemaRules; diff --git a/portal/hooks/devHmrPort.ts b/portal/hooks/devHmrPort.ts new file mode 100644 index 000000000..efd47e421 --- /dev/null +++ b/portal/hooks/devHmrPort.ts @@ -0,0 +1,10 @@ +import { hooks } from "@adonisjs/core/app"; + +// AdonisJS internals override VITE_HMR_PORT env var. +// This overrides that override (yo dawg) with our own value. +export default hooks.devServerStarting((server) => { + server.options.env = { + ...server.options.env, + VITE_HMR_PORT: "3004", + }; +}); diff --git a/portal/hooks/indexInertiaPages.ts b/portal/hooks/indexInertiaPages.ts new file mode 100644 index 000000000..4a51a2e6a --- /dev/null +++ b/portal/hooks/indexInertiaPages.ts @@ -0,0 +1,41 @@ +import { hooks } from "@adonisjs/core/app"; + +/** + * Custom hook to load inertia pages from feature folders, e.g. `features/docs/pages/DocsIndex.vue` + */ +export default hooks.init((_parent, _manager, generator) => { + generator.add("inertiaPages", { + source: "./inertia", + glob: ["**/pages/*.vue"], + output: "./.adonisjs/server/pages.d.ts", + + as(vfs, buffer, _config, helpers) { + const pages = vfs.asList(); + + buffer.writeLine(`import '@adonisjs/inertia/types'`); + buffer.writeLine(` + import type { + VNodeProps, + AllowedComponentProps, + ComponentInstance + } from 'vue' + + type ExtractProps = Omit< + ComponentInstance['$props'], + keyof VNodeProps | keyof AllowedComponentProps + > + `); + + buffer.writeLine(`declare module '@adonisjs/inertia/types' {`).indent(); + + buffer.writeLine(`export interface InertiaPages {`).indent(); + + for (const [name, file] of Object.entries(pages)) { + buffer.writeLine(`'${name}': ExtractProps<(typeof import('${helpers.toImportPath(file)}'))['default']>`); + } + + buffer.dedent().writeLine("}"); + buffer.dedent().writeLine("}"); + }, + }); +}); diff --git a/portal/inertia/app.ts b/portal/inertia/app.ts new file mode 100644 index 000000000..79e55b5c6 --- /dev/null +++ b/portal/inertia/app.ts @@ -0,0 +1,26 @@ +import "@fontsource-variable/recursive"; +import "@fontsource-variable/playpen-sans"; +import "./css/global.css"; +import "vue-sonner/style.css"; +import { client } from "#frontend/client.js"; +import { createInertiaApp } from "@inertiajs/vue3"; +import { TuyauProvider } from "@adonisjs/inertia/vue"; +import { createApp, type DefineComponent, h } from "vue"; +import { resolvePageComponent } from "@adonisjs/inertia/helpers"; + +const appName = import.meta.env.VITE_APP_NAME || "Zeppelin"; + +createInertiaApp({ + title: (title) => (title ? `${title} - ${appName}` : appName), + resolve: (name) => { + return resolvePageComponent(`./${name}.vue`, import.meta.glob("./**/pages/*.vue")); + }, + setup({ el, App, props, plugin }) { + createApp({ render: () => h(TuyauProvider, { client }, { default: () => h(App, props) }) }) + .use(plugin) + .mount(el); + }, + progress: { + color: "#4B5563", + }, +}); diff --git a/portal/inertia/assets/charcoal-noise.webp b/portal/inertia/assets/charcoal-noise.webp new file mode 100644 index 000000000..a2d456d30 Binary files /dev/null and b/portal/inertia/assets/charcoal-noise.webp differ diff --git a/portal/inertia/assets/grid-16x16.png b/portal/inertia/assets/grid-16x16.png new file mode 100644 index 000000000..6719d4167 Binary files /dev/null and b/portal/inertia/assets/grid-16x16.png differ diff --git a/portal/inertia/assets/grid-64x64.png b/portal/inertia/assets/grid-64x64.png new file mode 100644 index 000000000..7565da5a9 Binary files /dev/null and b/portal/inertia/assets/grid-64x64.png differ diff --git a/portal/inertia/assets/grid-8x8.png b/portal/inertia/assets/grid-8x8.png new file mode 100644 index 000000000..52bb25589 Binary files /dev/null and b/portal/inertia/assets/grid-8x8.png differ diff --git a/portal/inertia/assets/logo.svg b/portal/inertia/assets/logo.svg new file mode 100644 index 000000000..601eb5716 --- /dev/null +++ b/portal/inertia/assets/logo.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/portal/inertia/assets/paper-texture.jpg b/portal/inertia/assets/paper-texture.jpg new file mode 100644 index 000000000..c0ebc7eec Binary files /dev/null and b/portal/inertia/assets/paper-texture.jpg differ diff --git a/portal/inertia/assets/squiggle.svg b/portal/inertia/assets/squiggle.svg new file mode 100644 index 000000000..55016b8af --- /dev/null +++ b/portal/inertia/assets/squiggle.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/portal/inertia/client.ts b/portal/inertia/client.ts new file mode 100644 index 000000000..fdc500f34 --- /dev/null +++ b/portal/inertia/client.ts @@ -0,0 +1,9 @@ +import { registry } from "#client/registry/index.js"; +import { createTuyau } from "@tuyau/core/client"; + +export const client = createTuyau({ + baseUrl: "/", + registry, +}); + +export const urlFor = client.urlFor; diff --git a/portal/inertia/components/BasicButton.vue b/portal/inertia/components/BasicButton.vue new file mode 100644 index 000000000..100b921af --- /dev/null +++ b/portal/inertia/components/BasicButton.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/portal/inertia/components/BasicLink.vue b/portal/inertia/components/BasicLink.vue new file mode 100644 index 000000000..3584bc9c6 --- /dev/null +++ b/portal/inertia/components/BasicLink.vue @@ -0,0 +1,13 @@ + + + diff --git a/portal/inertia/components/BasicTab.vue b/portal/inertia/components/BasicTab.vue new file mode 100644 index 000000000..b7cecfe64 --- /dev/null +++ b/portal/inertia/components/BasicTab.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/portal/inertia/components/DefaultH1.vue b/portal/inertia/components/DefaultH1.vue new file mode 100644 index 000000000..afed5707d --- /dev/null +++ b/portal/inertia/components/DefaultH1.vue @@ -0,0 +1,15 @@ + + + diff --git a/portal/inertia/components/MainMenuItem.vue b/portal/inertia/components/MainMenuItem.vue new file mode 100644 index 000000000..ffd87bcb2 --- /dev/null +++ b/portal/inertia/components/MainMenuItem.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/portal/inertia/components/PageHeader.vue b/portal/inertia/components/PageHeader.vue new file mode 100644 index 000000000..b3a36e612 --- /dev/null +++ b/portal/inertia/components/PageHeader.vue @@ -0,0 +1,32 @@ + + + diff --git a/portal/inertia/components/SidebarPaper.vue b/portal/inertia/components/SidebarPaper.vue new file mode 100644 index 000000000..30a7f5c4c --- /dev/null +++ b/portal/inertia/components/SidebarPaper.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/portal/inertia/components/Squiggle.vue b/portal/inertia/components/Squiggle.vue new file mode 100644 index 000000000..33f8b6712 --- /dev/null +++ b/portal/inertia/components/Squiggle.vue @@ -0,0 +1,14 @@ + + + diff --git a/portal/inertia/css/global.css b/portal/inertia/css/global.css new file mode 100644 index 000000000..a8b579a47 --- /dev/null +++ b/portal/inertia/css/global.css @@ -0,0 +1,125 @@ +:root { + --color-blue-50: rgb(193, 245, 255); + --color-blue-100: rgb(178, 231, 255); + --color-blue-200: rgb(149, 203, 255); + --color-blue-300: rgb(121, 175, 234); + --color-blue-400: rgb(92, 149, 206); + --color-blue-500: rgb(62, 123, 178); + --color-blue-600: rgb(26, 98, 151); + --color-blue-700: rgb(0, 75, 125); + --color-blue-800: rgb(0, 52, 100); + --color-blue-900: rgb(0, 32, 76); + --color-blue-950: rgb(0, 22, 64); + --color-steelblue-50: rgb(210, 243, 255); + --color-steelblue-100: rgb(196, 229, 255); + --color-steelblue-200: rgb(168, 201, 245); + --color-steelblue-300: rgb(141, 174, 216); + --color-steelblue-400: rgb(114, 147, 188); + --color-steelblue-500: rgb(88, 121, 161); + --color-steelblue-600: rgb(62, 97, 135); + --color-steelblue-700: rgb(34, 73, 109); + --color-steelblue-800: rgb(0, 51, 85); + --color-steelblue-900: rgb(0, 30, 61); + --color-steelblue-950: rgb(0, 20, 50); + --color-green-50: rgb(164, 255, 127); + --color-green-100: rgb(149, 251, 113); + --color-green-200: rgb(120, 222, 86); + --color-green-300: rgb(90, 193, 59); + --color-green-400: rgb(59, 166, 29); + --color-green-500: rgb(17, 139, 0); + --color-green-600: rgb(0, 112, 0); + --color-green-700: rgb(0, 87, 0); + --color-green-800: rgb(0, 62, 0); + --color-green-900: rgb(0, 41, 0); + --color-green-950: rgb(0, 35, 0); + --color-yellow-50: rgb(255, 238, 63); + --color-yellow-100: rgb(255, 224, 45); + --color-yellow-200: rgb(231, 197, 0); + --color-yellow-300: rgb(200, 170, 0); + --color-yellow-400: rgb(170, 143, 0); + --color-yellow-500: rgb(141, 118, 0); + --color-yellow-600: rgb(113, 94, 0); + --color-yellow-700: rgb(88, 70, 0); + --color-yellow-800: rgb(68, 47, 0); + --color-yellow-900: rgb(55, 25, 0); + --color-yellow-950: rgb(50, 12, 0); + --color-orange-50: rgb(255, 210, 101); + --color-orange-100: rgb(255, 196, 87); + --color-orange-200: rgb(255, 168, 60); + --color-orange-300: rgb(255, 141, 28); + --color-orange-400: rgb(224, 115, 0); + --color-orange-500: rgb(193, 90, 0); + --color-orange-600: rgb(162, 64, 0); + --color-orange-700: rgb(132, 39, 0); + --color-orange-800: rgb(105, 9, 0); + --color-orange-900: rgb(81, 0, 0); + --color-orange-950: rgb(72, 0, 0); + --color-red-50: rgb(255, 178, 120); + --color-red-100: rgb(255, 164, 107); + --color-red-200: rgb(255, 134, 81); + --color-red-300: rgb(255, 105, 56); + --color-red-400: rgb(255, 75, 29); + --color-red-500: rgb(231, 39, 0); + --color-red-600: rgb(198, 0, 0); + --color-red-700: rgb(166, 0, 0); + --color-red-800: rgb(135, 0, 0); + --color-red-900: rgb(106, 0, 0); + --color-red-950: rgb(94, 0, 0); + --color-gray-50: rgb(241, 241, 241); + --color-gray-100: rgb(226, 226, 226); + --color-gray-200: rgb(198, 198, 198); + --color-gray-300: rgb(171, 171, 171); + --color-gray-400: rgb(145, 145, 145); + --color-gray-500: rgb(119, 119, 119); + --color-gray-600: rgb(94, 94, 94); + --color-gray-700: rgb(71, 71, 71); + --color-gray-800: rgb(48, 48, 48); + --color-gray-900: rgb(27, 27, 27); + --color-gray-950: rgb(17, 17, 17); + + --color-ink-dark: hsl(203, 28%, 22%); + --color-ink-light: hsl(202, 21%, 82%); + + --text-base: 16px; + --text-lg: 24px; + --text-xl: 32px; + --text-xl2: 40px; + --text-xl3: 48px; + + --font-stack-system-sans: + -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, Adwaita Sans, Cantarell, Ubuntu, + roboto, noto, helvetica, arial, sans-serif; + --font-stack-recursive: "Recursive Variable", var(--font-stack-system-sans); + --font-stack-playpen-sans: "Playpen Sans Variable", var(--font-stack-system-sans); +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + margin: 0; + font: 16px/1.2 var(--font-stack-system-sans); + font-weight: 400; +} + +@layer rootBase { + body { + background-color: white; + color: black; + } + @media (prefers-color-scheme: dark) { + body { + background-color: black; + color: white; + } + } +} + +@layer base { +} + +@layer reset { +} diff --git a/portal/inertia/features/account/pages/MyAccountPage.vue b/portal/inertia/features/account/pages/MyAccountPage.vue new file mode 100644 index 000000000..55c72a564 --- /dev/null +++ b/portal/inertia/features/account/pages/MyAccountPage.vue @@ -0,0 +1,66 @@ + + + diff --git a/portal/inertia/features/account/pages/SpecificAccountPage.vue b/portal/inertia/features/account/pages/SpecificAccountPage.vue new file mode 100644 index 000000000..2b97decab --- /dev/null +++ b/portal/inertia/features/account/pages/SpecificAccountPage.vue @@ -0,0 +1,51 @@ + + + diff --git a/portal/inertia/features/auth/pages/LoginRequiredPage.vue b/portal/inertia/features/auth/pages/LoginRequiredPage.vue new file mode 100644 index 000000000..f0ae42580 --- /dev/null +++ b/portal/inertia/features/auth/pages/LoginRequiredPage.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/portal/inertia/features/docs/layouts/DocsLayout.vue b/portal/inertia/features/docs/layouts/DocsLayout.vue new file mode 100644 index 000000000..e9e16497a --- /dev/null +++ b/portal/inertia/features/docs/layouts/DocsLayout.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/portal/inertia/features/docs/pages/DocsIndex.vue b/portal/inertia/features/docs/pages/DocsIndex.vue new file mode 100644 index 000000000..6a6156929 --- /dev/null +++ b/portal/inertia/features/docs/pages/DocsIndex.vue @@ -0,0 +1,38 @@ + + + diff --git a/portal/inertia/features/errors/pages/NotFound.vue b/portal/inertia/features/errors/pages/NotFound.vue new file mode 100644 index 000000000..7d76ee3d0 --- /dev/null +++ b/portal/inertia/features/errors/pages/NotFound.vue @@ -0,0 +1 @@ + diff --git a/portal/inertia/features/errors/pages/ServerError.vue b/portal/inertia/features/errors/pages/ServerError.vue new file mode 100644 index 000000000..745263567 --- /dev/null +++ b/portal/inertia/features/errors/pages/ServerError.vue @@ -0,0 +1 @@ + diff --git a/portal/inertia/features/layout/ContentPaper.vue b/portal/inertia/features/layout/ContentPaper.vue new file mode 100644 index 000000000..2b1ffa11b --- /dev/null +++ b/portal/inertia/features/layout/ContentPaper.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/portal/inertia/features/layout/MainLayout.vue b/portal/inertia/features/layout/MainLayout.vue new file mode 100644 index 000000000..ad4e2e7e5 --- /dev/null +++ b/portal/inertia/features/layout/MainLayout.vue @@ -0,0 +1,373 @@ + + + + + + + diff --git a/portal/inertia/features/layout/PaperH1.vue b/portal/inertia/features/layout/PaperH1.vue new file mode 100644 index 000000000..bd26ee61e --- /dev/null +++ b/portal/inertia/features/layout/PaperH1.vue @@ -0,0 +1,11 @@ + + + diff --git a/portal/inertia/features/layout/SidebarMenu.vue b/portal/inertia/features/layout/SidebarMenu.vue new file mode 100644 index 000000000..5525b7b27 --- /dev/null +++ b/portal/inertia/features/layout/SidebarMenu.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/portal/inertia/features/layout/WithSidebar.vue b/portal/inertia/features/layout/WithSidebar.vue new file mode 100644 index 000000000..f372b6a55 --- /dev/null +++ b/portal/inertia/features/layout/WithSidebar.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/portal/inertia/features/layout/measurements.ts b/portal/inertia/features/layout/measurements.ts new file mode 100644 index 000000000..eb6b15ae4 --- /dev/null +++ b/portal/inertia/features/layout/measurements.ts @@ -0,0 +1 @@ +export const LAYOUT_GRID_SIZE_PX = 48; diff --git a/portal/inertia/features/legal/pages/PrivacyPolicyPage.vue b/portal/inertia/features/legal/pages/PrivacyPolicyPage.vue new file mode 100644 index 000000000..e723d02d6 --- /dev/null +++ b/portal/inertia/features/legal/pages/PrivacyPolicyPage.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/portal/inertia/features/menu/menuItemIsActive.ts b/portal/inertia/features/menu/menuItemIsActive.ts new file mode 100644 index 000000000..45e217d53 --- /dev/null +++ b/portal/inertia/features/menu/menuItemIsActive.ts @@ -0,0 +1,11 @@ +import { MenuItem } from "#backend/features/menu/types"; + +const normalize = (path: string) => path.replace(/\/$/, "").toLowerCase(); + +export function menuItemIsActive(item: MenuItem, currentPath: string) { + const normalizedCurrentPath = normalize(currentPath); + const normalizedItemPath = normalize(item.path); + return item.activeStartsWith + ? normalizedCurrentPath.startsWith(normalizedItemPath) + : normalizedCurrentPath === normalizedItemPath; +} diff --git a/portal/inertia/features/splash/pages/SplashIndex.vue b/portal/inertia/features/splash/pages/SplashIndex.vue new file mode 100644 index 000000000..fd922d757 --- /dev/null +++ b/portal/inertia/features/splash/pages/SplashIndex.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/portal/inertia/features/toasts/FlashToasts.vue b/portal/inertia/features/toasts/FlashToasts.vue new file mode 100644 index 000000000..d9e51ca8c --- /dev/null +++ b/portal/inertia/features/toasts/FlashToasts.vue @@ -0,0 +1,73 @@ + + + + + + + diff --git a/portal/inertia/features/utils/useCurrentPath.ts b/portal/inertia/features/utils/useCurrentPath.ts new file mode 100644 index 000000000..838631a49 --- /dev/null +++ b/portal/inertia/features/utils/useCurrentPath.ts @@ -0,0 +1,7 @@ +import { usePage } from "@inertiajs/vue3"; +import { computed } from "vue"; + +export function useCurrentPath() { + const page = usePage(); + return computed(() => page.url.split("?")[0]); +} diff --git a/portal/inertia/shims.ts b/portal/inertia/shims.ts new file mode 100644 index 000000000..525d5f827 --- /dev/null +++ b/portal/inertia/shims.ts @@ -0,0 +1,5 @@ +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent; + export default component; +} diff --git a/portal/inertia/ssr.ts b/portal/inertia/ssr.ts new file mode 100644 index 000000000..6738be7d3 --- /dev/null +++ b/portal/inertia/ssr.ts @@ -0,0 +1,24 @@ +import { client } from "#frontend/client.js"; +import { createInertiaApp } from "@inertiajs/vue3"; +import { TuyauProvider } from "@adonisjs/inertia/vue"; +import { renderToString } from "@vue/server-renderer"; +import { createSSRApp, h, type DefineComponent } from "vue"; +import { resolvePageComponent } from "@adonisjs/inertia/helpers"; + +export default function render(page: any) { + return createInertiaApp({ + page, + render: renderToString, + resolve: (name) => { + return resolvePageComponent( + `./${name}.vue`, + import.meta.glob("./**/pages/*.vue", { eager: true }), + ); + }, + setup: ({ App, props, plugin }) => { + return createSSRApp({ + render: () => h(TuyauProvider, { client }, { default: () => h(App, props) }), + }).use(plugin); + }, + }); +} diff --git a/portal/inertia/tsconfig.json b/portal/inertia/tsconfig.json new file mode 100644 index 000000000..83546ac29 --- /dev/null +++ b/portal/inertia/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@adonisjs/tsconfig/tsconfig.client.json", + "compilerOptions": { + "jsx": "preserve", + "module": "ESNext", + "jsxImportSource": "vue" + }, + "include": [ + "./**/*.ts", + "./**/*.vue", + "../.adonisjs/client/**/*.ts", + "../.adonisjs/server/**/*.ts" + ] +} diff --git a/portal/inertia/types.ts b/portal/inertia/types.ts new file mode 100644 index 000000000..1c00c1184 --- /dev/null +++ b/portal/inertia/types.ts @@ -0,0 +1,14 @@ +import type { Data } from "#client/data.d.ts"; + +/** + * Bridge the shared props and flash data inferred from the Inertia + * middleware into the Inertia client, so `usePage().props`, `usePage().flash`, + * and layout callbacks are typed globally without passing a generic at each + * call site. + */ +declare module "@inertiajs/core" { + interface InertiaConfig { + sharedPageProps: Data.SharedProps; + flashDataType: Data.FlashMessages; + } +} diff --git a/portal/package.json b/portal/package.json new file mode 100644 index 000000000..ab44cce94 --- /dev/null +++ b/portal/package.json @@ -0,0 +1,92 @@ +{ + "name": "@zeppelinbot/portal", + "private": true, + "type": "module", + "scripts": { + "start": "node bin/server.js", + "build": "node ace build", + "dev": "node ace serve --hmr", + "test": "node ace test", + "ace": "node ace", + "generate-db-schema": "node ace schema:generate", + "typecheck": "tsc --noEmit && vue-tsc --noEmit --project inertia/tsconfig.json" + }, + "imports": { + "#backend/*": "./app/*.js", + "#frontend/*.vue": "./inertia/*.vue", + "#frontend/*": "./inertia/*", + "#generated/*": "./.adonisjs/server/*.js", + "#client/*": "./.adonisjs/client/*", + "#providers/*": "./providers/*.js", + "#database/*": "./database/*.js", + "#tests/*": "./tests/*.js", + "#start/*": "./start/*.js", + "#config/*": "./config/*.js" + }, + "devDependencies": { + "@adonisjs/assembler": "^8.5.2", + "@adonisjs/prettier-config": "^1.5.0", + "@adonisjs/tsconfig": "^2.0.0", + "@japa/assert": "^4.2.0", + "@japa/browser-client": "^2.3.0", + "@japa/plugin-adonisjs": "^5.2.0", + "@japa/runner": "^5.3.0", + "@poppinss/ts-exec": "^1.4.4", + "@types/luxon": "^3.7.5", + "@types/node": "~26.6.2", + "@vitejs/plugin-vue": "^6.0.9", + "hot-hook": "^1.0.0", + "pino-pretty": "^13.1.3", + "typescript": "catalog:ts6", + "vite": "^8.3.0", + "vue-tsc": "^3.3.11", + "youch": "^4.1.1" + }, + "dependencies": { + "@adonisjs/ally": "^6.3.2", + "@adonisjs/auth": "^10.1.0", + "@adonisjs/core": "^7.5.2", + "@adonisjs/cors": "^3.0.0", + "@adonisjs/inertia": "^5.0.1", + "@adonisjs/limiter": "^3.0.1", + "@adonisjs/lucid": "^22.4.2", + "@adonisjs/redis": "^11.0.0", + "@adonisjs/session": "^8.1.0", + "@adonisjs/shield": "^9.0.0", + "@adonisjs/static": "^2.0.1", + "@adonisjs/vite": "^6.0.2", + "@fontsource-variable/playpen-sans": "^5.3.0", + "@fontsource-variable/recursive": "^5.3.0", + "@inertiajs/core": "^3.7.1", + "@inertiajs/vue3": "^3.7.1", + "@tuyau/core": "^1.2.2", + "@vinejs/vine": "^4.4.0", + "@vue/server-renderer": "^3.5.43", + "@zeppelinbot/shared": "workspace:*", + "csv-stringify": "^6.9.0", + "edge.js": "^6.5.1", + "jszip": "^3.10.2", + "lucide-vue-next": "^1.0.0", + "luxon": "^3.7.2", + "markdown-it": "^15.0.2", + "mysql2": "^3.23.0", + "reflect-metadata": "^0.2.2", + "reka-ui": "^2.11.0", + "vue": "^3.5.43", + "vue-sonner": "^2.0.9", + "zod": "^4.4.3" + }, + "hotHook": { + "boundaries": [ + "./app/features/**/controllers/*.ts", + "./app/features/**/middleware/*.ts", + "./app/middleware/*.ts" + ] + }, + "allowScripts": { + "@swc/core": true, + "better-sqlite3": true, + "esbuild": true, + "fsevents": true + } +} diff --git a/portal/providers/apiProvider.ts b/portal/providers/apiProvider.ts new file mode 100644 index 000000000..3d7956fa6 --- /dev/null +++ b/portal/providers/apiProvider.ts @@ -0,0 +1,64 @@ +import { HttpContext } from "@adonisjs/core/http"; +import { BaseSerializer } from "@adonisjs/core/transformers"; +import { type SimplePaginatorMetaKeys } from "@adonisjs/lucid/types/querybuilder"; + +/** + * Custom serializer for API responses that ensures consistent JSON structure + * across all API endpoints. Wraps response data in a 'data' property and handles + * pagination metadata for Lucid ORM query results. + */ +class ApiSerializer extends BaseSerializer<{ + Wrap: "data"; + PaginationMetaData: SimplePaginatorMetaKeys; +}> { + /** + * Wraps all serialized data under this key in the response object. + * Example: { data: [...] } instead of returning raw arrays/objects + */ + wrap = "data" as const; + + /** + * Validates and defines pagination metadata structure for paginated responses. + * Ensures that pagination info from Lucid queries is properly formatted. + * + * @throws Error if metadata doesn't match Lucid's pagination structure + */ + definePaginationMetaData(metaData: unknown): SimplePaginatorMetaKeys { + if (!this.isLucidPaginatorMetaData(metaData)) { + throw new Error("Invalid pagination metadata. Expected metadata to contain Lucid pagination keys"); + } + return metaData; + } +} + +/** + * Single instance of ApiSerializer used across the application + */ +const serializer = new ApiSerializer(); +const serialize = Object.assign( + function (this: HttpContext, ...[data, resolver]: Parameters) { + return serializer.serialize(data, resolver ?? this.containerResolver); + }, + { + withoutWrapping(this: HttpContext, ...[data, resolver]: Parameters) { + return serializer.serializeWithoutWrapping(data, resolver ?? this.containerResolver); + }, + }, +) as ApiSerializer["serialize"] & { withoutWrapping: ApiSerializer["serializeWithoutWrapping"] }; + +/** + * Adds the serialize method to all HttpContext instances. + * Usage in controllers: return ctx.serialize(data) + * This ensures all API responses follow the same structure with data wrapping. + */ +HttpContext.instanceProperty("serialize", serialize); + +/** + * Module augmentation to add the serialize method to HttpContext. + * This allows controllers to use ctx.serialize() for consistent API responses. + */ +declare module "@adonisjs/core/http" { + export interface HttpContext { + serialize: typeof serialize; + } +} diff --git a/portal/resources/views/inertia_layout.edge b/portal/resources/views/inertia_layout.edge new file mode 100644 index 000000000..6b64c09bf --- /dev/null +++ b/portal/resources/views/inertia_layout.edge @@ -0,0 +1,13 @@ + + + + + + @inertiaHead() + {{ csrfMeta() }} + @vite(['inertia/app.ts']) + + + @inertia() + + diff --git a/portal/start/env.ts b/portal/start/env.ts new file mode 100644 index 000000000..9358a7a43 --- /dev/null +++ b/portal/start/env.ts @@ -0,0 +1,38 @@ +/* +|-------------------------------------------------------------------------- +| Environment variables service +|-------------------------------------------------------------------------- +| +| The `Env.create` method creates an instance of the Env service. The +| service validates the environment variables and also cast values +| to JavaScript data types. +| +*/ + +import { Env } from "@adonisjs/core/env"; + +export const rootEnv = await Env.create(new URL("../../", import.meta.url), { + PORTAL_URL: Env.schema.string.optional(), + KEY: Env.schema.string(), + DB_HOST: Env.schema.string.optional(), + DB_PORT: Env.schema.number.optional(), + DB_USER: Env.schema.string.optional(), + DB_PASSWORD: Env.schema.string.optional(), + DB_DATABASE: Env.schema.string.optional(), + REDIS_URL: Env.schema.string.optional(), + DEVELOPMENT_MYSQL_PASSWORD: Env.schema.string.optional(), + DEVELOPMENT_VITE_ALLOWED_HOSTS: Env.schema.string.optional(), + DEVELOPMENT_PORTAL_PORT: Env.schema.number.optional(), + STAFF: Env.schema.string.optional(), + + // Discord client id/secret + CLIENT_ID: Env.schema.string(), + CLIENT_SECRET: Env.schema.string(), +}); + +export const portalEnv = await Env.create(new URL("../", import.meta.url), { + SESSION_DRIVER: Env.schema.enum.optional(["redis", "memory"] as const), + LOG_LEVEL: Env.schema.string.optional(), + LIMITER_STORE: Env.schema.enum.optional(["redis", "memory"] as const), + PORTAL_PRIVACY_POLICY_PATH: Env.schema.string.optional(), +}); diff --git a/portal/start/kernel.ts b/portal/start/kernel.ts new file mode 100644 index 000000000..af5f406d0 --- /dev/null +++ b/portal/start/kernel.ts @@ -0,0 +1,37 @@ +/* +|-------------------------------------------------------------------------- +| HTTP kernel file +|-------------------------------------------------------------------------- +| +| The HTTP kernel file is used to register the middleware with the server +| or the router. +| +*/ + +import router from "@adonisjs/core/services/router"; +import server from "@adonisjs/core/services/server"; + +server.errorHandler(() => import("#backend/exceptions/handler")); + +server.use([ + () => import("#backend/middleware/containerBindingsMiddleware"), + () => import("@adonisjs/static/static_middleware"), + () => import("@adonisjs/cors/cors_middleware"), + () => import("@adonisjs/vite/vite_middleware"), + () => import("#backend/middleware/inertiaMiddleware"), +]); + +router.use([ + () => import("@adonisjs/core/bodyparser_middleware"), + () => import("@adonisjs/session/session_middleware"), + () => import("@adonisjs/shield/shield_middleware"), + () => import("@adonisjs/auth/initialize_auth_middleware"), + () => import("#backend/middleware/silentAuthMiddleware"), +]); + +export const middleware = router.named({ + guest: () => import("#backend/middleware/guestMiddleware"), + auth: () => import("#backend/middleware/authMiddleware"), + authPage: () => import("#backend/features/auth/middleware/authPageMiddleware"), + isStaff: () => import("#backend/middleware/isStaffMiddleware"), +}); diff --git a/portal/start/limiter.ts b/portal/start/limiter.ts new file mode 100644 index 000000000..d17172312 --- /dev/null +++ b/portal/start/limiter.ts @@ -0,0 +1,26 @@ +/* +|-------------------------------------------------------------------------- +| Define HTTP limiters +|-------------------------------------------------------------------------- +| +| The "limiter.define" method creates an HTTP middleware to apply rate +| limits on a route or a group of routes. Feel free to define as many +| throttle middleware as needed. +| +*/ + +import limiter from "@adonisjs/limiter/services/main"; + +export const dataDownloadThrottle = limiter.define("dataDownload", (ctx) => { + return limiter + .allowRequests(1) + .every("5 minutes") + .usingKey(`user_${ctx.auth.user?.discordUserId ?? "anonymous"}`); +}); + +export const dataDeleteThrottle = limiter.define("dataDelete", (ctx) => { + return limiter + .allowRequests(1) + .every("5 minutes") + .usingKey(`user_${ctx.auth.user?.discordUserId ?? "anonymous"}`); +}); diff --git a/portal/start/routes.ts b/portal/start/routes.ts new file mode 100644 index 000000000..db491b789 --- /dev/null +++ b/portal/start/routes.ts @@ -0,0 +1,68 @@ +/* +|-------------------------------------------------------------------------- +| Routes file +|-------------------------------------------------------------------------- +| +| The routes file is used for defining the HTTP routes. +| +*/ + +import { docsLayoutData } from "#backend/features/docs/utils/docsLayoutData"; +import { controllers } from "#generated/controllers"; +import { middleware } from "#start/kernel"; +import { dataDeleteThrottle, dataDownloadThrottle } from "#start/limiter"; +import router from "@adonisjs/core/services/router"; + +router.get("/", [controllers.splash.Splash, "getIndex"]); + +router.get("/privacy-policy", [controllers.legal.PrivacyPolicy, "getPrivacyPolicyPage"]); + +router + .group(() => { + router.get("/", [controllers.docs.Docs, "getIndex"]); + }) + .prefix("/docs") + .use(({ inertia }, next) => { + inertia.share({ + docsLayoutData, + }); + return next(); + }); + +router + .group(() => { + router.get("/oauth/discord/login", [controllers.auth.Auth, "getDiscordLogin"]); + router.get("/oauth/discord/callback", [controllers.auth.Auth, "getDiscordCallback"]); + }) + .middleware(middleware.guest()); + +router.post("/logout", [controllers.auth.Auth, "postLogout"]); + +router + .group(() => { + router.get("/account", [controllers.account.Account, "getMyAccountPage"]); + router + .post("/account/download-data", [controllers.account.Account, "postDownloadMyAccountData"]) + .use(dataDownloadThrottle); + router + .post("/account/delete-data", [controllers.account.Account, "postDeleteMyAccountData"]) + .use(dataDeleteThrottle); + + router + .group(() => { + router + .get("/specific-account/:userId", [controllers.account.Account, "getSpecificAccountPage"]) + .where("userId", { match: /^\d+$/ }); + router + .post("/specific-account/:userId/download-data", [ + controllers.account.Account, + "postDownloadSpecificAccountData", + ]) + .where("userId", { match: /^\d+$/ }); + router + .post("/specific-account/:userId/delete-data", [controllers.account.Account, "postDeleteSpecificAccountData"]) + .where("userId", { match: /^\d+$/ }); + }) + .middleware(middleware.isStaff()); + }) + .middleware(middleware.authPage()); diff --git a/portal/start/validator.ts b/portal/start/validator.ts new file mode 100644 index 000000000..050cac257 --- /dev/null +++ b/portal/start/validator.ts @@ -0,0 +1,23 @@ +/* +|-------------------------------------------------------------------------- +| Validator file +|-------------------------------------------------------------------------- +| +| The validator file is used for configuring global transforms for VineJS. +| The transform below converts all VineJS date outputs from JavaScript +| Date objects to Luxon DateTime instances, so that validated dates are +| ready to use with Lucid models and other parts of the app that expect +| Luxon DateTime. +| +*/ + +import { DateTime } from "luxon"; +import { VineDate } from "@vinejs/vine"; + +declare module "@vinejs/vine/types" { + interface VineGlobalTransforms { + date: DateTime; + } +} + +VineDate.transform((value) => DateTime.fromJSDate(value)); diff --git a/portal/tests/bootstrap.ts b/portal/tests/bootstrap.ts new file mode 100644 index 000000000..d863cfb20 --- /dev/null +++ b/portal/tests/bootstrap.ts @@ -0,0 +1,38 @@ +import { assert } from "@japa/assert"; +import app from "@adonisjs/core/services/app"; +import type { Config } from "@japa/runner/types"; +import { pluginAdonisJS } from "@japa/plugin-adonisjs"; +import { dbAssertions } from "@adonisjs/lucid/plugins/db"; +import testUtils from "@adonisjs/core/services/test_utils"; + +/** + * This file is imported by the "bin/test.ts" entrypoint file + */ + +/** + * Configure Japa plugins in the plugins array. + * Learn more - https://japa.dev/docs/runner-config#plugins-optional + */ +export const plugins: Config["plugins"] = [assert(), pluginAdonisJS(app), dbAssertions(app)]; + +/** + * Configure lifecycle function to run before and after all the + * tests. + * + * The setup functions are executed before all the tests + * The teardown functions are executed after all the tests + */ +export const runnerHooks: Required> = { + setup: [], + teardown: [], +}; + +/** + * Configure suites by tapping into the test suite instance. + * Learn more - https://japa.dev/docs/test-suites#lifecycle-hooks + */ +export const configureSuite: Config["configureSuite"] = (suite) => { + if (["browser", "functional", "e2e"].includes(suite.name)) { + return suite.setup(() => testUtils.httpServer().start()); + } +}; diff --git a/portal/tmp/.gitkeep b/portal/tmp/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/portal/tsconfig.inertia.json b/portal/tsconfig.inertia.json new file mode 100644 index 000000000..8521e34a8 --- /dev/null +++ b/portal/tsconfig.inertia.json @@ -0,0 +1,8 @@ +{ + "extends": "./inertia/tsconfig.json", + "compilerOptions": { + "rootDir": "./inertia", + "composite": true + }, + "include": ["./inertia/**/*.ts", "./inertia/**/*.vue"] +} diff --git a/portal/tsconfig.json b/portal/tsconfig.json new file mode 100644 index 000000000..32a388df7 --- /dev/null +++ b/portal/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@adonisjs/tsconfig/tsconfig.app.json", + "compilerOptions": { + "rootDir": "./", + "outDir": "./build" + }, + "references": [{ "path": "./tsconfig.inertia.json" }] +} diff --git a/portal/vite.config.ts b/portal/vite.config.ts new file mode 100644 index 000000000..6942f2289 --- /dev/null +++ b/portal/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import adonisjs from "@adonisjs/vite/client"; +import { rootEnv } from "#start/env"; + +const allowedHosts = rootEnv + .get("DEVELOPMENT_VITE_ALLOWED_HOSTS", "") + .split(",") + .map((v) => v.trim()) + .filter(Boolean); + +export default defineConfig({ + plugins: [vue(), adonisjs({ entryPoints: ["inertia/app.ts"], reload: ["resources/views/**/*.edge"] })], + + server: { + watch: { + ignored: ["**/storage/**", "**/tmp/**"], + }, + allowedHosts, + ws: { + port: 3004, + clientPort: rootEnv.get("DEVELOPMENT_PORTAL_PORT", 3400), + }, + }, +}); diff --git a/shared/src/CaseTypes.ts b/shared/src/CaseTypes.ts new file mode 100644 index 000000000..e403e92fd --- /dev/null +++ b/shared/src/CaseTypes.ts @@ -0,0 +1,28 @@ +export enum CaseTypes { + Ban = 1, + Unban, + Note, + Warn, + Kick, + Mute, + Unmute, + Deleted, + Softban, +} + +export const CaseNameToType = { + ban: CaseTypes.Ban, + unban: CaseTypes.Unban, + note: CaseTypes.Note, + warn: CaseTypes.Warn, + kick: CaseTypes.Kick, + mute: CaseTypes.Mute, + unmute: CaseTypes.Unmute, + deleted: CaseTypes.Deleted, + softban: CaseTypes.Softban, +}; + +export const CaseTypeToName = Object.entries(CaseNameToType).reduce((map, [name, type]) => { + map[type] = name; + return map; +}, {}) as Record; diff --git a/shared/src/docsData.json b/shared/src/docsData.json new file mode 100644 index 000000000..463ef9c0f --- /dev/null +++ b/shared/src/docsData.json @@ -0,0 +1 @@ +{"guildPlugins":[{"name":"auto_delete","prettyName":"Auto-delete","type":"stable","description":"Allows Zeppelin to auto-delete messages from a channel after a delay","configurationGuide":"Maximum deletion delay is currently 5 minutes","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"enabled":{"default":false,"type":"boolean"},"delay":{"default":"5s","type":"string","maxLength":32}},"additionalProperties":false}},{"name":"automod","prettyName":"Automod","type":"stable","description":"Allows specifying automated actions in response to triggers. Example use cases include word filtering and spam prevention.","configurationGuide":"The automod plugin is very customizable. For a full list of available triggers, actions, and their options, see Config schema at the bottom of this page. \n\n### Simple word filter\nRemoves any messages that contain the word 'banana' and sends a warning to the user.\nModerators (level >= 50) are ignored by the filter based on the override.\n\n~~~yml\nautomod:\n config:\n rules:\n my_filter:\n triggers:\n - match_words:\n words: ['banana']\n case_sensitive: false\n only_full_words: true\n actions:\n clean: true\n warn:\n reason: 'Do not talk about bananas!'\n overrides:\n - level: '>=50'\n config:\n rules:\n my_filter:\n enabled: false\n~~~\n\n### Spam detection\nThis example includes 2 filters:\n\n- The first one is triggered if a user sends 5 messages within 10 seconds OR 3 attachments within 60 seconds.\n The messages are deleted and the user is muted for 5 minutes.\n- The second filter is triggered if a user sends more than 2 emoji within 5 seconds.\n The messages are deleted but the user is not muted.\n\nModerators are ignored by both filters based on the override.\n\n~~~yml\nautomod:\n config:\n rules:\n my_spam_filter:\n triggers:\n - message_spam:\n amount: 5\n within: 10s\n - attachment_spam:\n amount: 3\n within: 60s\n actions:\n clean: true\n mute:\n duration: 5m\n reason: 'Auto-muted for spam'\n my_second_filter:\n triggers:\n - emoji_spam:\n amount: 2\n within: 5s\n actions:\n clean: true\n overrides:\n - level: '>=50'\n config:\n rules:\n my_spam_filter:\n enabled: false\n my_second_filter:\n enabled: false\n~~~\n\n### Custom status alerts\nThis example sends an alert any time a user with a matching custom status sends a message.\n\n~~~yml\nautomod:\n config:\n rules:\n bad_custom_statuses:\n triggers:\n - match_words:\n words: ['banana']\n match_custom_status: true\n actions:\n alert:\n channel: \"473087035574321152\"\n text: |-\n Bad custom status on user <@!{user.id}>:\n {matchSummary}\n~~~","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"rules":{"type":"object","propertyNames":{"type":"string","maxLength":100},"additionalProperties":{"type":"object","properties":{"enabled":{"default":true,"type":"boolean"},"pretty_name":{"type":"string"},"presets":{"default":[],"maxItems":25,"type":"array","items":{"type":"string","maxLength":100}},"affects_bots":{"default":false,"type":"boolean"},"affects_self":{"default":false,"type":"boolean"},"cooldown":{"default":null,"anyOf":[{"type":"string","maxLength":32},{"type":"null"}]},"allow_further_rules":{"default":false,"type":"boolean"},"triggers":{"type":"array","items":{"type":"object","properties":{"any_message":{"type":"object","properties":{},"additionalProperties":false},"match_words":{"type":"object","properties":{"words":{"maxItems":1024,"type":"array","items":{"type":"string","maxLength":2000}},"case_sensitive":{"default":false,"type":"boolean"},"only_full_words":{"default":true,"type":"boolean"},"normalize":{"default":false,"type":"boolean"},"loose_matching":{"default":false,"type":"boolean"},"loose_matching_threshold":{"default":1,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"strip_markdown":{"default":false,"type":"boolean"},"match_messages":{"default":true,"type":"boolean"},"match_embeds":{"default":false,"type":"boolean"},"match_visible_names":{"default":false,"type":"boolean"},"match_usernames":{"default":false,"type":"boolean"},"match_nicknames":{"default":false,"type":"boolean"},"match_custom_status":{"default":false,"type":"boolean"}},"required":["words"],"additionalProperties":false},"match_regex":{"type":"object","properties":{"patterns":{"maxItems":512,"type":"array","items":{"type":"string","maxLength":2000}},"case_sensitive":{"default":false,"type":"boolean"},"normalize":{"default":false,"type":"boolean"},"strip_markdown":{"default":false,"type":"boolean"},"match_messages":{"default":true,"type":"boolean"},"match_embeds":{"default":false,"type":"boolean"},"match_visible_names":{"default":false,"type":"boolean"},"match_usernames":{"default":false,"type":"boolean"},"match_nicknames":{"default":false,"type":"boolean"},"match_custom_status":{"default":false,"type":"boolean"}},"required":["patterns"],"additionalProperties":false},"match_invites":{"type":"object","properties":{"include_guilds":{"maxItems":255,"type":"array","items":{"type":"string"}},"exclude_guilds":{"maxItems":255,"type":"array","items":{"type":"string"}},"include_invite_codes":{"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}},"exclude_invite_codes":{"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}},"include_custom_invite_codes":{"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}},"exclude_custom_invite_codes":{"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}},"allow_group_dm_invites":{"default":false,"type":"boolean"},"match_messages":{"default":true,"type":"boolean"},"match_embeds":{"default":false,"type":"boolean"},"match_visible_names":{"default":false,"type":"boolean"},"match_usernames":{"default":false,"type":"boolean"},"match_nicknames":{"default":false,"type":"boolean"},"match_custom_status":{"default":false,"type":"boolean"}},"additionalProperties":false},"match_links":{"type":"object","properties":{"include_domains":{"maxItems":700,"type":"array","items":{"type":"string","maxLength":255}},"exclude_domains":{"maxItems":700,"type":"array","items":{"type":"string","maxLength":255}},"include_subdomains":{"default":true,"type":"boolean"},"include_words":{"maxItems":700,"type":"array","items":{"type":"string","maxLength":2000}},"exclude_words":{"maxItems":700,"type":"array","items":{"type":"string","maxLength":2000}},"include_regex":{"maxItems":512,"type":"array","items":{"type":"string","maxLength":2000}},"exclude_regex":{"maxItems":512,"type":"array","items":{"type":"string","maxLength":2000}},"phisherman":{"type":"object","properties":{"include_suspected":{"type":"boolean"},"include_verified":{"type":"boolean"}},"additionalProperties":false},"include_malicious":{"default":false,"type":"boolean"},"only_real_links":{"default":true,"type":"boolean"},"match_messages":{"default":true,"type":"boolean"},"match_embeds":{"default":true,"type":"boolean"},"match_visible_names":{"default":false,"type":"boolean"},"match_usernames":{"default":false,"type":"boolean"},"match_nicknames":{"default":false,"type":"boolean"},"match_custom_status":{"default":false,"type":"boolean"}},"additionalProperties":false},"has_attachments":{"type":"object","properties":{"min_count":{"default":1,"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"max_count":{"default":null,"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"additionalProperties":false},"match_attachment_type":{"type":"object","properties":{"whitelist_enabled":{"default":false,"type":"boolean"},"filetype_whitelist":{"default":[],"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}},"blacklist_enabled":{"default":false,"type":"boolean"},"filetype_blacklist":{"default":[],"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}}},"additionalProperties":false},"match_mime_type":{"type":"object","properties":{"whitelist_enabled":{"default":false,"type":"boolean"},"mime_type_whitelist":{"default":[],"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}},"blacklist_enabled":{"default":false,"type":"boolean"},"mime_type_blacklist":{"default":[],"maxItems":255,"type":"array","items":{"type":"string","maxLength":32}}},"additionalProperties":false},"member_join":{"type":"object","properties":{"only_new":{"default":false,"type":"boolean"},"new_threshold":{"default":"1h","type":"string","maxLength":32}},"additionalProperties":false},"member_leave":{"type":"object","properties":{},"additionalProperties":false},"role_added":{"default":[],"anyOf":[{"type":"string"},{"maxItems":255,"type":"array","items":{"type":"string"}}]},"role_removed":{"default":[],"anyOf":[{"type":"string"},{"maxItems":255,"type":"array","items":{"type":"string"}}]},"message_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"mention_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"link_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"attachment_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"emoji_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"line_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"character_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"member_join_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32}},"required":["amount","within"],"additionalProperties":false},"sticker_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32},"per_channel":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["amount","within"],"additionalProperties":false},"thread_create_spam":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"within":{"type":"string","maxLength":32}},"required":["amount","within"],"additionalProperties":false},"counter_trigger":{"type":"object","properties":{"counter":{"type":"string","maxLength":100},"trigger":{"type":"string","maxLength":100},"reverse":{"type":"boolean"}},"required":["counter","trigger"],"additionalProperties":false},"note":{"type":"object","properties":{},"additionalProperties":false},"warn":{"type":"object","properties":{"manual":{"default":true,"type":"boolean"},"automatic":{"default":true,"type":"boolean"}},"additionalProperties":false},"mute":{"type":"object","properties":{"manual":{"default":true,"type":"boolean"},"automatic":{"default":true,"type":"boolean"}},"additionalProperties":false},"unmute":{"type":"object","properties":{},"additionalProperties":false},"kick":{"type":"object","properties":{"manual":{"default":true,"type":"boolean"},"automatic":{"default":true,"type":"boolean"}},"additionalProperties":false},"ban":{"type":"object","properties":{"manual":{"default":true,"type":"boolean"},"automatic":{"default":true,"type":"boolean"}},"additionalProperties":false},"unban":{"type":"object","properties":{},"additionalProperties":false},"antiraid_level":{"type":"object","properties":{"level":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"only_on_change":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["level","only_on_change"],"additionalProperties":false},"thread_create":{"type":"object","properties":{},"additionalProperties":false},"thread_delete":{"type":"object","properties":{},"additionalProperties":false},"thread_archive":{"type":"object","properties":{"locked":{"type":"boolean"}},"additionalProperties":false},"thread_unarchive":{"type":"object","properties":{"locked":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}},"actions":{"type":"object","properties":{"clean":{"default":false,"type":"boolean"},"warn":{"type":"object","properties":{"reason":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"notify":{"default":null,"anyOf":[{"anyOf":[{"type":"string","const":"dm"},{"type":"string","const":"channel"}]},{"type":"null"}]},"notifyChannel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"postInCaseLog":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"hide_case":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false},"mute":{"type":"object","properties":{"reason":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"duration":{"default":null,"anyOf":[{"type":"string","maxLength":32},{"type":"null"}]},"notify":{"default":null,"anyOf":[{"anyOf":[{"type":"string","const":"dm"},{"type":"string","const":"channel"}]},{"type":"null"}]},"notifyChannel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"remove_roles_on_mute":{"default":null,"anyOf":[{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},{"type":"null"}]},"restore_roles_on_mute":{"default":null,"anyOf":[{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},{"type":"null"}]},"postInCaseLog":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"hide_case":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false},"kick":{"type":"object","properties":{"reason":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"notify":{"default":null,"anyOf":[{"anyOf":[{"type":"string","const":"dm"},{"type":"string","const":"channel"}]},{"type":"null"}]},"notifyChannel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"postInCaseLog":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"hide_case":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false},"ban":{"type":"object","properties":{"reason":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"duration":{"default":null,"anyOf":[{"type":"string","maxLength":32},{"type":"null"}]},"notify":{"default":null,"anyOf":[{"anyOf":[{"type":"string","const":"dm"},{"type":"string","const":"channel"}]},{"type":"null"}]},"notifyChannel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"deleteMessageDays":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"postInCaseLog":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"hide_case":{"default":false,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false},"alert":{"type":"object","properties":{"channel":{"type":"string"},"text":{"type":"string"},"allowed_mentions":{"anyOf":[{"type":"object","properties":{"everyone":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"users":{"anyOf":[{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},{"type":"null"}]},"roles":{"anyOf":[{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},{"type":"null"}]},"replied_user":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}]}},"required":["channel","text"]},"change_nickname":{"anyOf":[{"type":"string"},{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false}]},"log":{"default":true,"type":"boolean"},"add_roles":{"type":"array","items":{"type":"string"}},"remove_roles":{"default":[],"type":"array","items":{"type":"string"}},"set_antiraid_level":{"anyOf":[{"type":"string"},{"type":"null"}]},"reply":{"anyOf":[{"type":"string"},{"type":"object","properties":{"text":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"auto_delete":{"default":null,"anyOf":[{"anyOf":[{"type":"string","maxLength":32},{"type":"number"}]},{"type":"null"}]},"inline":{"default":false,"type":"boolean"}},"required":["text"],"additionalProperties":false}]},"add_to_counter":{"type":"object","properties":{"counter":{"type":"string"},"amount":{"type":"number"}},"required":["counter","amount"]},"set_counter":{"type":"object","properties":{"counter":{"type":"string"},"value":{"type":"number","minimum":0,"maximum":2147483647}},"required":["counter","value"],"additionalProperties":false},"set_slowmode":{"type":"object","properties":{"channels":{"default":[],"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"duration":{"default":"10s","anyOf":[{"type":"string","maxLength":32},{"type":"null"}]}},"additionalProperties":false},"start_thread":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_archive":{"type":"string","maxLength":32},"private":{"default":false,"type":"boolean"},"slowmode":{"default":null,"anyOf":[{"type":"string","maxLength":32},{"type":"null"}]},"limit_per_channel":{"default":5,"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["name","auto_archive"],"additionalProperties":false},"archive_thread":{"type":"object","properties":{},"additionalProperties":false},"change_perms":{"type":"object","properties":{"target":{"type":"string"},"channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"perms":{"type":"object","properties":{"CreateInstantInvite":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"KickMembers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"BanMembers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"Administrator":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageChannels":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageGuild":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"AddReactions":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ViewAuditLog":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"PrioritySpeaker":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"Stream":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ViewChannel":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SendMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SendTTSMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"EmbedLinks":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"AttachFiles":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ReadMessageHistory":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MentionEveryone":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseExternalEmojis":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ViewGuildInsights":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"Connect":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"Speak":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MuteMembers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"DeafenMembers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MoveMembers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseVAD":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ChangeNickname":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageNicknames":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageRoles":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageWebhooks":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageEmojisAndStickers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageGuildExpressions":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseApplicationCommands":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"RequestToSpeak":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageEvents":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ManageThreads":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CreatePublicThreads":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CreatePrivateThreads":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseExternalStickers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SendMessagesInThreads":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseEmbeddedActivities":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ModerateMembers":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ViewCreatorMonetizationAnalytics":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseSoundboard":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CreateGuildExpressions":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CreateEvents":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseExternalSounds":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SendVoiceMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SendPolls":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"UseExternalApps":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"PinMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CREATE_INSTANT_INVITE":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"KICK_MEMBERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"BAN_MEMBERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ADMINISTRATOR":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_CHANNELS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_GUILD":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ADD_REACTIONS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"VIEW_AUDIT_LOG":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"PRIORITY_SPEAKER":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"STREAM":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"VIEW_CHANNEL":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SEND_MESSAGES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SEND_TTSMESSAGES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_MESSAGES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"EMBED_LINKS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ATTACH_FILES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"READ_MESSAGE_HISTORY":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MENTION_EVERYONE":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"USE_EXTERNAL_EMOJIS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"VIEW_GUILD_INSIGHTS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CONNECT":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SPEAK":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MUTE_MEMBERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"DEAFEN_MEMBERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MOVE_MEMBERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"USE_VAD":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CHANGE_NICKNAME":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_NICKNAMES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_ROLES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_WEBHOOKS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_EMOJIS_AND_STICKERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"USE_APPLICATION_COMMANDS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"REQUEST_TO_SPEAK":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_EVENTS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MANAGE_THREADS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CREATE_PUBLIC_THREADS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"CREATE_PRIVATE_THREADS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"USE_EXTERNAL_STICKERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"SEND_MESSAGES_IN_THREADS":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"USE_EMBEDDED_ACTIVITIES":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"MODERATE_MEMBERS":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false}},"required":["target","perms"],"additionalProperties":false},"pause_invites":{"type":"object","properties":{"paused":{"type":"boolean"}},"required":["paused"],"additionalProperties":false}},"additionalProperties":false}},"required":["triggers","actions"],"additionalProperties":false}},"antiraid_levels":{"default":["low","medium","high"],"maxItems":10,"type":"array","items":{"type":"string","maxLength":100}},"can_set_antiraid":{"default":false,"type":"boolean"},"can_view_antiraid":{"default":false,"type":"boolean"},"can_debug_automod":{"default":false,"type":"boolean"}},"additionalProperties":false,"$defs":{"strictMessageContent":{"type":"object","properties":{"content":{"type":"string"},"tts":{"type":"boolean"},"embeds":{"anyOf":[{"type":"array","items":{"$ref":"#/$defs/embedInput"}},{"$ref":"#/$defs/embedInput"}]},"embed":{"$ref":"#/$defs/embedInput"}},"additionalProperties":false},"embedInput":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"timestamp":{"type":"string"},"color":{"type":"number"},"footer":{"type":"object","properties":{"text":{"type":"string"},"icon_url":{"type":"string"}},"required":["text"]},"image":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"video":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"provider":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}},"required":["name"]},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"inline":{"type":"boolean"}}}},"author":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}},"required":["name"]},{"type":"null"}]}},"additionalProperties":false}}}},{"name":"auto_reactions","prettyName":"Auto-reactions","type":"stable","description":"Allows setting up automatic reactions to all new messages on a channel","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_manage":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"cases","prettyName":"Cases","type":"stable","description":"This plugin contains basic configuration for cases created by other plugins","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"log_automatic_actions":{"default":true,"type":"boolean"},"case_log_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"show_relative_times":{"default":true,"type":"boolean"},"relative_time_cutoff":{"default":"1w","type":"string","maxLength":32},"case_colors":{"anyOf":[{"type":"object","properties":{"ban":{"type":"string"},"unban":{"type":"string"},"note":{"type":"string"},"warn":{"type":"string"},"kick":{"type":"string"},"mute":{"type":"string"},"unmute":{"type":"string"},"deleted":{"type":"string"},"softban":{"type":"string"}},"additionalProperties":false},{"type":"null"}]},"case_icons":{"default":null,"anyOf":[{"type":"object","properties":{"ban":{"type":"string"},"unban":{"type":"string"},"note":{"type":"string"},"warn":{"type":"string"},"kick":{"type":"string"},"mute":{"type":"string"},"unmute":{"type":"string"},"deleted":{"type":"string"},"softban":{"type":"string"}},"additionalProperties":false},{"type":"null"}]}},"additionalProperties":false}},{"name":"censor","prettyName":"Censor","type":"legacy","description":"Censor words, tokens, links, regex, etc.\nFor more advanced filtering, check out the Automod plugin!","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"filter_zalgo":{"default":false,"type":"boolean"},"filter_invites":{"default":false,"type":"boolean"},"invite_guild_whitelist":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"invite_guild_blacklist":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"invite_code_whitelist":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"invite_code_blacklist":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"allow_group_dm_invites":{"default":false,"type":"boolean"},"filter_domains":{"default":false,"type":"boolean"},"domain_whitelist":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"domain_blacklist":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"blocked_tokens":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"blocked_words":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"blocked_regex":{"default":null,"anyOf":[{"type":"array","items":{"type":"string","maxLength":1000}},{"type":"null"}]}},"additionalProperties":false}},{"name":"command_aliases","prettyName":"Command Aliases","type":"stable","description":"This plugin lets you create shortcuts for existing commands.","usageGuide":"\nFor example, you can make `!b` work the same as `!ban`, or `!c` work the same as `!cases`.\n\n### Example\n\n```yaml\nplugins:\n command_aliases:\n config:\n aliases:\n \"b\": \"ban\"\n \"c\": \"cases\"\n \"b2\": \"ban -d 2\"\n \"ownerinfo\": \"info 754421392988045383\"\n```\n\nWith this setup:\n- `!b @User` runs `!ban @User`\n- `!c` runs `!cases`\n- `!b2 @User` runs `!ban -d 2 @User`\n- `!ownerinfo` runs `!info 754421392988045383`\n ","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"aliases":{"type":"object","propertyNames":{"type":"string","minLength":1},"additionalProperties":{"type":"string","minLength":1}}},"additionalProperties":false}},{"name":"companion_channels","prettyName":"Companion channels","type":"stable","description":"Set up 'companion channels' between text and voice channels.\nOnce set up, any time a user joins one of the specified voice channels,\nthey'll get channel permissions applied to them for the text channels.","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"entries":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"voice_channel_ids":{"type":"array","items":{"type":"string"}},"text_channel_ids":{"type":"array","items":{"type":"string"}},"permissions":{"type":"number"},"enabled":{"default":true,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["voice_channel_ids","text_channel_ids","permissions"],"additionalProperties":false}}},"additionalProperties":false}},{"name":"context_menu","prettyName":"Context menu","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_use":{"default":false,"type":"boolean"},"can_open_mod_menu":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"counters","prettyName":"Counters","type":"stable","description":"Keep track of per-user, per-channel, or global numbers and trigger specific actions based on this number","configurationGuide":"See Counters setup guide","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"counters":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"pretty_name":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"per_channel":{"default":false,"type":"boolean"},"per_user":{"default":false,"type":"boolean"},"initial_value":{"default":0,"type":"number","minimum":0,"maximum":2147483647},"triggers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"pretty_name":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"condition":{"type":"string"},"reverse_condition":{"type":"string"}},"required":["condition"],"additionalProperties":false},{"type":"string"}]}},"decay":{"default":null,"anyOf":[{"type":"object","properties":{"amount":{"type":"number"},"every":{"type":"string","maxLength":32}},"required":["amount","every"],"additionalProperties":false},{"type":"null"}]},"can_view":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"can_edit":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"can_reset_all":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["triggers"],"additionalProperties":false}},"can_view":{"default":false,"type":"boolean"},"can_edit":{"default":false,"type":"boolean"},"can_reset_all":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"custom_events","prettyName":"Custom events","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"events":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"name":{"type":"string"},"trigger":{"type":"object","properties":{"type":{"type":"string","const":"command"},"name":{"type":"string"},"params":{"type":"string"},"can_use":{"type":"boolean"}},"required":["type","name","params","can_use"],"additionalProperties":false},"actions":{"maxItems":10,"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"add_role"},"target":{"type":"string"},"role":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["type","target","role"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"create_case"},"case_type":{"type":"string"},"mod":{"type":"string"},"target":{"type":"string"},"reason":{"type":"string"}},"required":["type","case_type","mod","target","reason"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"move_to_vc"},"target":{"type":"string"},"channel":{"type":"string"}},"required":["type","target","channel"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"message"},"channel":{"type":"string"},"content":{"type":"string"}},"required":["type","channel","content"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"make_role_mentionable"},"role":{"type":"string"},"timeout":{"type":"string","maxLength":32}},"required":["type","role","timeout"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"make_role_unmentionable"},"role":{"type":"string"}},"required":["type","role"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"set_channel_permission_overrides"},"channel":{"type":"string"},"overrides":{"maxItems":15,"type":"array","items":{"type":"object","properties":{"type":{"anyOf":[{"type":"string","const":"member"},{"type":"string","const":"role"}]},"id":{"type":"string"},"allow":{"type":"number"},"deny":{"type":"number"}},"required":["type","id","allow","deny"],"additionalProperties":false}}},"required":["type","channel","overrides"],"additionalProperties":false}]}}},"required":["name","trigger","actions"],"additionalProperties":false}}},"additionalProperties":false}},{"name":"guild_info_saver","prettyName":"Guild info saver","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}},{"name":"internal_poster","prettyName":"Internal poster","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","default":{},"type":"object","properties":{},"additionalProperties":false}},{"name":"locate_user","prettyName":"Locate user","type":"stable","description":"This plugin allows users with access to the commands the following:\n* Instantly receive an invite to the voice channel of a user\n* Be notified as soon as a user switches or joins a voice channel","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_where":{"default":false,"type":"boolean"},"can_alert":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"logs","prettyName":"Logs","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"channels":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"include":{"default":[],"type":"array","items":{"type":"string"}},"exclude":{"default":[],"type":"array","items":{"type":"string"}},"batched":{"default":true,"type":"boolean"},"batch_time":{"default":1000,"type":"number","minimum":250,"maximum":5000},"excluded_users":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"excluded_message_regexes":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"excluded_channels":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"excluded_categories":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"excluded_threads":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"exclude_bots":{"default":false,"type":"boolean"},"excluded_roles":{"default":null,"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"format":{"type":"object","properties":{"MEMBER_WARN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_MUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_UNMUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_MUTE_EXPIRED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_KICK":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_BAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_UNBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_FORCEBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_SOFTBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_JOIN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_LEAVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_ROLE_ADD":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_ROLE_REMOVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_NICK_CHANGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_USERNAME_CHANGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_RESTORE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CHANNEL_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CHANNEL_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CHANNEL_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"THREAD_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"THREAD_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"THREAD_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"ROLE_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"ROLE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"ROLE_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_EDIT":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE_BULK":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE_BARE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_JOIN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_LEAVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_MOVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STAGE_INSTANCE_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STAGE_INSTANCE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STAGE_INSTANCE_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"EMOJI_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"EMOJI_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"EMOJI_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STICKER_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STICKER_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STICKER_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"COMMAND":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_SPAM_DETECTED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CENSOR":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CLEAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CASE_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MASSUNBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MASSBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MASSMUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_MUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_UNMUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_BAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_UNBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_JOIN_WITH_PRIOR_RECORDS":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"OTHER_SPAM_DETECTED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_ROLE_CHANGES":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_FORCE_MOVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_FORCE_DISCONNECT":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CASE_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_MUTE_REJOIN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SCHEDULED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"POSTED_SCHEDULED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"BOT_ALERT":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"AUTOMOD_ACTION":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SCHEDULED_REPEATED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"REPEATED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE_AUTO":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SET_ANTIRAID_USER":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SET_ANTIRAID_AUTO":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_NOTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CASE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"DM_FAILED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]}},"additionalProperties":false},"timestamp_format":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"include_embed_timestamp":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"additionalProperties":false}},"format":{"default":{},"type":"object","properties":{"MEMBER_WARN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_MUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_UNMUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_MUTE_EXPIRED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_KICK":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_BAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_UNBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_FORCEBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_SOFTBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_JOIN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_LEAVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_ROLE_ADD":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_ROLE_REMOVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_NICK_CHANGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_USERNAME_CHANGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_RESTORE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CHANNEL_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CHANNEL_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CHANNEL_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"THREAD_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"THREAD_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"THREAD_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"ROLE_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"ROLE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"ROLE_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_EDIT":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE_BULK":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE_BARE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_JOIN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_LEAVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_MOVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STAGE_INSTANCE_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STAGE_INSTANCE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STAGE_INSTANCE_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"EMOJI_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"EMOJI_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"EMOJI_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STICKER_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STICKER_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"STICKER_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"COMMAND":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_SPAM_DETECTED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CENSOR":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CLEAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CASE_CREATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MASSUNBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MASSBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MASSMUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_MUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_UNMUTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_BAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_TIMED_UNBAN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_JOIN_WITH_PRIOR_RECORDS":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"OTHER_SPAM_DETECTED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_ROLE_CHANGES":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_FORCE_MOVE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"VOICE_CHANNEL_FORCE_DISCONNECT":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CASE_UPDATE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_MUTE_REJOIN":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SCHEDULED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"POSTED_SCHEDULED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"BOT_ALERT":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"AUTOMOD_ACTION":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SCHEDULED_REPEATED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"REPEATED_MESSAGE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MESSAGE_DELETE_AUTO":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SET_ANTIRAID_USER":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"SET_ANTIRAID_AUTO":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"MEMBER_NOTE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"CASE_DELETE":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"DM_FAILED":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]}},"additionalProperties":false},"ping_user":{"default":true,"type":"boolean"},"allow_user_mentions":{"default":false,"type":"boolean"},"timestamp_format":{"default":"[]","anyOf":[{"type":"string"},{"type":"null"}]},"include_embed_timestamp":{"default":true,"type":"boolean"}},"additionalProperties":false,"$defs":{"strictMessageContent":{"type":"object","properties":{"content":{"type":"string"},"tts":{"type":"boolean"},"embeds":{"anyOf":[{"type":"array","items":{"$ref":"#/$defs/embedInput"}},{"$ref":"#/$defs/embedInput"}]},"embed":{"$ref":"#/$defs/embedInput"}},"additionalProperties":false},"embedInput":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"timestamp":{"type":"string"},"color":{"type":"number"},"footer":{"type":"object","properties":{"text":{"type":"string"},"icon_url":{"type":"string"}},"required":["text"]},"image":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"video":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"provider":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}},"required":["name"]},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"inline":{"type":"boolean"}}}},"author":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}},"required":["name"]},{"type":"null"}]}},"additionalProperties":false}}}},{"name":"message_saver","prettyName":"Message saver","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_manage":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"mod_actions","prettyName":"Mod actions","type":"stable","description":"This plugin contains the 'typical' mod actions such as warning, muting, kicking, banning, etc.","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dm_on_warn":{"default":true,"type":"boolean"},"dm_on_kick":{"default":false,"type":"boolean"},"dm_on_ban":{"default":false,"type":"boolean"},"message_on_warn":{"default":false,"type":"boolean"},"message_on_kick":{"default":false,"type":"boolean"},"message_on_ban":{"default":false,"type":"boolean"},"message_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"warn_message":{"default":"You have received a warning on the {guildName} server: {reason}","anyOf":[{"type":"string"},{"type":"null"}]},"kick_message":{"default":"You have been kicked from the {guildName} server. Reason given: {reason}","anyOf":[{"type":"string"},{"type":"null"}]},"ban_message":{"default":"You have been banned from the {guildName} server. Reason given: {reason}","anyOf":[{"type":"string"},{"type":"null"}]},"tempban_message":{"default":"You have been banned from the {guildName} server for {banTime}. Reason given: {reason}","anyOf":[{"type":"string"},{"type":"null"}]},"alert_on_rejoin":{"default":false,"type":"boolean"},"alert_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"warn_notify_enabled":{"default":false,"type":"boolean"},"warn_notify_threshold":{"default":5,"type":"number"},"warn_notify_message":{"default":"The user already has **{priorWarnings}** warnings!\n Please check their prior cases and assess whether or not to warn anyways.\n Proceed with the warning?","type":"string"},"ban_delete_message_days":{"default":1,"type":"number"},"attachment_link_reaction":{"default":"warn","anyOf":[{"anyOf":[{"type":"string","const":"none"},{"type":"string","const":"warn"},{"type":"string","const":"restrict"}]},{"type":"null"}]},"can_note":{"default":false,"type":"boolean"},"can_warn":{"default":false,"type":"boolean"},"can_mute":{"default":false,"type":"boolean"},"can_kick":{"default":false,"type":"boolean"},"can_ban":{"default":false,"type":"boolean"},"can_unban":{"default":false,"type":"boolean"},"can_view":{"default":false,"type":"boolean"},"can_addcase":{"default":false,"type":"boolean"},"can_massunban":{"default":false,"type":"boolean"},"can_massban":{"default":false,"type":"boolean"},"can_massmute":{"default":false,"type":"boolean"},"can_hidecase":{"default":false,"type":"boolean"},"can_deletecase":{"default":false,"type":"boolean"},"can_act_as_other":{"default":false,"type":"boolean"},"create_cases_for_manual_actions":{"default":true,"type":"boolean"}},"additionalProperties":false}},{"name":"mutes","prettyName":"Mutes","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"mute_role":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"move_to_voice_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"kick_from_voice_channel":{"default":false,"type":"boolean"},"dm_on_mute":{"default":false,"type":"boolean"},"dm_on_update":{"default":false,"type":"boolean"},"message_on_mute":{"default":false,"type":"boolean"},"message_on_update":{"default":false,"type":"boolean"},"message_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"mute_message":{"default":"You have been muted on the {guildName} server. Reason given: {reason}","anyOf":[{"type":"string"},{"type":"null"}]},"timed_mute_message":{"default":"You have been muted on the {guildName} server for {time}. Reason given: {reason}","anyOf":[{"type":"string"},{"type":"null"}]},"update_mute_message":{"default":"Your mute on the {guildName} server has been updated to {time}.","anyOf":[{"type":"string"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"can_view_list":{"default":false,"type":"boolean"},"can_cleanup":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"name_history","prettyName":"Name history","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_view":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"persist","prettyName":"Persist","type":"stable","description":"Re-apply roles or nicknames for users when they rejoin the server.\nMute roles are re-applied automatically, this plugin is not required for that.","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"persisted_roles":{"default":[],"type":"array","items":{"type":"string"}},"persist_nicknames":{"default":false,"type":"boolean"},"persist_voice_mutes":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"phisherman","prettyName":"Phisherman","type":"legacy","description":"Match malicious links using Phisherman","configurationGuide":"This plugin has been deprecated. Please use the `include_malicious` option for automod `match_links` trigger instead.","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"api_key":{"default":null,"anyOf":[{"type":"string","maxLength":255},{"type":"null"}]}},"additionalProperties":false}},{"name":"pingable_roles","prettyName":"Pingable roles","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_manage":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"post","prettyName":"Post","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_post":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"reaction_roles","prettyName":"Reaction roles","type":"legacy","description":"Consider using the [Role buttons](https://zeppelin.gg/docs/plugins/role_buttons) plugin instead.","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"auto_refresh_interval":{"default":900000,"type":"number","minimum":900000},"remove_user_reactions":{"default":true,"type":"boolean"},"can_manage":{"default":false,"type":"boolean"},"button_groups":{"default":null,"type":"null"}},"additionalProperties":false}},{"name":"reminders","prettyName":"Reminders","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_use":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"role_buttons","prettyName":"Role buttons","type":"stable","description":"Allow users to pick roles by clicking on buttons","configurationGuide":"Button roles are entirely config-based; this is in contrast to the old reaction roles. They can either be added to an existing message posted by Zeppelin or posted as a new message.\n\n## Basic role buttons\n~~~yml\nrole_buttons:\n config:\n buttons:\n my_roles: # You can use any name you want here, but make sure not to change it afterwards\n message:\n channel_id: \"967407495544983552\"\n content: \"Click the reactions below to get roles! Click again to remove the role.\"\n options:\n - role_id: \"878339100015489044\"\n label: \"Role 1\"\n - role_id: \"967410091571703808\"\n emoji: \"😁\" # Default emoji as a unicode emoji\n label: \"Role 2\"\n - role_id: \"967410091571703234\"\n emoji: \"967412591683047445\" # Custom emoji ID\n - role_id: \"967410091571703567\"\n label: \"Role 4\"\n style: DANGER # Button style (in all caps), see https://discord.com/developers/docs/interactions/message-components#button-object-button-styles\n~~~\n\n### Or with an embed:\n~~~yml\nrole_buttons:\n config:\n buttons:\n my_roles:\n message:\n channel_id: \"967407495544983552\"\n content:\n embeds:\n - title: \"Pick your role below!\"\n color: 0x0088FF\n description: \"You can pick any role you want by clicking the buttons below.\"\n options:\n ... # See above for examples for options\n~~~\n\n## Role buttons for an existing message\nThis message must be posted by Zeppelin.\n~~~yml\nrole_buttons:\n config:\n buttons:\n my_roles:\n message:\n channel_id: \"967407495544983552\"\n message_id: \"967407554412040193\"\n options:\n ... # See above for examples for options\n~~~\n\n## Limiting to one role (\"exclusive\" roles)\nWhen the `exclusive` option is enabled, only one role can be selected at a time.\n~~~yml\nrole_buttons:\n config:\n buttons:\n my_roles:\n message:\n channel_id: \"967407495544983552\"\n message_id: \"967407554412040193\"\n exclusive: true # With this option set, only one role can be selected at a time\n options:\n ... # See above for examples for options\n~~~","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"buttons":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"message":{"anyOf":[{"type":"object","properties":{"channel_id":{"type":"string"},"message_id":{"type":"string"}},"required":["channel_id","message_id"],"additionalProperties":false},{"type":"object","properties":{"channel_id":{"type":"string"},"content":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]}},"required":["channel_id","content"],"additionalProperties":false}]},"add_message":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"remove_message":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},"options":{"maxItems":25,"type":"array","items":{"type":"object","properties":{"role_id":{"type":"string"},"label":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"emoji":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"style":{"default":null,"anyOf":[{"anyOf":[{"type":"number","const":1},{"type":"number","const":2},{"type":"number","const":3},{"type":"number","const":4},{"type":"string","const":"PRIMARY"},{"type":"string","const":"SECONDARY"},{"type":"string","const":"SUCCESS"},{"type":"string","const":"DANGER"}]},{"type":"null"}]},"start_new_row":{"default":false,"type":"boolean"}},"required":["role_id"],"additionalProperties":false}},"exclusive":{"default":false,"type":"boolean"}},"required":["message","options"],"additionalProperties":false}},"can_reset":{"default":false,"type":"boolean"}},"additionalProperties":false,"$defs":{"strictMessageContent":{"type":"object","properties":{"content":{"type":"string"},"tts":{"type":"boolean"},"embeds":{"anyOf":[{"type":"array","items":{"$ref":"#/$defs/embedInput"}},{"$ref":"#/$defs/embedInput"}]},"embed":{"$ref":"#/$defs/embedInput"}},"additionalProperties":false},"embedInput":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"timestamp":{"type":"string"},"color":{"type":"number"},"footer":{"type":"object","properties":{"text":{"type":"string"},"icon_url":{"type":"string"}},"required":["text"]},"image":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"video":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"provider":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}},"required":["name"]},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"inline":{"type":"boolean"}}}},"author":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}},"required":["name"]},{"type":"null"}]}},"additionalProperties":false}}}},{"name":"role_manager","prettyName":"Role manager","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}},{"name":"roles","prettyName":"Roles","type":"stable","description":"Enables authorised users to add and remove whitelisted roles with a command.","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_assign":{"default":false,"type":"boolean"},"can_mass_assign":{"default":false,"type":"boolean"},"assignable_roles":{"default":[],"maxItems":100,"type":"array","items":{"type":"string"}}},"additionalProperties":false}},{"name":"self_grantable_roles","prettyName":"Self-grantable roles","type":"stable","description":"Allows users to grant themselves roles via a command","configurationGuide":"### Basic configuration\nIn this example, users can add themselves platform roles on the channel 473087035574321152 by using the\n`!role` command. For example, `!role pc ps4` to add both the \"pc\" and \"ps4\" roles as specified below.\n\n~~~yml\nself_grantable_roles:\n config:\n entries:\n basic:\n roles:\n \"543184300250759188\": [\"pc\", \"computer\"]\n \"534710505915547658\": [\"ps4\", \"ps\", \"playstation\"]\n \"473085927053590538\": [\"xbox\", \"xb1\", \"xb\"]\n overrides:\n - channel: \"473087035574321152\"\n config:\n entries:\n basic:\n can_use: true\n~~~\n\n### Maximum number of roles\nThis is identical to the basic example above, but users can only choose 1 role.\n\n~~~yml\nself_grantable_roles:\n config:\n entries:\n basic:\n roles:\n \"543184300250759188\": [\"pc\", \"computer\"]\n \"534710505915547658\": [\"ps4\", \"ps\", \"playstation\"]\n \"473085927053590538\": [\"xbox\", \"xb1\", \"xb\"]\n max_roles: 1\n overrides:\n - channel: \"473087035574321152\"\n config:\n entries:\n basic:\n can_use: true\n~~~","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"entries":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"roles":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"maxItems":100,"type":"array","items":{"type":"string"}}},"can_use":{"default":false,"type":"boolean"},"can_ignore_cooldown":{"default":false,"type":"boolean"},"max_roles":{"default":0,"type":"number"}},"required":["roles"],"additionalProperties":false}},"mention_roles":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"slowmode","prettyName":"Slowmode","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"use_native_slowmode":{"default":true,"type":"boolean"},"can_manage":{"default":false,"type":"boolean"},"is_affected":{"default":true,"type":"boolean"}},"additionalProperties":false}},{"name":"spam","prettyName":"Spam protection","type":"legacy","description":"Basic spam detection and auto-muting.\nFor more advanced spam filtering, check out the Automod plugin!","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"max_censor":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_messages":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_mentions":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_links":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_attachments":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_emojis":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_newlines":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_duplicates":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_characters":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]},"max_voice_moves":{"default":null,"anyOf":[{"type":"object","properties":{"interval":{"type":"number"},"count":{"type":"number"},"mute":{"default":false,"type":"boolean"},"mute_time":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]},"remove_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"restore_roles_on_mute":{"default":false,"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"clean":{"default":false,"type":"boolean"}},"required":["interval","count"],"additionalProperties":false},{"type":"null"}]}},"additionalProperties":false}},{"name":"starboard","prettyName":"Starboard","type":"stable","description":"This plugin allows you to set up starboards on your server. Starboards are like user voted pins where messages with enough reactions get immortalized on a \"starboard\" channel.","configurationGuide":"### Note on emojis\nTo specify emoji in the config, you need to use the emoji's \"raw form\".\nTo obtain this, post the emoji with a backslash in front of it.\n\n- Example with a default emoji: \":star:\" => \"⭐\"\n- Example with a custom emoji: \":mrvnSmile:\" => \"<:mrvnSmile:543000534102310933>\"\n\n### Basic starboard\nAny message on the server that gets 5 star reactions will be posted into the starboard channel (604342689038729226).\n\n~~~yml\nstarboard:\n config:\n boards:\n basic:\n channel_id: \"604342689038729226\"\n stars_required: 5\n~~~\n\n### Basic starboard with custom color\nAny message on the server that gets 5 star reactions will be posted into the starboard channel (604342689038729226), with the given color (0x87CEEB).\n\n~~~yml\nstarboard:\n config:\n boards:\n basic:\n channel_id: \"604342689038729226\"\n stars_required: 5\n color: 0x87CEEB\n~~~\n\n### Custom star emoji\nThis is identical to the basic starboard above, but accepts two emoji: the regular star and a custom :mrvnSmile: emoji\n\n~~~yml\nstarboard:\n config:\n boards:\n basic:\n channel_id: \"604342689038729226\"\n star_emoji: [\"⭐\", \"<:mrvnSmile:543000534102310933>\"]\n stars_required: 5\n~~~\n\n### Limit starboard to a specific channel\nThis is identical to the basic starboard above, but only works from a specific channel (473087035574321152).\n\n~~~yml\nstarboard:\n config:\n boards:\n basic:\n enabled: false # The starboard starts disabled and is then enabled in a channel override below\n channel_id: \"604342689038729226\"\n stars_required: 5\n overrides:\n - channel: \"473087035574321152\"\n config:\n boards:\n basic:\n enabled: true\n~~~\n\n### Limit starboard to a specific level (and above)\nThis is identical to the basic starboard above, but only works for a specific level (>=50).\n\n~~~yml\nstarboard:\n config:\n boards:\n levelonly:\n enabled: false # The starboard starts disabled and is then enabled in a level override below\n channel_id: \"604342689038729226\"\n stars_required: 1\n overrides:\n - level: \">=50\"\n config:\n boards:\n levelonly:\n enabled: true\n~~~","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"boards":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"channel_id":{"type":"string"},"stars_required":{"type":"number"},"star_emoji":{"default":["⭐"],"type":"array","items":{"type":"string"}},"allow_selfstars":{"default":false,"type":"boolean"},"copy_full_embed":{"default":false,"type":"boolean"},"enabled":{"default":true,"type":"boolean"},"show_star_count":{"default":true,"type":"boolean"},"color":{"default":null,"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["channel_id","stars_required"],"additionalProperties":false}},"can_migrate":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"tags","prettyName":"Tags","type":"stable","description":"Tags are a way to store and reuse information.","configurationGuide":"### Template Functions\nYou can use template functions in your tags. These functions are called when the tag is rendered.\nYou can use these functions to render dynamic content, or to access information from the message and/or user calling the tag.\nYou use them by adding a `{}` on your tag.\n\nHere are the functions you can use in your tags:\n\n## if\n**Checks if a condition is true or false and returns the corresponding ifTrue or ifFalse**\n\n__Usage__: `{if(condition, ifTrue, ifFalse)}`\n\n__Examples__:\n> `{if(user.bot, \"User is a bot\", \"User is not a bot\")}`\n\n## and\n**Checks if all provided conditions are true**\n\n__Usage__: `{and(condition1, condition2, ...)}`\n\n__Examples__:\n> `{and(user.bot, user.verified)}`\n\n## or\n**Checks if atleast one of the provided conditions is true**\n\n__Usage__: `{or(condition1, condition2, ...)}`\n\n__Examples__:\n> `{or(user.bot, user.verified)}`\n\n## not\n**Checks if the provided condition is false**\n\n__Usage__: `{not(condition)}`\n\n__Examples__:\n> `{not(user.bot)}`\n\n## concat\n**Concatenates several arguments into a string**\n\n__Usage__: `{concat(argument1, argument2, ...)}`\n\n__Examples__:\n> `{concat(\"Hello \", user.username, \"!\")}`\n\n## concatArr\n**Joins a array with the provided separator**\n\n__Usage__: `{concatArr(array, separator)}`\n\n__Examples__:\n> `{concatArr([\"Hello\", \"World\"], \" \")}`\n\n## eq\n**Checks if all provided arguments are equal to each other**\n\n__Usage__: `{eq(argument1, argument2, ...)}`\n\n__Examples__:\n> `{eq(user.id, \"106391128718245888\")}`\n\n## gt\n**Checks if the first argument is greater than the second**\n\n__Usage__: `{gt(argument1, argument2)}`\n\n__Examples__:\n> `{gt(5, 2)}`\n\n## gte\n**Checks if the first argument is greater or equal to the second**\n\n__Usage__: `{gte(argument1, argument2)}`\n\n__Examples__:\n> `{gte(2, 2)}`\n\n## lt\n**Checks if the first argument is smaller than the second**\n\n__Usage__: `{lt(argument1, argument2)}`\n\n__Examples__:\n> `{lt(2, 5)}`\n\n## lte\n**Checks if the first argument is smaller or equal to the second**\n\n__Usage__: `{lte(argument1, argument2)}`\n\n__Examples__:\n> `{lte(2, 2)}`\n\n## slice\n**Slices a string argument at start and end**\n\n__Usage__: `{slice(string, start, end)}`\n\n__Examples__:\n> `{slice(\"Hello World\", 0, 5)}`\n\n## lower\n**Converts a string argument to lowercase**\n\n__Usage__: `{lower(string)}`\n\n__Examples__:\n> `{lower(\"Hello World\")}`\n\n## upper\n**Converts a string argument to uppercase**\n\n__Usage__: `{upper(string)}`\n\n__Examples__:\n> `{upper(\"Hello World\")}`\n\n## upperFirst\n**Converts the first character of a string argument to uppercase**\n\n__Usage__: `{upperFirst(string)}`\n\n__Examples__:\n> `{upperFirst(\"hello World\")}`\n\n## rand\n**Returns a random number between from and to, optionally using seed**\n\n__Usage__: `{rand(from, to, seed)}`\n\n__Examples__:\n> `{rand(1, 10)}`\n\n## round\n**Rounds a number to the given decimal places**\n\n__Usage__: `{round(number, decimalPlaces)}`\n\n__Examples__:\n> `{round(1.2345, 2)}`\n\n## add\n**Adds two or more numbers**\n\n__Usage__: `{add(number1, number2, ...)}`\n\n__Examples__:\n> `{add(1, 2)}`\n\n## sub\n**Subtracts two or more numbers**\n\n__Usage__: `{sub(number1, number2, ...)}`\n\n__Examples__:\n> `{sub(3, 1)}`\n\n## mul\n**Multiplies two or more numbers**\n\n__Usage__: `{mul(number1, number2, ...)}`\n\n__Examples__:\n> `{mul(2, 3)}`\n\n## div\n**Divides two or more numbers**\n\n__Usage__: `{div(number1, number2, ...)}`\n\n__Examples__:\n> `{div(6, 2)}`\n\n## cases\n**Returns the argument at position**\n\n__Usage__: `{cases(position, argument1, argument2, ...)}`\n\n__Examples__:\n> `{cases(1, \"Hello\", \"World\")}`\n\n## choose\n**Returns a random argument**\n\n__Usage__: `{choose(argument1, argument2, ...)}`\n\n__Examples__:\n> `{choose(\"Hello\", \"World\", \"!\")}`","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"prefix":{"default":"!!","type":"string"},"delete_with_command":{"default":true,"type":"boolean"},"user_tag_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"global_tag_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"user_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"allow_mentions":{"default":false,"type":"boolean"},"global_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"auto_delete_command":{"default":false,"type":"boolean"},"categories":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"prefix":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"delete_with_command":{"default":false,"type":"boolean"},"user_tag_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"user_category_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"global_tag_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"allow_mentions":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"global_category_cooldown":{"default":null,"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"auto_delete_command":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"tags":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]}},"can_use":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["tags"],"additionalProperties":false}},"can_create":{"default":false,"type":"boolean"},"can_use":{"default":false,"type":"boolean"},"can_list":{"default":false,"type":"boolean"}},"additionalProperties":false,"$defs":{"strictMessageContent":{"type":"object","properties":{"content":{"type":"string"},"tts":{"type":"boolean"},"embeds":{"anyOf":[{"type":"array","items":{"$ref":"#/$defs/embedInput"}},{"$ref":"#/$defs/embedInput"}]},"embed":{"$ref":"#/$defs/embedInput"}},"additionalProperties":false},"embedInput":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"timestamp":{"type":"string"},"color":{"type":"number"},"footer":{"type":"object","properties":{"text":{"type":"string"},"icon_url":{"type":"string"}},"required":["text"]},"image":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"video":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"provider":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}},"required":["name"]},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"inline":{"type":"boolean"}}}},"author":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}},"required":["name"]},{"type":"null"}]}},"additionalProperties":false}}}},{"name":"time_and_date","prettyName":"Time and date","type":"stable","description":"Allows controlling the displayed time/date formats and timezones","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"timezone":{"default":"Etc/UTC","type":"string"},"date_formats":{"default":{"date":"MMM D, YYYY","time":"H:mm","pretty_datetime":"MMM D, YYYY [at] H:mm z"},"type":"object","properties":{"date":{"default":"MMM D, YYYY","type":"string"},"time":{"default":"H:mm","type":"string"},"pretty_datetime":{"default":"MMM D, YYYY [at] H:mm z","type":"string"}},"additionalProperties":false},"can_set_timezone":{"default":false,"type":"boolean"}},"additionalProperties":false}},{"name":"username_saver","prettyName":"Username saver","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}},{"name":"utility","prettyName":"Utility","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_roles":{"default":false,"type":"boolean"},"can_level":{"default":false,"type":"boolean"},"can_search":{"default":false,"type":"boolean"},"can_clean":{"default":false,"type":"boolean"},"can_info":{"default":false,"type":"boolean"},"can_server":{"default":false,"type":"boolean"},"can_inviteinfo":{"default":false,"type":"boolean"},"can_channelinfo":{"default":false,"type":"boolean"},"can_messageinfo":{"default":false,"type":"boolean"},"can_userinfo":{"default":false,"type":"boolean"},"can_roleinfo":{"default":false,"type":"boolean"},"can_emojiinfo":{"default":false,"type":"boolean"},"can_snowflake":{"default":false,"type":"boolean"},"can_reload_guild":{"default":false,"type":"boolean"},"can_nickname":{"default":false,"type":"boolean"},"can_ping":{"default":false,"type":"boolean"},"can_source":{"default":false,"type":"boolean"},"can_vcmove":{"default":false,"type":"boolean"},"can_vckick":{"default":false,"type":"boolean"},"can_help":{"default":false,"type":"boolean"},"can_about":{"default":false,"type":"boolean"},"can_context":{"default":false,"type":"boolean"},"can_jumbo":{"default":false,"type":"boolean"},"jumbo_size":{"default":128,"type":"number"},"can_avatar":{"default":false,"type":"boolean"},"info_on_single_result":{"default":true,"type":"boolean"},"autojoin_threads":{"default":true,"type":"boolean"}},"additionalProperties":false}},{"name":"welcome_message","prettyName":"Welcome message","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"send_dm":{"default":false,"type":"boolean"},"send_to_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"message":{"anyOf":[{"anyOf":[{"type":"string"},{"$ref":"#/$defs/strictMessageContent"}]},{"type":"null"}]}},"additionalProperties":false,"$defs":{"strictMessageContent":{"type":"object","properties":{"content":{"type":"string"},"tts":{"type":"boolean"},"embeds":{"anyOf":[{"type":"array","items":{"$ref":"#/$defs/embedInput"}},{"$ref":"#/$defs/embedInput"}]},"embed":{"$ref":"#/$defs/embedInput"}},"additionalProperties":false},"embedInput":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"timestamp":{"type":"string"},"color":{"type":"number"},"footer":{"type":"object","properties":{"text":{"type":"string"},"icon_url":{"type":"string"}},"required":["text"]},"image":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"video":{"type":"object","properties":{"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}}},"provider":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}},"required":["name"]},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"inline":{"type":"boolean"}}}},"author":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}},"required":["name"]},{"type":"null"}]}},"additionalProperties":false}}}},{"name":"common","prettyName":"Common","type":"stable","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success_emoji":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"error_emoji":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"attachment_storing_channel":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false}}],"globalPlugins":[{"name":"guild_config_reloader","prettyName":"Guild config reloader","type":"internal","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}},{"name":"bot_control","prettyName":"Bot control","type":"stable","description":"Contains commands to manage allowed servers","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"can_use":{"default":false,"type":"boolean"},"can_eligible":{"default":false,"type":"boolean"},"can_performance":{"default":false,"type":"boolean"},"can_add_server_from_invite":{"default":false,"type":"boolean"},"can_list_dashboard_perms":{"default":false,"type":"boolean"},"update_cmd":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false}},{"name":"guild_access_monitor","prettyName":"Bot control","type":"stable","description":"Automatically leaves servers that are not on the list of allowed servers","configJsonSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}}]} \ No newline at end of file diff --git a/shared/src/docsData.ts b/shared/src/docsData.ts new file mode 100644 index 000000000..ca6bb0fc9 --- /dev/null +++ b/shared/src/docsData.ts @@ -0,0 +1,4 @@ +import data from "./docsData.json" with { type: "json" }; +import type { ZeppelinDocsData } from "./docsDataTypes.js"; + +export const docsData = data as ZeppelinDocsData; diff --git a/shared/src/docsDataTypes.ts b/shared/src/docsDataTypes.ts new file mode 100644 index 000000000..745709a0b --- /dev/null +++ b/shared/src/docsDataTypes.ts @@ -0,0 +1,17 @@ +/** + * A serializable version of ZeppelinPluginDocs + */ +export interface ZeppelinPluginDocsData { + name: string; + prettyName: string; + type: "stable" | "legacy" | "internal"; + description?: string; + usageGuide?: string; + configurationGuide?: string; + configJsonSchema: any; +} + +export interface ZeppelinDocsData { + guildPlugins: ZeppelinPluginDocsData[]; + globalPlugins: ZeppelinPluginDocsData[]; +} diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 9b8f9a1b0..9ce377ad0 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -5,7 +5,8 @@ "module": "NodeNext", "rootDir": "./src", "outDir": "./dist", - "declaration": true + "declaration": true, + "resolveJsonModule": true }, "include": ["src/**/*.ts"] }